comparison view/View.cpp @ 978:64c2b3a4435a 3.0-integration

Merge from branch osx-retina
author Chris Cannam
date Fri, 26 Jun 2015 14:10:40 +0100
parents 092de22db207
children 5fdf5cd032ac
comparison
equal deleted inserted replaced
977:f40ccbf228c2 978:64c2b3a4435a
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"
26 #include "data/model/PowerOfSqrtTwoZoomConstraint.h" 27 #include "data/model/PowerOfSqrtTwoZoomConstraint.h"
27 #include "data/model/RangeSummarisableTimeValueModel.h" 28 #include "data/model/RangeSummarisableTimeValueModel.h"
35 #include <QProgressDialog> 36 #include <QProgressDialog>
36 #include <QTextStream> 37 #include <QTextStream>
37 #include <QFont> 38 #include <QFont>
38 #include <QMessageBox> 39 #include <QMessageBox>
39 #include <QPushButton> 40 #include <QPushButton>
41 #include <QSettings>
40 42
41 #include <iostream> 43 #include <iostream>
42 #include <cassert> 44 #include <cassert>
43 #include <cmath> 45 #include <cmath>
44 46
45 #include <unistd.h> 47 #include <unistd.h>
46 48
47 //#define DEBUG_VIEW 1 49 #define DEBUG_VIEW 1
48 //#define DEBUG_VIEW_WIDGET_PAINT 1 50 #define DEBUG_VIEW_WIDGET_PAINT 1
49 51
50 52
51 View::View(QWidget *w, bool showProgress) : 53 View::View(QWidget *w, bool showProgress) :
52 QFrame(w), 54 QFrame(w),
53 m_centreFrame(0), 55 m_centreFrame(0),
57 m_followPlay(PlaybackScrollPageWithCentre), 59 m_followPlay(PlaybackScrollPageWithCentre),
58 m_followPlayIsDetached(false), 60 m_followPlayIsDetached(false),
59 m_playPointerFrame(0), 61 m_playPointerFrame(0),
60 m_showProgress(showProgress), 62 m_showProgress(showProgress),
61 m_cache(0), 63 m_cache(0),
64 m_buffer(0),
62 m_cacheCentreFrame(0), 65 m_cacheCentreFrame(0),
63 m_cacheZoomLevel(1024), 66 m_cacheZoomLevel(1024),
64 m_selectionCached(false), 67 m_selectionCached(false),
65 m_deleting(false), 68 m_deleting(false),
66 m_haveSelectedLayer(false), 69 m_haveSelectedLayer(false),
446 // cout << "zoom level: " << m_zoomLevel << endl; 449 // cout << "zoom level: " << m_zoomLevel << endl;
447 #endif 450 #endif
448 return m_zoomLevel; 451 return m_zoomLevel;
449 } 452 }
450 453
454 int
455 View::effectiveDevicePixelRatio() const
456 {
457 #ifdef Q_OS_MAC
458 int dpratio = devicePixelRatio();
459 if (dpratio > 1) {
460 QSettings settings;
461 settings.beginGroup("Preferences");
462 if (!settings.value("scaledHiDpi", true).toBool()) {
463 dpratio = 1;
464 }
465 settings.endGroup();
466 }
467 return dpratio;
468 #else
469 return 1;
470 #endif
471 }
472
451 void 473 void
452 View::setZoomLevel(int z) 474 View::setZoomLevel(int z)
453 { 475 {
476 int dpratio = effectiveDevicePixelRatio();
477 if (z < dpratio) return;
454 if (z < 1) z = 1; 478 if (z < 1) z = 1;
455 if (m_zoomLevel != int(z)) { 479 if (m_zoomLevel != int(z)) {
456 m_zoomLevel = z; 480 m_zoomLevel = z;
457 emit zoomLevelChanged(z, m_followZoom); 481 emit zoomLevelChanged(z, m_followZoom);
458 update(); 482 update();
1025 #endif 1049 #endif
1026 1050
1027 f = getAlignedPlaybackFrame(); 1051 f = getAlignedPlaybackFrame();
1028 1052
1029 #ifdef DEBUG_VIEW 1053 #ifdef DEBUG_VIEW
1030 cerr << " -> aligned frame = " << af << endl; 1054 cerr << " -> aligned frame = " << f << endl;
1031 #endif 1055 #endif
1032 1056
1033 movePlayPointer(f); 1057 movePlayPointer(f);
1034 } 1058 }
1035 1059
1651 } 1675 }
1652 1676
1653 void 1677 void
1654 View::setPaintFont(QPainter &paint) 1678 View::setPaintFont(QPainter &paint)
1655 { 1679 {
1680 int scaleFactor = 1;
1681 int dpratio = effectiveDevicePixelRatio();
1682 if (dpratio > 1) {
1683 QPaintDevice *dev = paint.device();
1684 if (dynamic_cast<QPixmap *>(dev) || dynamic_cast<QImage *>(dev)) {
1685 scaleFactor = dpratio;
1686 }
1687 }
1688
1656 QFont font(paint.font()); 1689 QFont font(paint.font());
1657 font.setPointSize(Preferences::getInstance()->getViewFontSize()); 1690 font.setPointSize(Preferences::getInstance()->getViewFontSize()
1691 * scaleFactor);
1658 paint.setFont(font); 1692 paint.setFont(font);
1693 }
1694
1695 QRect
1696 View::getPaintRect() const
1697 {
1698 return rect();
1659 } 1699 }
1660 1700
1661 void 1701 void
1662 View::paintEvent(QPaintEvent *e) 1702 View::paintEvent(QPaintEvent *e)
1663 { 1703 {
1692 #endif 1732 #endif
1693 } 1733 }
1694 1734
1695 QRect nonCacheRect(cacheRect); 1735 QRect nonCacheRect(cacheRect);
1696 1736
1737 int dpratio = effectiveDevicePixelRatio();
1738
1697 // If not all layers are scrollable, but some of the back layers 1739 // If not all layers are scrollable, but some of the back layers
1698 // are, we should store only those in the cache. 1740 // are, we should store only those in the cache.
1699 1741
1700 bool layersChanged = false; 1742 bool layersChanged = false;
1701 LayerList scrollables = getScrollableBackLayers(true, layersChanged); 1743 LayerList scrollables = getScrollableBackLayers(true, layersChanged);
1703 bool selectionCacheable = nonScrollables.empty(); 1745 bool selectionCacheable = nonScrollables.empty();
1704 bool haveSelections = m_manager && !m_manager->getSelections().empty(); 1746 bool haveSelections = m_manager && !m_manager->getSelections().empty();
1705 1747
1706 // If all the non-scrollable layers are non-opaque, then we draw 1748 // If all the non-scrollable layers are non-opaque, then we draw
1707 // the selection rectangle behind them and cache it. If any are 1749 // the selection rectangle behind them and cache it. If any are
1708 // opaque, however, we can't cache. 1750 // opaque, however, or if our device-pixel ratio is not 1 (so we
1751 // need to paint direct to the widget), then we can't cache.
1709 // 1752 //
1710 if (!selectionCacheable) { 1753 if (dpratio == 1) {
1711 selectionCacheable = true; 1754
1712 for (LayerList::const_iterator i = nonScrollables.begin(); 1755 if (!selectionCacheable) {
1713 i != nonScrollables.end(); ++i) { 1756 selectionCacheable = true;
1714 if ((*i)->isLayerOpaque()) { 1757 for (LayerList::const_iterator i = nonScrollables.begin();
1715 selectionCacheable = false; 1758 i != nonScrollables.end(); ++i) {
1716 break; 1759 if ((*i)->isLayerOpaque()) {
1717 } 1760 selectionCacheable = false;
1718 } 1761 break;
1719 } 1762 }
1720 1763 }
1721 if (selectionCacheable) { 1764 }
1722 QPoint localPos; 1765
1723 bool closeToLeft, closeToRight; 1766 if (selectionCacheable) {
1724 if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) { 1767 QPoint localPos;
1725 selectionCacheable = false; 1768 bool closeToLeft, closeToRight;
1726 } 1769 if (shouldIlluminateLocalSelection
1770 (localPos, closeToLeft, closeToRight)) {
1771 selectionCacheable = false;
1772 }
1773 }
1774
1775 } else {
1776
1777 selectionCacheable = false;
1727 } 1778 }
1728 1779
1729 #ifdef DEBUG_VIEW_WIDGET_PAINT 1780 #ifdef DEBUG_VIEW_WIDGET_PAINT
1730 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size() 1781 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
1731 << " scrollable back layers and " << nonScrollables.size() 1782 << " scrollable back layers and " << nonScrollables.size()
1739 delete m_cache; 1790 delete m_cache;
1740 m_cache = 0; 1791 m_cache = 0;
1741 m_selectionCached = false; 1792 m_selectionCached = false;
1742 } 1793 }
1743 1794
1795 QSize scaledCacheSize(scaledSize(size(), dpratio));
1796 QRect scaledCacheRect(scaledRect(cacheRect, dpratio));
1797
1798 if (!m_buffer || scaledCacheSize != m_buffer->size()) {
1799 delete m_buffer;
1800 m_buffer = new QPixmap(scaledCacheSize);
1801 }
1802
1744 if (!scrollables.empty()) { 1803 if (!scrollables.empty()) {
1745 1804
1746 #ifdef DEBUG_VIEW_WIDGET_PAINT 1805 #ifdef DEBUG_VIEW_WIDGET_PAINT
1747 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom " 1806 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom "
1748 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl; 1807 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl;
1749 #endif 1808 #endif
1750 1809
1751 if (!m_cache || 1810 if (!m_cache ||
1752 m_cacheZoomLevel != m_zoomLevel || 1811 m_cacheZoomLevel != m_zoomLevel ||
1753 width() != m_cache->width() || 1812 scaledCacheSize != m_cache->size()) {
1754 height() != m_cache->height()) {
1755 1813
1756 // cache is not valid 1814 // cache is not valid
1757 1815
1758 if (cacheRect.width() < width()/10) { 1816 if (cacheRect.width() < width()/10) {
1759 delete m_cache; 1817 delete m_cache;
1761 #ifdef DEBUG_VIEW_WIDGET_PAINT 1819 #ifdef DEBUG_VIEW_WIDGET_PAINT
1762 cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl; 1820 cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl;
1763 #endif 1821 #endif
1764 } else { 1822 } else {
1765 delete m_cache; 1823 delete m_cache;
1766 m_cache = new QPixmap(width(), height()); 1824 m_cache = new QPixmap(scaledCacheSize);
1767 #ifdef DEBUG_VIEW_WIDGET_PAINT 1825 #ifdef DEBUG_VIEW_WIDGET_PAINT
1768 cerr << "View(" << this << ")::paintEvent: recreated cache" << endl; 1826 cerr << "View(" << this << ")::paintEvent: recreated cache" << endl;
1769 #endif 1827 #endif
1770 cacheRect = rect(); 1828 cacheRect = rect();
1771 repaintCache = true; 1829 repaintCache = true;
1776 int dx = 1834 int dx =
1777 getXForFrame(m_cacheCentreFrame) - 1835 getXForFrame(m_cacheCentreFrame) -
1778 getXForFrame(m_centreFrame); 1836 getXForFrame(m_centreFrame);
1779 1837
1780 if (dx > -width() && dx < width()) { 1838 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; 1839 static QPixmap *tmpPixmap = 0;
1794 if (!tmpPixmap || 1840 if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) {
1795 tmpPixmap->width() != width() ||
1796 tmpPixmap->height() != height()) {
1797 delete tmpPixmap; 1841 delete tmpPixmap;
1798 tmpPixmap = new QPixmap(width(), height()); 1842 tmpPixmap = new QPixmap(scaledCacheSize);
1799 } 1843 }
1800 paint.begin(tmpPixmap); 1844 paint.begin(tmpPixmap);
1801 paint.drawPixmap(0, 0, *m_cache); 1845 paint.drawPixmap(0, 0, *m_cache);
1802 paint.end(); 1846 paint.end();
1803 paint.begin(m_cache); 1847 paint.begin(m_cache);
1804 paint.drawPixmap(dx, 0, *tmpPixmap); 1848 paint.drawPixmap(dx, 0, *tmpPixmap);
1805 paint.end(); 1849 paint.end();
1806 #endif
1807 if (dx < 0) { 1850 if (dx < 0) {
1808 cacheRect = QRect(width() + dx, 0, -dx, height()); 1851 cacheRect = QRect(width() + dx, 0, -dx, height());
1809 } else { 1852 } else {
1810 cacheRect = QRect(0, 0, dx, height()); 1853 cacheRect = QRect(0, 0, dx, height());
1811 } 1854 }
1822 1865
1823 } else { 1866 } else {
1824 #ifdef DEBUG_VIEW_WIDGET_PAINT 1867 #ifdef DEBUG_VIEW_WIDGET_PAINT
1825 cerr << "View(" << this << ")::paintEvent: cache is good" << endl; 1868 cerr << "View(" << this << ")::paintEvent: cache is good" << endl;
1826 #endif 1869 #endif
1827 paint.begin(this); 1870 paint.begin(m_buffer);
1828 paint.drawPixmap(cacheRect, *m_cache, cacheRect); 1871 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
1829 paint.end(); 1872 paint.end();
1830 QFrame::paintEvent(e); 1873 QFrame::paintEvent(e);
1831 paintedCacheRect = true; 1874 paintedCacheRect = true;
1832 } 1875 }
1833 1876
1839 // cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << endl; 1882 // cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << endl;
1840 #endif 1883 #endif
1841 1884
1842 // Scrollable (cacheable) items first 1885 // Scrollable (cacheable) items first
1843 1886
1887 ViewProxy proxy(this, dpratio);
1888
1844 if (!paintedCacheRect) { 1889 if (!paintedCacheRect) {
1845 1890
1846 if (repaintCache) paint.begin(m_cache); 1891 QRect rectToPaint;
1847 else paint.begin(this); 1892
1893 if (repaintCache) {
1894 paint.begin(m_cache);
1895 rectToPaint = scaledCacheRect;
1896 } else {
1897 paint.begin(m_buffer);
1898 rectToPaint = scaledCacheRect;
1899 }
1900
1848 setPaintFont(paint); 1901 setPaintFont(paint);
1849 paint.setClipRect(cacheRect); 1902 paint.setClipRect(rectToPaint);
1850 1903
1851 paint.setPen(getBackground()); 1904 paint.setPen(getBackground());
1852 paint.setBrush(getBackground()); 1905 paint.setBrush(getBackground());
1853 paint.drawRect(cacheRect); 1906 paint.drawRect(rectToPaint);
1854 1907
1855 paint.setPen(getForeground()); 1908 paint.setPen(getForeground());
1856 paint.setBrush(Qt::NoBrush); 1909 paint.setBrush(Qt::NoBrush);
1857 1910
1858 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) { 1911 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
1859 paint.setRenderHint(QPainter::Antialiasing, false); 1912 paint.setRenderHint(QPainter::Antialiasing, false);
1860 paint.save(); 1913 paint.save();
1861 (*i)->paint(this, paint, cacheRect); 1914 #ifdef DEBUG_VIEW_WIDGET_PAINT
1915 cerr << "Painting scrollable layer " << *i << " using proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << rectToPaint.x() << "," << rectToPaint.y() << " " << rectToPaint.width() << "x" << rectToPaint.height() << endl;
1916 #endif
1917 (*i)->paint(&proxy, paint, rectToPaint);
1862 paint.restore(); 1918 paint.restore();
1863 } 1919 }
1864 1920
1865 if (haveSelections && selectionCacheable) { 1921 if (haveSelections && selectionCacheable) {
1866 drawSelections(paint); 1922 drawSelections(paint);
1869 1925
1870 paint.end(); 1926 paint.end();
1871 1927
1872 if (repaintCache) { 1928 if (repaintCache) {
1873 cacheRect |= (e ? e->rect() : rect()); 1929 cacheRect |= (e ? e->rect() : rect());
1874 paint.begin(this); 1930 scaledCacheRect = scaledRect(cacheRect, dpratio);
1875 paint.drawPixmap(cacheRect, *m_cache, cacheRect); 1931 paint.begin(m_buffer);
1932 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
1876 paint.end(); 1933 paint.end();
1877 } 1934 }
1878 } 1935 }
1879 1936
1880 // Now non-cacheable items. We always need to redraw the 1937 // Now non-cacheable items. We always need to redraw the
1881 // non-cacheable items across at least the area we drew of the 1938 // non-cacheable items across at least the area we drew of the
1882 // cacheable items. 1939 // cacheable items.
1883 1940
1884 nonCacheRect |= cacheRect; 1941 nonCacheRect |= cacheRect;
1885 1942
1886 paint.begin(this); 1943 QRect scaledNonCacheRect = scaledRect(nonCacheRect, dpratio);
1887 paint.setClipRect(nonCacheRect); 1944
1945 paint.begin(m_buffer);
1946 paint.setClipRect(scaledNonCacheRect);
1888 setPaintFont(paint); 1947 setPaintFont(paint);
1889 if (scrollables.empty()) { 1948 if (scrollables.empty()) {
1890 paint.setPen(getBackground()); 1949 paint.setPen(getBackground());
1891 paint.setBrush(getBackground()); 1950 paint.setBrush(getBackground());
1892 paint.drawRect(nonCacheRect); 1951 paint.drawRect(scaledNonCacheRect);
1893 } 1952 }
1894 1953
1895 paint.setPen(getForeground()); 1954 paint.setPen(getForeground());
1896 paint.setBrush(Qt::NoBrush); 1955 paint.setBrush(Qt::NoBrush);
1897 1956
1898 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) { 1957 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
1899 // Profiler profiler2("View::paintEvent non-cacheable"); 1958 // Profiler profiler2("View::paintEvent non-cacheable");
1900 (*i)->paint(this, paint, nonCacheRect); 1959 #ifdef DEBUG_VIEW_WIDGET_PAINT
1960 cerr << "Painting non-scrollable layer " << *i << " without proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << nonCacheRect.x() << "," << nonCacheRect.y() << " " << nonCacheRect.width() << "x" << nonCacheRect.height() << endl;
1961 #endif
1962 (*i)->paint(&proxy, paint, scaledNonCacheRect);
1901 } 1963 }
1902 1964
1965 paint.end();
1966
1967 paint.begin(this);
1968 QRect finalPaintRect = e ? e->rect() : rect();
1969 paint.drawPixmap(finalPaintRect, *m_buffer, scaledRect(finalPaintRect, dpratio));
1903 paint.end(); 1970 paint.end();
1904 1971
1905 paint.begin(this); 1972 paint.begin(this);
1906 setPaintFont(paint); 1973 setPaintFont(paint);
1907 if (e) paint.setClipRect(e->rect()); 1974 if (e) paint.setClipRect(e->rect());
1923 // Don't show the play pointer when it is redundant with 1990 // Don't show the play pointer when it is redundant with
1924 // the centre line 1991 // the centre line
1925 showPlayPointer = false; 1992 showPlayPointer = false;
1926 } 1993 }
1927 } 1994 }
1928 1995
1929 if (showPlayPointer) { 1996 if (showPlayPointer) {
1930 1997
1931 paint.begin(this); 1998 paint.begin(this);
1932 1999
1933 int playx = getXForFrame(m_playPointerFrame); 2000 int playx = getXForFrame(m_playPointerFrame);
2410 paint.setPen(getForeground()); 2477 paint.setPen(getForeground());
2411 paint.setBrush(Qt::NoBrush); 2478 paint.setBrush(Qt::NoBrush);
2412 2479
2413 for (LayerList::iterator i = m_layerStack.begin(); 2480 for (LayerList::iterator i = m_layerStack.begin();
2414 i != m_layerStack.end(); ++i) { 2481 i != m_layerStack.end(); ++i) {
2415 if(!((*i)->isLayerDormant(this))){ 2482 if (!((*i)->isLayerDormant(this))){
2416 2483
2417 paint.setRenderHint(QPainter::Antialiasing, false); 2484 paint.setRenderHint(QPainter::Antialiasing, false);
2418 2485
2419 paint.save(); 2486 paint.save();
2420 paint.translate(xorigin + x, 0); 2487 paint.translate(xorigin + x, 0);
2421 2488
2422 cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl; 2489 cerr << "Centre frame now: " << m_centreFrame << " drawing to " << chunk.x() + x + xorigin << ", " << chunk.width() << endl;
2423 2490
2424 (*i)->setSynchronousPainting(true); 2491 (*i)->setSynchronousPainting(true);
2425 2492
2426 (*i)->paint(this, paint, chunk); 2493 (*i)->paint(this, paint, chunk);
2427 2494
2428 (*i)->setSynchronousPainting(false); 2495 (*i)->setSynchronousPainting(false);
2429 2496
2430 paint.restore(); 2497 paint.restore();
2431 } 2498 }
2432 } 2499 }
2433 } 2500 }
2434 2501
2435 m_centreFrame = origCentreFrame; 2502 m_centreFrame = origCentreFrame;
2436 update(); 2503 update();