comparison view/View.cpp @ 1216:dc2af6616c83

Merge from branch 3.0-integration
author Chris Cannam
date Fri, 13 Jan 2017 10:29:50 +0000
parents c603aba61702
children a34a2a25907c
comparison
equal deleted inserted replaced
1048:e8102ff5573b 1216:dc2af6616c83
18 #include "data/model/Model.h" 18 #include "data/model/Model.h"
19 #include "base/ZoomConstraint.h" 19 #include "base/ZoomConstraint.h"
20 #include "base/Profiler.h" 20 #include "base/Profiler.h"
21 #include "base/Pitch.h" 21 #include "base/Pitch.h"
22 #include "base/Preferences.h" 22 #include "base/Preferences.h"
23 #include "ViewProxy.h"
23 24
24 #include "layer/TimeRulerLayer.h" 25 #include "layer/TimeRulerLayer.h"
25 #include "layer/SingleColourLayer.h" 26 #include "layer/SingleColourLayer.h"
27 #include "layer/PaintAssistant.h"
28
26 #include "data/model/PowerOfSqrtTwoZoomConstraint.h" 29 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
27 #include "data/model/RangeSummarisableTimeValueModel.h" 30 #include "data/model/RangeSummarisableTimeValueModel.h"
28 31
29 #include "widgets/IconLoader.h" 32 #include "widgets/IconLoader.h"
30 33
35 #include <QProgressDialog> 38 #include <QProgressDialog>
36 #include <QTextStream> 39 #include <QTextStream>
37 #include <QFont> 40 #include <QFont>
38 #include <QMessageBox> 41 #include <QMessageBox>
39 #include <QPushButton> 42 #include <QPushButton>
43 #include <QSettings>
44 #include <QSvgGenerator>
40 45
41 #include <iostream> 46 #include <iostream>
42 #include <cassert> 47 #include <cassert>
43 #include <cmath> 48 #include <cmath>
44 49
45 #include <unistd.h>
46
47 //#define DEBUG_VIEW 1 50 //#define DEBUG_VIEW 1
48 //#define DEBUG_VIEW_WIDGET_PAINT 1 51 //#define DEBUG_VIEW_WIDGET_PAINT 1
49 52
50
51 View::View(QWidget *w, bool showProgress) : 53 View::View(QWidget *w, bool showProgress) :
52 QFrame(w), 54 QFrame(w),
55 m_id(getNextId()),
53 m_centreFrame(0), 56 m_centreFrame(0),
54 m_zoomLevel(1024), 57 m_zoomLevel(1024),
55 m_followPan(true), 58 m_followPan(true),
56 m_followZoom(true), 59 m_followZoom(true),
57 m_followPlay(PlaybackScrollPageWithCentre), 60 m_followPlay(PlaybackScrollPageWithCentre),
58 m_followPlayIsDetached(false), 61 m_followPlayIsDetached(false),
59 m_playPointerFrame(0), 62 m_playPointerFrame(0),
60 m_showProgress(showProgress), 63 m_showProgress(showProgress),
61 m_cache(0), 64 m_cache(0),
65 m_buffer(0),
62 m_cacheCentreFrame(0), 66 m_cacheCentreFrame(0),
63 m_cacheZoomLevel(1024), 67 m_cacheZoomLevel(1024),
64 m_selectionCached(false), 68 m_selectionCached(false),
65 m_deleting(false), 69 m_deleting(false),
66 m_haveSelectedLayer(false), 70 m_haveSelectedLayer(false),
74 { 78 {
75 // cerr << "View::~View(" << this << ")" << endl; 79 // cerr << "View::~View(" << this << ")" << endl;
76 80
77 m_deleting = true; 81 m_deleting = true;
78 delete m_propertyContainer; 82 delete m_propertyContainer;
83 delete m_cache;
84 delete m_buffer;
79 } 85 }
80 86
81 PropertyContainer::PropertyList 87 PropertyContainer::PropertyList
82 View::getProperties() const 88 View::getProperties() const
83 { 89 {
360 } 366 }
361 367
362 sv_frame_t 368 sv_frame_t
363 View::getFrameForX(int x) const 369 View::getFrameForX(int x) const
364 { 370 {
365 int z = m_zoomLevel; 371 sv_frame_t z = m_zoomLevel; // nb not just int, or multiplication may overflow
366 sv_frame_t frame = m_centreFrame - (width()/2) * z; 372 sv_frame_t frame = m_centreFrame - (width()/2) * z;
367 373
374 frame = (frame / z) * z; // this is start frame
375 frame = frame + x * z;
376
368 #ifdef DEBUG_VIEW_WIDGET_PAINT 377 #ifdef DEBUG_VIEW_WIDGET_PAINT
369 SVDEBUG << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << endl; 378 cerr << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << endl;
370 #endif 379 #endif
371 380
372 frame = (frame / z) * z; // this is start frame 381 return frame;
373 return frame + x * z;
374 } 382 }
375 383
376 double 384 double
377 View::getYForFrequency(double frequency, 385 View::getYForFrequency(double frequency,
378 double minf, 386 double minf,
406 return h - (h * (frequency - minf)) / (maxf - minf); 414 return h - (h * (frequency - minf)) / (maxf - minf);
407 } 415 }
408 } 416 }
409 417
410 double 418 double
411 View::getFrequencyForY(int y, 419 View::getFrequencyForY(double y,
412 double minf, 420 double minf,
413 double maxf, 421 double maxf,
414 bool logarithmic) const 422 bool logarithmic) const
415 { 423 {
416 int h = height(); 424 double h = height();
417 425
418 if (logarithmic) { 426 if (logarithmic) {
419 427
420 static double lastminf = 0.0, lastmaxf = 0.0; 428 static double lastminf = 0.0, lastmaxf = 0.0;
421 static double logminf = 0.0, logmaxf = 0.0; 429 static double logminf = 0.0, logmaxf = 0.0;
446 // cout << "zoom level: " << m_zoomLevel << endl; 454 // cout << "zoom level: " << m_zoomLevel << endl;
447 #endif 455 #endif
448 return m_zoomLevel; 456 return m_zoomLevel;
449 } 457 }
450 458
459 int
460 View::effectiveDevicePixelRatio() const
461 {
462 #ifdef Q_OS_MAC
463 int dpratio = devicePixelRatio();
464 if (dpratio > 1) {
465 QSettings settings;
466 settings.beginGroup("Preferences");
467 if (!settings.value("scaledHiDpi", true).toBool()) {
468 dpratio = 1;
469 }
470 settings.endGroup();
471 }
472 return dpratio;
473 #else
474 return 1;
475 #endif
476 }
477
451 void 478 void
452 View::setZoomLevel(int z) 479 View::setZoomLevel(int z)
453 { 480 {
481 int dpratio = effectiveDevicePixelRatio();
482 if (z < dpratio) return;
454 if (z < 1) z = 1; 483 if (z < 1) z = 1;
455 if (m_zoomLevel != int(z)) { 484 if (m_zoomLevel != int(z)) {
456 m_zoomLevel = z; 485 m_zoomLevel = z;
457 emit zoomLevelChanged(z, m_followZoom); 486 emit zoomLevelChanged(z, m_followZoom);
458 update(); 487 update();
782 m_followZoom = f; 811 m_followZoom = f;
783 emit propertyContainerPropertyChanged(m_propertyContainer); 812 emit propertyContainerPropertyChanged(m_propertyContainer);
784 } 813 }
785 814
786 void 815 void
787 View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style) const
788 {
789 if (style == OutlinedText || style == OutlinedItalicText) {
790
791 paint.save();
792
793 if (style == OutlinedItalicText) {
794 QFont f(paint.font());
795 f.setItalic(true);
796 paint.setFont(f);
797 }
798
799 QColor penColour, surroundColour, boxColour;
800
801 penColour = getForeground();
802 surroundColour = getBackground();
803 boxColour = surroundColour;
804 boxColour.setAlpha(127);
805
806 paint.setPen(Qt::NoPen);
807 paint.setBrush(boxColour);
808
809 QRect r = paint.fontMetrics().boundingRect(text);
810 r.translate(QPoint(x, y));
811 // cerr << "drawVisibleText: r = " << r.x() << "," <<r.y() << " " << r.width() << "x" << r.height() << endl;
812 paint.drawRect(r);
813 paint.setBrush(Qt::NoBrush);
814
815 paint.setPen(surroundColour);
816
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);
821 }
822 }
823
824 paint.setPen(penColour);
825
826 paint.drawText(x, y, text);
827
828 paint.restore();
829
830 } else {
831
832 cerr << "ERROR: View::drawVisibleText: Boxed style not yet implemented!" << endl;
833 }
834 }
835
836 void
837 View::setPlaybackFollow(PlaybackFollowMode m) 816 View::setPlaybackFollow(PlaybackFollowMode m)
838 { 817 {
839 m_followPlay = m; 818 m_followPlay = m;
840 emit propertyContainerPropertyChanged(m_propertyContainer); 819 emit propertyContainerPropertyChanged(m_propertyContainer);
841 } 820 }
1025 #endif 1004 #endif
1026 1005
1027 f = getAlignedPlaybackFrame(); 1006 f = getAlignedPlaybackFrame();
1028 1007
1029 #ifdef DEBUG_VIEW 1008 #ifdef DEBUG_VIEW
1030 cerr << " -> aligned frame = " << af << endl; 1009 cerr << " -> aligned frame = " << f << endl;
1031 #endif 1010 #endif
1032 1011
1033 movePlayPointer(f); 1012 movePlayPointer(f);
1034 } 1013 }
1035 1014
1651 } 1630 }
1652 1631
1653 void 1632 void
1654 View::setPaintFont(QPainter &paint) 1633 View::setPaintFont(QPainter &paint)
1655 { 1634 {
1635 int scaleFactor = 1;
1636 int dpratio = effectiveDevicePixelRatio();
1637 if (dpratio > 1) {
1638 QPaintDevice *dev = paint.device();
1639 if (dynamic_cast<QPixmap *>(dev) || dynamic_cast<QImage *>(dev)) {
1640 scaleFactor = dpratio;
1641 }
1642 }
1643
1656 QFont font(paint.font()); 1644 QFont font(paint.font());
1657 font.setPointSize(Preferences::getInstance()->getViewFontSize()); 1645 font.setPointSize(Preferences::getInstance()->getViewFontSize()
1646 * scaleFactor);
1658 paint.setFont(font); 1647 paint.setFont(font);
1648 }
1649
1650 QRect
1651 View::getPaintRect() const
1652 {
1653 return rect();
1659 } 1654 }
1660 1655
1661 void 1656 void
1662 View::paintEvent(QPaintEvent *e) 1657 View::paintEvent(QPaintEvent *e)
1663 { 1658 {
1692 #endif 1687 #endif
1693 } 1688 }
1694 1689
1695 QRect nonCacheRect(cacheRect); 1690 QRect nonCacheRect(cacheRect);
1696 1691
1692 int dpratio = effectiveDevicePixelRatio();
1693
1697 // If not all layers are scrollable, but some of the back layers 1694 // If not all layers are scrollable, but some of the back layers
1698 // are, we should store only those in the cache. 1695 // are, we should store only those in the cache.
1699 1696
1700 bool layersChanged = false; 1697 bool layersChanged = false;
1701 LayerList scrollables = getScrollableBackLayers(true, layersChanged); 1698 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
1703 bool selectionCacheable = nonScrollables.empty(); 1700 bool selectionCacheable = nonScrollables.empty();
1704 bool haveSelections = m_manager && !m_manager->getSelections().empty(); 1701 bool haveSelections = m_manager && !m_manager->getSelections().empty();
1705 1702
1706 // If all the non-scrollable layers are non-opaque, then we draw 1703 // If all the non-scrollable layers are non-opaque, then we draw
1707 // the selection rectangle behind them and cache it. If any are 1704 // the selection rectangle behind them and cache it. If any are
1708 // opaque, however, we can't cache. 1705 // opaque, however, or if our device-pixel ratio is not 1 (so we
1706 // need to paint direct to the widget), then we can't cache.
1709 // 1707 //
1710 if (!selectionCacheable) { 1708 if (dpratio == 1) {
1711 selectionCacheable = true; 1709
1712 for (LayerList::const_iterator i = nonScrollables.begin(); 1710 if (!selectionCacheable) {
1713 i != nonScrollables.end(); ++i) { 1711 selectionCacheable = true;
1714 if ((*i)->isLayerOpaque()) { 1712 for (LayerList::const_iterator i = nonScrollables.begin();
1715 selectionCacheable = false; 1713 i != nonScrollables.end(); ++i) {
1716 break; 1714 if ((*i)->isLayerOpaque()) {
1717 } 1715 selectionCacheable = false;
1718 } 1716 break;
1719 } 1717 }
1720 1718 }
1721 if (selectionCacheable) { 1719 }
1722 QPoint localPos; 1720
1723 bool closeToLeft, closeToRight; 1721 if (selectionCacheable) {
1724 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) { 1722 QPoint localPos;
1725 selectionCacheable = false; 1723 bool closeToLeft, closeToRight;
1726 } 1724 if (shouldIlluminateLocalSelection
1725 (localPos, closeToLeft, closeToRight)) {
1726 selectionCacheable = false;
1727 }
1728 }
1729
1730 } else {
1731
1732 selectionCacheable = false;
1727 } 1733 }
1728 1734
1729 #ifdef DEBUG_VIEW_WIDGET_PAINT 1735 #ifdef DEBUG_VIEW_WIDGET_PAINT
1730 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size() 1736 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
1731 << " scrollable back layers and " << nonScrollables.size() 1737 << " scrollable back layers and " << nonScrollables.size()
1739 delete m_cache; 1745 delete m_cache;
1740 m_cache = 0; 1746 m_cache = 0;
1741 m_selectionCached = false; 1747 m_selectionCached = false;
1742 } 1748 }
1743 1749
1750 QSize scaledCacheSize(scaledSize(size(), dpratio));
1751 QRect scaledCacheRect(scaledRect(cacheRect, dpratio));
1752
1753 if (!m_buffer || scaledCacheSize != m_buffer->size()) {
1754 delete m_buffer;
1755 m_buffer = new QPixmap(scaledCacheSize);
1756 }
1757
1744 if (!scrollables.empty()) { 1758 if (!scrollables.empty()) {
1745 1759
1746 #ifdef DEBUG_VIEW_WIDGET_PAINT 1760 #ifdef DEBUG_VIEW_WIDGET_PAINT
1747 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom " 1761 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom "
1748 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl; 1762 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl;
1749 #endif 1763 #endif
1750 1764
1751 if (!m_cache || 1765 if (!m_cache ||
1752 m_cacheZoomLevel != m_zoomLevel || 1766 m_cacheZoomLevel != m_zoomLevel ||
1753 width() != m_cache->width() || 1767 scaledCacheSize != m_cache->size()) {
1754 height() != m_cache->height()) {
1755 1768
1756 // cache is not valid 1769 // cache is not valid
1757 1770
1758 if (cacheRect.width() < width()/10) { 1771 if (cacheRect.width() < width()/10) {
1759 delete m_cache; 1772 delete m_cache;
1761 #ifdef DEBUG_VIEW_WIDGET_PAINT 1774 #ifdef DEBUG_VIEW_WIDGET_PAINT
1762 cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl; 1775 cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl;
1763 #endif 1776 #endif
1764 } else { 1777 } else {
1765 delete m_cache; 1778 delete m_cache;
1766 m_cache = new QPixmap(width(), height()); 1779 m_cache = new QPixmap(scaledCacheSize);
1767 #ifdef DEBUG_VIEW_WIDGET_PAINT 1780 #ifdef DEBUG_VIEW_WIDGET_PAINT
1768 cerr << "View(" << this << ")::paintEvent: recreated cache" << endl; 1781 cerr << "View(" << this << ")::paintEvent: recreated cache" << endl;
1769 #endif 1782 #endif
1770 cacheRect = rect(); 1783 cacheRect = rect();
1771 repaintCache = true; 1784 repaintCache = true;
1776 int dx = 1789 int dx =
1777 getXForFrame(m_cacheCentreFrame) - 1790 getXForFrame(m_cacheCentreFrame) -
1778 getXForFrame(m_centreFrame); 1791 getXForFrame(m_centreFrame);
1779 1792
1780 if (dx > -width() && dx < width()) { 1793 if (dx > -width() && dx < width()) {
1781 #ifdef PIXMAP_COPY_TO_SELF
1782 // This is not normally defined. Copying a pixmap to
1783 // itself doesn't work properly on Windows, Mac, or
1784 // X11 with the raster backend (it only works when
1785 // moving in one direction and then presumably only by
1786 // accident). It does actually seem to be fine on X11
1787 // with the native backend, but we prefer not to use
1788 // that anyway
1789 paint.begin(m_cache);
1790 paint.drawPixmap(dx, 0, *m_cache);
1791 paint.end();
1792 #else
1793 static QPixmap *tmpPixmap = 0; 1794 static QPixmap *tmpPixmap = 0;
1794 if (!tmpPixmap || 1795 if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) {
1795 tmpPixmap->width() != width() ||
1796 tmpPixmap->height() != height()) {
1797 delete tmpPixmap; 1796 delete tmpPixmap;
1798 tmpPixmap = new QPixmap(width(), height()); 1797 tmpPixmap = new QPixmap(scaledCacheSize);
1799 } 1798 }
1800 paint.begin(tmpPixmap); 1799 paint.begin(tmpPixmap);
1801 paint.drawPixmap(0, 0, *m_cache); 1800 paint.drawPixmap(0, 0, *m_cache);
1802 paint.end(); 1801 paint.end();
1803 paint.begin(m_cache); 1802 paint.begin(m_cache);
1804 paint.drawPixmap(dx, 0, *tmpPixmap); 1803 paint.drawPixmap(dx, 0, *tmpPixmap);
1805 paint.end(); 1804 paint.end();
1806 #endif
1807 if (dx < 0) { 1805 if (dx < 0) {
1808 cacheRect = QRect(width() + dx, 0, -dx, height()); 1806 cacheRect = QRect(width() + dx, 0, -dx, height());
1809 } else { 1807 } else {
1810 cacheRect = QRect(0, 0, dx, height()); 1808 cacheRect = QRect(0, 0, dx, height());
1811 } 1809 }
1822 1820
1823 } else { 1821 } else {
1824 #ifdef DEBUG_VIEW_WIDGET_PAINT 1822 #ifdef DEBUG_VIEW_WIDGET_PAINT
1825 cerr << "View(" << this << ")::paintEvent: cache is good" << endl; 1823 cerr << "View(" << this << ")::paintEvent: cache is good" << endl;
1826 #endif 1824 #endif
1827 paint.begin(this); 1825 paint.begin(m_buffer);
1828 paint.drawPixmap(cacheRect, *m_cache, cacheRect); 1826 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
1829 paint.end(); 1827 paint.end();
1830 QFrame::paintEvent(e); 1828 QFrame::paintEvent(e);
1831 paintedCacheRect = true; 1829 paintedCacheRect = true;
1832 } 1830 }
1833 1831
1839 // cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << endl; 1837 // cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << endl;
1840 #endif 1838 #endif
1841 1839
1842 // Scrollable (cacheable) items first 1840 // Scrollable (cacheable) items first
1843 1841
1842 ViewProxy proxy(this, dpratio);
1843
1844 if (!paintedCacheRect) { 1844 if (!paintedCacheRect) {
1845 1845
1846 if (repaintCache) paint.begin(m_cache); 1846 QRect rectToPaint;
1847 else paint.begin(this); 1847
1848 if (repaintCache) {
1849 paint.begin(m_cache);
1850 rectToPaint = scaledCacheRect;
1851 } else {
1852 paint.begin(m_buffer);
1853 rectToPaint = scaledCacheRect;
1854 }
1855
1848 setPaintFont(paint); 1856 setPaintFont(paint);
1849 paint.setClipRect(cacheRect); 1857 paint.setClipRect(rectToPaint);
1850 1858
1851 paint.setPen(getBackground()); 1859 paint.setPen(getBackground());
1852 paint.setBrush(getBackground()); 1860 paint.setBrush(getBackground());
1853 paint.drawRect(cacheRect); 1861 paint.drawRect(rectToPaint);
1854 1862
1855 paint.setPen(getForeground()); 1863 paint.setPen(getForeground());
1856 paint.setBrush(Qt::NoBrush); 1864 paint.setBrush(Qt::NoBrush);
1857 1865
1858 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) { 1866 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
1859 paint.setRenderHint(QPainter::Antialiasing, false); 1867 paint.setRenderHint(QPainter::Antialiasing, false);
1860 paint.save(); 1868 paint.save();
1861 (*i)->paint(this, paint, cacheRect); 1869 #ifdef DEBUG_VIEW_WIDGET_PAINT
1870 cerr << "Painting scrollable layer " << *i << " using proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << rectToPaint.x() << "," << rectToPaint.y() << " " << rectToPaint.width() << "x" << rectToPaint.height() << endl;
1871 #endif
1872 (*i)->paint(&proxy, paint, rectToPaint);
1862 paint.restore(); 1873 paint.restore();
1863 } 1874 }
1864 1875
1865 if (haveSelections && selectionCacheable) { 1876 if (haveSelections && selectionCacheable) {
1866 drawSelections(paint); 1877 drawSelections(paint);
1869 1880
1870 paint.end(); 1881 paint.end();
1871 1882
1872 if (repaintCache) { 1883 if (repaintCache) {
1873 cacheRect |= (e ? e->rect() : rect()); 1884 cacheRect |= (e ? e->rect() : rect());
1874 paint.begin(this); 1885 scaledCacheRect = scaledRect(cacheRect, dpratio);
1875 paint.drawPixmap(cacheRect, *m_cache, cacheRect); 1886 paint.begin(m_buffer);
1887 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
1876 paint.end(); 1888 paint.end();
1877 } 1889 }
1878 } 1890 }
1879 1891
1880 // Now non-cacheable items. We always need to redraw the 1892 // Now non-cacheable items. We always need to redraw the
1881 // non-cacheable items across at least the area we drew of the 1893 // non-cacheable items across at least the area we drew of the
1882 // cacheable items. 1894 // cacheable items.
1883 1895
1884 nonCacheRect |= cacheRect; 1896 nonCacheRect |= cacheRect;
1885 1897
1886 paint.begin(this); 1898 QRect scaledNonCacheRect = scaledRect(nonCacheRect, dpratio);
1887 paint.setClipRect(nonCacheRect); 1899
1900 paint.begin(m_buffer);
1901 paint.setClipRect(scaledNonCacheRect);
1888 setPaintFont(paint); 1902 setPaintFont(paint);
1889 if (scrollables.empty()) { 1903 if (scrollables.empty()) {
1890 paint.setPen(getBackground()); 1904 paint.setPen(getBackground());
1891 paint.setBrush(getBackground()); 1905 paint.setBrush(getBackground());
1892 paint.drawRect(nonCacheRect); 1906 paint.drawRect(scaledNonCacheRect);
1893 } 1907 }
1894 1908
1895 paint.setPen(getForeground()); 1909 paint.setPen(getForeground());
1896 paint.setBrush(Qt::NoBrush); 1910 paint.setBrush(Qt::NoBrush);
1897 1911
1898 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) { 1912 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
1899 // Profiler profiler2("View::paintEvent non-cacheable"); 1913 // Profiler profiler2("View::paintEvent non-cacheable");
1900 (*i)->paint(this, paint, nonCacheRect); 1914 #ifdef DEBUG_VIEW_WIDGET_PAINT
1915 cerr << "Painting non-scrollable layer " << *i << " without proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << nonCacheRect.x() << "," << nonCacheRect.y() << " " << nonCacheRect.width() << "x" << nonCacheRect.height() << endl;
1916 #endif
1917 (*i)->paint(&proxy, paint, scaledNonCacheRect);
1901 } 1918 }
1902 1919
1920 paint.end();
1921
1922 paint.begin(this);
1923 QRect finalPaintRect = e ? e->rect() : rect();
1924 paint.drawPixmap(finalPaintRect, *m_buffer, scaledRect(finalPaintRect, dpratio));
1903 paint.end(); 1925 paint.end();
1904 1926
1905 paint.begin(this); 1927 paint.begin(this);
1906 setPaintFont(paint); 1928 setPaintFont(paint);
1907 if (e) paint.setClipRect(e->rect()); 1929 if (e) paint.setClipRect(e->rect());
1923 // Don't show the play pointer when it is redundant with 1945 // Don't show the play pointer when it is redundant with
1924 // the centre line 1946 // the centre line
1925 showPlayPointer = false; 1947 showPlayPointer = false;
1926 } 1948 }
1927 } 1949 }
1928 1950
1929 if (showPlayPointer) { 1951 if (showPlayPointer) {
1930 1952
1931 paint.begin(this); 1953 paint.begin(this);
1932 1954
1933 int playx = getXForFrame(m_playPointerFrame); 1955 int playx = getXForFrame(m_playPointerFrame);
2079 2101
2080 if (dw < (p1 - p0)) { 2102 if (dw < (p1 - p0)) {
2081 dx = p1 - 2 - dw; 2103 dx = p1 - 2 - dw;
2082 } 2104 }
2083 2105
2084 paint.drawText(sx, sy, startText); 2106 PaintAssistant::drawVisibleText(this, paint, sx, sy, startText,
2085 paint.drawText(ex, ey, endText); 2107 PaintAssistant::OutlinedText);
2086 paint.drawText(dx, dy, durationText); 2108 PaintAssistant::drawVisibleText(this, paint, ex, ey, endText,
2109 PaintAssistant::OutlinedText);
2110 PaintAssistant::drawVisibleText(this, paint, dx, dy, durationText,
2111 PaintAssistant::OutlinedText);
2087 if (durationBothEnds) { 2112 if (durationBothEnds) {
2088 paint.drawText(sx, dy, durationText); 2113 PaintAssistant::drawVisibleText(this, paint, sx, dy, durationText,
2114 PaintAssistant::OutlinedText);
2089 } 2115 }
2090 } 2116 }
2091 } 2117 }
2092 2118
2093 paint.restore(); 2119 paint.restore();
2298 2324
2299 dxy = r.y() + r.height() + fontAscent + 2; 2325 dxy = r.y() + r.height() + fontAscent + 2;
2300 } 2326 }
2301 2327
2302 if (axs != "") { 2328 if (axs != "") {
2303 drawVisibleText(paint, axx, axy, axs, OutlinedText); 2329 PaintAssistant::drawVisibleText(this, paint, axx, axy, axs, PaintAssistant::OutlinedText);
2304 axy += fontHeight; 2330 axy += fontHeight;
2305 } 2331 }
2306 2332
2307 if (ays != "") { 2333 if (ays != "") {
2308 drawVisibleText(paint, axx, axy, ays, OutlinedText); 2334 PaintAssistant::drawVisibleText(this, paint, axx, axy, ays, PaintAssistant::OutlinedText);
2309 axy += fontHeight; 2335 axy += fontHeight;
2310 } 2336 }
2311 2337
2312 if (bxs != "") { 2338 if (bxs != "") {
2313 drawVisibleText(paint, bxx, bxy, bxs, OutlinedText); 2339 PaintAssistant::drawVisibleText(this, paint, bxx, bxy, bxs, PaintAssistant::OutlinedText);
2314 bxy += fontHeight; 2340 bxy += fontHeight;
2315 } 2341 }
2316 2342
2317 if (bys != "") { 2343 if (bys != "") {
2318 drawVisibleText(paint, bxx, bxy, bys, OutlinedText); 2344 PaintAssistant::drawVisibleText(this, paint, bxx, bxy, bys, PaintAssistant::OutlinedText);
2319 bxy += fontHeight; 2345 bxy += fontHeight;
2320 } 2346 }
2321 2347
2322 if (dxs != "") { 2348 if (dxs != "") {
2323 drawVisibleText(paint, dxx, dxy, dxs, OutlinedText); 2349 PaintAssistant::drawVisibleText(this, paint, dxx, dxy, dxs, PaintAssistant::OutlinedText);
2324 dxy += fontHeight; 2350 dxy += fontHeight;
2325 } 2351 }
2326 2352
2327 if (dys != "") { 2353 if (dys != "") {
2328 drawVisibleText(paint, dxx, dxy, dys, OutlinedText); 2354 PaintAssistant::drawVisibleText(this, paint, dxx, dxy, dys, PaintAssistant::OutlinedText);
2329 dxy += fontHeight; 2355 dxy += fontHeight;
2330 } 2356 }
2331 2357
2332 paint.restore(); 2358 paint.restore();
2333 } 2359 }
2410 paint.setPen(getForeground()); 2436 paint.setPen(getForeground());
2411 paint.setBrush(Qt::NoBrush); 2437 paint.setBrush(Qt::NoBrush);
2412 2438
2413 for (LayerList::iterator i = m_layerStack.begin(); 2439 for (LayerList::iterator i = m_layerStack.begin();
2414 i != m_layerStack.end(); ++i) { 2440 i != m_layerStack.end(); ++i) {
2415 if(!((*i)->isLayerDormant(this))){ 2441 if (!((*i)->isLayerDormant(this))){
2416 2442
2417 paint.setRenderHint(QPainter::Antialiasing, false); 2443 paint.setRenderHint(QPainter::Antialiasing, false);
2418 2444
2419 paint.save(); 2445 paint.save();
2420 paint.translate(xorigin + x, 0); 2446 paint.translate(xorigin + x, 0);
2421 2447
2422 cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl; 2448 cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl;
2423 2449
2424 (*i)->setSynchronousPainting(true); 2450 (*i)->setSynchronousPainting(true);
2425 2451
2426 (*i)->paint(this, paint, chunk); 2452 (*i)->paint(this, paint, chunk);
2427 2453
2428 (*i)->setSynchronousPainting(false); 2454 (*i)->setSynchronousPainting(false);
2429 2455
2430 paint.restore(); 2456 paint.restore();
2431 } 2457 }
2432 } 2458 }
2433 } 2459 }
2434 2460
2435 m_centreFrame = origCentreFrame; 2461 m_centreFrame = origCentreFrame;
2436 update(); 2462 update();
2437 return true; 2463 return true;
2438 } 2464 }
2439 2465
2440 QImage * 2466 QImage *
2441 View::toNewImage() 2467 View::renderToNewImage()
2442 { 2468 {
2443 sv_frame_t f0 = getModelsStartFrame(); 2469 sv_frame_t f0 = getModelsStartFrame();
2444 sv_frame_t f1 = getModelsEndFrame(); 2470 sv_frame_t f1 = getModelsEndFrame();
2445 2471
2446 return toNewImage(f0, f1); 2472 return renderPartToNewImage(f0, f1);
2447 } 2473 }
2448 2474
2449 QImage * 2475 QImage *
2450 View::toNewImage(sv_frame_t f0, sv_frame_t f1) 2476 View::renderPartToNewImage(sv_frame_t f0, sv_frame_t f1)
2451 { 2477 {
2452 int x0 = int(f0 / getZoomLevel()); 2478 int x0 = int(f0 / getZoomLevel());
2453 int x1 = int(f1 / getZoomLevel()); 2479 int x1 = int(f1 / getZoomLevel());
2454 2480
2455 QImage *image = new QImage(x1 - x0, height(), QImage::Format_RGB32); 2481 QImage *image = new QImage(x1 - x0, height(), QImage::Format_RGB32);
2464 return image; 2490 return image;
2465 } 2491 }
2466 } 2492 }
2467 2493
2468 QSize 2494 QSize
2469 View::getImageSize() 2495 View::getRenderedImageSize()
2470 { 2496 {
2471 sv_frame_t f0 = getModelsStartFrame(); 2497 sv_frame_t f0 = getModelsStartFrame();
2472 sv_frame_t f1 = getModelsEndFrame(); 2498 sv_frame_t f1 = getModelsEndFrame();
2473 2499
2474 return getImageSize(f0, f1); 2500 return getRenderedPartImageSize(f0, f1);
2475 } 2501 }
2476 2502
2477 QSize 2503 QSize
2478 View::getImageSize(sv_frame_t f0, sv_frame_t f1) 2504 View::getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1)
2479 { 2505 {
2480 int x0 = int(f0 / getZoomLevel()); 2506 int x0 = int(f0 / getZoomLevel());
2481 int x1 = int(f1 / getZoomLevel()); 2507 int x1 = int(f1 / getZoomLevel());
2482 2508
2483 return QSize(x1 - x0, height()); 2509 return QSize(x1 - x0, height());
2510 }
2511
2512 bool
2513 View::renderToSvgFile(QString filename)
2514 {
2515 sv_frame_t f0 = getModelsStartFrame();
2516 sv_frame_t f1 = getModelsEndFrame();
2517
2518 return renderPartToSvgFile(filename, f0, f1);
2519 }
2520
2521 bool
2522 View::renderPartToSvgFile(QString filename, sv_frame_t f0, sv_frame_t f1)
2523 {
2524 int x0 = int(f0 / getZoomLevel());
2525 int x1 = int(f1 / getZoomLevel());
2526
2527 QSvgGenerator generator;
2528 generator.setFileName(filename);
2529 generator.setSize(QSize(x1 - x0, height()));
2530 generator.setViewBox(QRect(0, 0, x1 - x0, height()));
2531 generator.setTitle(tr("Exported image from %1")
2532 .arg(QApplication::applicationName()));
2533
2534 QPainter paint;
2535 paint.begin(&generator);
2536 bool result = render(paint, 0, f0, f1);
2537 paint.end();
2538 return result;
2484 } 2539 }
2485 2540
2486 void 2541 void
2487 View::toXml(QTextStream &stream, 2542 View::toXml(QTextStream &stream,
2488 QString indent, QString extraAttributes) const 2543 QString indent, QString extraAttributes) const