Mercurial > hg > svgui
comparison view/View.cpp @ 1357:93eaff6f206d
Rework cacheing logic to reduce the number of reallocations and be more correct about the repaint areas. I don't expect the difference to be really noticeable but in theory performance should be a little better...
author | Chris Cannam |
---|---|
date | Thu, 11 Oct 2018 14:59:34 +0100 |
parents | b9bfcb8cd5a1 |
children | bbeffb29bf09 |
comparison
equal
deleted
inserted
replaced
1356:dddfd28e4f02 | 1357:93eaff6f206d |
---|---|
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 "base/HitCount.h" | |
23 #include "ViewProxy.h" | 24 #include "ViewProxy.h" |
24 | 25 |
25 #include "layer/TimeRulerLayer.h" | 26 #include "layer/TimeRulerLayer.h" |
26 #include "layer/SingleColourLayer.h" | 27 #include "layer/SingleColourLayer.h" |
27 #include "layer/PaintAssistant.h" | 28 #include "layer/PaintAssistant.h" |
61 m_followPlayIsDetached(false), | 62 m_followPlayIsDetached(false), |
62 m_playPointerFrame(0), | 63 m_playPointerFrame(0), |
63 m_showProgress(showProgress), | 64 m_showProgress(showProgress), |
64 m_cache(0), | 65 m_cache(0), |
65 m_buffer(0), | 66 m_buffer(0), |
67 m_cacheValid(false), | |
66 m_cacheCentreFrame(0), | 68 m_cacheCentreFrame(0), |
67 m_cacheZoomLevel(ZoomLevel::FramesPerPixel, 1024), | 69 m_cacheZoomLevel(ZoomLevel::FramesPerPixel, 1024), |
68 m_selectionCached(false), | 70 m_selectionCached(false), |
69 m_deleting(false), | 71 m_deleting(false), |
70 m_haveSelectedLayer(false), | 72 m_haveSelectedLayer(false), |
258 update(); | 260 update(); |
259 } | 261 } |
260 return; | 262 return; |
261 } | 263 } |
262 | 264 |
263 delete m_cache; | 265 m_cacheValid = false; |
264 m_cache = 0; | |
265 | 266 |
266 Layer *selectedLayer = 0; | 267 Layer *selectedLayer = 0; |
267 | 268 |
268 for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) { | 269 for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) { |
269 if (*i == pc) { | 270 if (*i == pc) { |
291 } | 292 } |
292 | 293 |
293 void | 294 void |
294 View::overlayModeChanged() | 295 View::overlayModeChanged() |
295 { | 296 { |
296 delete m_cache; | 297 m_cacheValid = false; |
297 m_cache = 0; | |
298 update(); | 298 update(); |
299 } | 299 } |
300 | 300 |
301 void | 301 void |
302 View::zoomWheelsEnabledChanged() | 302 View::zoomWheelsEnabledChanged() |
615 } | 615 } |
616 | 616 |
617 void | 617 void |
618 View::addLayer(Layer *layer) | 618 View::addLayer(Layer *layer) |
619 { | 619 { |
620 delete m_cache; | 620 m_cacheValid = false; |
621 m_cache = 0; | |
622 | 621 |
623 SingleColourLayer *scl = dynamic_cast<SingleColourLayer *>(layer); | 622 SingleColourLayer *scl = dynamic_cast<SingleColourLayer *>(layer); |
624 if (scl) scl->setDefaultColourFor(this); | 623 if (scl) scl->setDefaultColourFor(this); |
625 | 624 |
626 m_fixedOrderLayers.push_back(layer); | 625 m_fixedOrderLayers.push_back(layer); |
687 { | 686 { |
688 if (m_deleting) { | 687 if (m_deleting) { |
689 return; | 688 return; |
690 } | 689 } |
691 | 690 |
692 delete m_cache; | 691 m_cacheValid = false; |
693 m_cache = 0; | |
694 | 692 |
695 for (LayerList::iterator i = m_fixedOrderLayers.begin(); | 693 for (LayerList::iterator i = m_fixedOrderLayers.begin(); |
696 i != m_fixedOrderLayers.end(); | 694 i != m_fixedOrderLayers.end(); |
697 ++i) { | 695 ++i) { |
698 if (*i == layer) { | 696 if (*i == layer) { |
905 break; | 903 break; |
906 } | 904 } |
907 } | 905 } |
908 | 906 |
909 if (recreate) { | 907 if (recreate) { |
910 delete m_cache; | 908 m_cacheValid = false; |
911 m_cache = 0; | |
912 } | 909 } |
913 | 910 |
914 emit layerModelChanged(); | 911 emit layerModelChanged(); |
915 | 912 |
916 checkProgress(obj); | 913 checkProgress(obj); |
953 break; | 950 break; |
954 } | 951 } |
955 } | 952 } |
956 | 953 |
957 if (recreate) { | 954 if (recreate) { |
958 delete m_cache; | 955 m_cacheValid = false; |
959 m_cache = 0; | |
960 } | 956 } |
961 | 957 |
962 if (startFrame < myStartFrame) startFrame = myStartFrame; | 958 if (startFrame < myStartFrame) startFrame = myStartFrame; |
963 if (endFrame > myEndFrame) endFrame = myEndFrame; | 959 if (endFrame > myEndFrame) endFrame = myEndFrame; |
964 | 960 |
989 View::modelReplaced() | 985 View::modelReplaced() |
990 { | 986 { |
991 #ifdef DEBUG_VIEW_WIDGET_PAINT | 987 #ifdef DEBUG_VIEW_WIDGET_PAINT |
992 cerr << "View(" << this << ")::modelReplaced()" << endl; | 988 cerr << "View(" << this << ")::modelReplaced()" << endl; |
993 #endif | 989 #endif |
994 delete m_cache; | 990 m_cacheValid = false; |
995 m_cache = 0; | |
996 | |
997 update(); | 991 update(); |
998 } | 992 } |
999 | 993 |
1000 void | 994 void |
1001 View::layerParametersChanged() | 995 View::layerParametersChanged() |
1004 | 998 |
1005 #ifdef DEBUG_VIEW_WIDGET_PAINT | 999 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1006 SVDEBUG << "View::layerParametersChanged()" << endl; | 1000 SVDEBUG << "View::layerParametersChanged()" << endl; |
1007 #endif | 1001 #endif |
1008 | 1002 |
1009 delete m_cache; | 1003 m_cacheValid = false; |
1010 m_cache = 0; | |
1011 update(); | 1004 update(); |
1012 | 1005 |
1013 if (layer) { | 1006 if (layer) { |
1014 emit propertyContainerPropertyChanged(layer); | 1007 emit propertyContainerPropertyChanged(layer); |
1015 } | 1008 } |
1201 | 1194 |
1202 void | 1195 void |
1203 View::selectionChanged() | 1196 View::selectionChanged() |
1204 { | 1197 { |
1205 if (m_selectionCached) { | 1198 if (m_selectionCached) { |
1206 delete m_cache; | 1199 m_cacheValid = false; |
1207 m_cache = 0; | |
1208 m_selectionCached = false; | 1200 m_selectionCached = false; |
1209 } | 1201 } |
1210 update(); | 1202 update(); |
1211 } | 1203 } |
1212 | 1204 |
1801 | 1793 |
1802 // ensure our constraints are met | 1794 // ensure our constraints are met |
1803 m_zoomLevel = getZoomConstraintLevel | 1795 m_zoomLevel = getZoomConstraintLevel |
1804 (m_zoomLevel, ZoomConstraint::RoundNearest); | 1796 (m_zoomLevel, ZoomConstraint::RoundNearest); |
1805 | 1797 |
1806 QPainter paint; | 1798 // We have a cache, which retains the state of scrollable (back) |
1807 bool repaintCache = false; | 1799 // layers from one paint to the next, and a buffer, which we paint |
1808 bool paintedCacheRect = false; | 1800 // onto before copying directly to the widget. Both are at scaled |
1809 | 1801 // resolution (e.g. 2x on a pixel-doubled display), whereas the |
1810 QRect cacheRect(rect()); | 1802 // paint event always comes in at formal (1x) resolution. |
1811 | 1803 |
1804 // If we touch the cache, we always leave it in a valid state | |
1805 // across its whole extent. When another method invalidates the | |
1806 // cache, it does so by setting m_cacheValid false, so if that | |
1807 // flag is true on entry, then the cache is valid across its whole | |
1808 // extent - although it may be valid for a different centre frame, | |
1809 // zoom level, or view size from those now in effect. | |
1810 | |
1811 // Our process goes: | |
1812 // | |
1813 // 1. Check whether we have any scrollable (cacheable) layers. If | |
1814 // we don't, then invalidate and ignore the cache and go to | |
1815 // step 5. Otherwise: | |
1816 // | |
1817 // 2. Check the cache, scroll as necessary, identify any area that | |
1818 // needs to be refreshed (this might be the whole cache). | |
1819 // | |
1820 // 3. Paint to cache the area that needs to be refreshed, from the | |
1821 // stack of scrollable layers. | |
1822 // | |
1823 // 4. Paint to buffer from cache: if there are no non-cached areas | |
1824 // or selections and the cache has not scrolled, then paint the | |
1825 // union of the area of cache that has changed and the area | |
1826 // that the paint event reported as exposed; otherwise paint | |
1827 // the whole. | |
1828 // | |
1829 // 5. Paint the exposed area to the buffer from the cache plus all | |
1830 // the layers that haven't been cached, plus selections etc. | |
1831 // | |
1832 // 6. Paint the exposed rect from the buffer. | |
1833 // | |
1834 // Note that all rects except the target for the final step are at | |
1835 // cache (scaled, 2x as applicable) resolution. | |
1836 | |
1837 int dpratio = effectiveDevicePixelRatio(); | |
1838 | |
1839 QRect requestedPaintArea(scaledRect(rect(), dpratio)); | |
1812 if (e) { | 1840 if (e) { |
1813 cacheRect &= e->rect(); | 1841 // cut down to only the area actually exposed |
1814 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1842 requestedPaintArea &= scaledRect(e->rect(), dpratio); |
1815 cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height() | 1843 } |
1816 << ", my rect " << width() << "x" << height() << endl; | |
1817 #endif | |
1818 } | |
1819 | |
1820 QRect nonCacheRect(cacheRect); | |
1821 | |
1822 int dpratio = effectiveDevicePixelRatio(); | |
1823 | 1844 |
1824 // If not all layers are scrollable, but some of the back layers | 1845 // If not all layers are scrollable, but some of the back layers |
1825 // are, we should store only those in the cache. | 1846 // are, we should store only those in the cache. |
1826 | 1847 |
1827 bool layersChanged = false; | 1848 bool layersChanged = false; |
1828 LayerList scrollables = getScrollableBackLayers(true, layersChanged); | 1849 LayerList scrollables = getScrollableBackLayers(true, layersChanged); |
1829 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged); | 1850 LayerList nonScrollables = getNonScrollableFrontLayers(true, layersChanged); |
1830 bool selectionCacheable = nonScrollables.empty(); | |
1831 bool haveSelections = m_manager && !m_manager->getSelections().empty(); | |
1832 | |
1833 // If all the non-scrollable layers are non-opaque, then we draw | |
1834 // the selection rectangle behind them and cache it. If any are | |
1835 // opaque, however, or if our device-pixel ratio is not 1 (so we | |
1836 // need to paint direct to the widget), then we can't cache. | |
1837 // | |
1838 if (dpratio == 1) { | |
1839 | |
1840 if (!selectionCacheable) { | |
1841 selectionCacheable = true; | |
1842 for (LayerList::const_iterator i = nonScrollables.begin(); | |
1843 i != nonScrollables.end(); ++i) { | |
1844 if ((*i)->isLayerOpaque()) { | |
1845 selectionCacheable = false; | |
1846 break; | |
1847 } | |
1848 } | |
1849 } | |
1850 | |
1851 if (selectionCacheable) { | |
1852 QPoint localPos; | |
1853 bool closeToLeft, closeToRight; | |
1854 if (shouldIlluminateLocalSelection | |
1855 (localPos, closeToLeft, closeToRight)) { | |
1856 selectionCacheable = false; | |
1857 } | |
1858 } | |
1859 | |
1860 } else { | |
1861 | |
1862 selectionCacheable = false; | |
1863 } | |
1864 | 1851 |
1865 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1852 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1866 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size() | 1853 cerr << "View(" << this << ")::paintEvent: have " << scrollables.size() |
1867 << " scrollable back layers and " << nonScrollables.size() | 1854 << " scrollable back layers and " << nonScrollables.size() |
1868 << " non-scrollable front layers" << endl; | 1855 << " non-scrollable front layers" << endl; |
1869 cerr << "haveSelections " << haveSelections << ", selectionCacheable " | 1856 #endif |
1870 << selectionCacheable << ", m_selectionCached " << m_selectionCached << endl; | 1857 |
1871 #endif | 1858 if (layersChanged || scrollables.empty()) { |
1872 | 1859 m_cacheValid = false; |
1873 if (layersChanged || scrollables.empty() || | 1860 } |
1874 (haveSelections && (selectionCacheable != m_selectionCached))) { | 1861 |
1875 delete m_cache; | 1862 QRect wholeArea(scaledRect(rect(), dpratio)); |
1876 m_cache = 0; | 1863 QSize wholeSize(scaledSize(size(), dpratio)); |
1877 m_selectionCached = false; | 1864 |
1878 } | 1865 if (!m_buffer || wholeSize != m_buffer->size()) { |
1879 | |
1880 QSize scaledCacheSize(scaledSize(size(), dpratio)); | |
1881 QRect scaledCacheRect(scaledRect(cacheRect, dpratio)); | |
1882 | |
1883 if (!m_buffer || scaledCacheSize != m_buffer->size()) { | |
1884 delete m_buffer; | 1866 delete m_buffer; |
1885 m_buffer = new QPixmap(scaledCacheSize); | 1867 m_buffer = new QPixmap(wholeSize); |
1886 } | 1868 } |
1869 | |
1870 bool shouldUseCache = false; | |
1871 bool shouldRepaintCache = false; | |
1872 QRect cacheAreaToRepaint; | |
1887 | 1873 |
1874 static HitCount count("View cache"); | |
1875 | |
1888 if (!scrollables.empty()) { | 1876 if (!scrollables.empty()) { |
1877 | |
1878 shouldUseCache = true; | |
1879 shouldRepaintCache = true; | |
1880 cacheAreaToRepaint = wholeArea; | |
1889 | 1881 |
1890 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1882 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1891 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom " | 1883 cerr << "View(" << this << "): cache " << m_cache << ", cache zoom " |
1892 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl; | 1884 << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl; |
1893 #endif | 1885 #endif |
1894 | 1886 |
1895 using namespace std::rel_ops; | 1887 using namespace std::rel_ops; |
1896 | 1888 |
1897 if (!m_cache || | 1889 if (!m_cacheValid || |
1890 !m_cache || | |
1898 m_cacheZoomLevel != m_zoomLevel || | 1891 m_cacheZoomLevel != m_zoomLevel || |
1899 scaledCacheSize != m_cache->size()) { | 1892 m_cache->size() != wholeSize) { |
1900 | 1893 |
1901 // cache is not valid | 1894 // cache is not valid at all |
1902 | 1895 |
1903 if (cacheRect.width() < width()/10) { | 1896 if (requestedPaintArea.width() < wholeSize.width() / 10) { |
1904 delete m_cache; | 1897 |
1905 m_cache = 0; | 1898 m_cacheValid = false; |
1899 shouldUseCache = false; | |
1900 shouldRepaintCache = false; | |
1901 | |
1906 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1902 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1907 cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl; | 1903 cerr << "View(" << this << ")::paintEvent: cache is invalid but only small area requested, will repaint directly instead" << endl; |
1908 #endif | 1904 #endif |
1909 } else { | 1905 } else { |
1910 delete m_cache; | 1906 |
1911 m_cache = new QPixmap(scaledCacheSize); | 1907 if (!m_cache || |
1908 m_cache->size() != wholeSize) { | |
1909 delete m_cache; | |
1910 m_cache = new QPixmap(wholeSize); | |
1911 } | |
1912 | |
1912 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1913 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1913 cerr << "View(" << this << ")::paintEvent: recreated cache" << endl; | 1914 cerr << "View(" << this << ")::paintEvent: cache is invalid, will repaint whole" << endl; |
1914 #endif | 1915 #endif |
1915 cacheRect = rect(); | 1916 } |
1916 repaintCache = true; | 1917 |
1917 } | 1918 count.miss(); |
1918 | 1919 |
1919 } else if (m_cacheCentreFrame != m_centreFrame) { | 1920 } else if (m_cacheCentreFrame != m_centreFrame) { |
1920 | 1921 |
1921 int dx = | 1922 int dx = dpratio * (getXForFrame(m_cacheCentreFrame) - |
1922 getXForFrame(m_cacheCentreFrame) - | 1923 getXForFrame(m_centreFrame)); |
1923 getXForFrame(m_centreFrame); | 1924 |
1924 | 1925 if (dx > -m_cache->width() && dx < m_cache->width()) { |
1925 if (dx > -width() && dx < width()) { | 1926 |
1926 static QPixmap *tmpPixmap = 0; | 1927 m_cache->scroll(dx, 0, m_cache->rect(), 0); |
1927 if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) { | 1928 |
1928 delete tmpPixmap; | 1929 if (dx < 0) { |
1929 tmpPixmap = new QPixmap(scaledCacheSize); | 1930 cacheAreaToRepaint = |
1931 QRect(m_cache->width() + dx, 0, -dx, m_cache->height()); | |
1932 } else { | |
1933 cacheAreaToRepaint = | |
1934 QRect(0, 0, dx, m_cache->height()); | |
1930 } | 1935 } |
1931 paint.begin(tmpPixmap); | 1936 |
1932 paint.drawPixmap(0, 0, *m_cache); | 1937 count.partial(); |
1933 paint.end(); | 1938 |
1934 paint.begin(m_cache); | |
1935 paint.drawPixmap(dx, 0, *tmpPixmap); | |
1936 paint.end(); | |
1937 if (dx < 0) { | |
1938 cacheRect = QRect(width() + dx, 0, -dx, height()); | |
1939 } else { | |
1940 cacheRect = QRect(0, 0, dx, height()); | |
1941 } | |
1942 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1939 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1943 cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << endl; | 1940 cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << endl; |
1944 #endif | 1941 #endif |
1945 } else { | 1942 } else { |
1946 cacheRect = rect(); | 1943 count.miss(); |
1947 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1944 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1948 cerr << "View(" << this << ")::paintEvent: scrolling too far" << endl; | 1945 cerr << "View(" << this << ")::paintEvent: scrolling too far" << endl; |
1949 #endif | 1946 #endif |
1950 } | 1947 } |
1951 repaintCache = true; | |
1952 | 1948 |
1953 } else { | 1949 } else { |
1954 #ifdef DEBUG_VIEW_WIDGET_PAINT | 1950 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1955 cerr << "View(" << this << ")::paintEvent: cache is good" << endl; | 1951 cerr << "View(" << this << ")::paintEvent: cache is good" << endl; |
1956 #endif | 1952 #endif |
1957 paint.begin(m_buffer); | 1953 count.hit(); |
1958 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect); | 1954 shouldRepaintCache = false; |
1959 paint.end(); | 1955 } |
1960 QFrame::paintEvent(e); | 1956 } |
1961 paintedCacheRect = true; | 1957 |
1962 } | 1958 #ifdef DEBUG_VIEW_WIDGET_PAINT |
1963 | 1959 cerr << "View(" << this << ")::paintEvent: m_cacheValid = " << m_cacheValid << ", shouldUseCache = " << shouldUseCache << ", shouldRepaintCache = " << shouldRepaintCache << ", cacheAreaToRepaint = " << cacheAreaToRepaint.x() << "," << cacheAreaToRepaint.y() << " " << cacheAreaToRepaint.width() << "x" << cacheAreaToRepaint.height() << endl; |
1960 #endif | |
1961 | |
1962 if (shouldRepaintCache && !shouldUseCache) { | |
1963 // If we are repainting the cache, then we paint the | |
1964 // scrollables only to the cache, not to the buffer. So if | |
1965 // shouldUseCache is also false, then the scrollables can't | |
1966 // appear because they will only be on the cache | |
1967 throw std::logic_error("ERROR: shouldRepaintCache is true, but shouldUseCache is false: this can't lead to the correct result"); | |
1968 } | |
1969 | |
1970 // Scrollable (cacheable) items first. If we are repainting the | |
1971 // cache, then we paint these to the cache; otherwise straight to | |
1972 // the buffer. | |
1973 | |
1974 ViewProxy proxy(this, dpratio); | |
1975 QRect areaToPaint; | |
1976 QPainter paint; | |
1977 | |
1978 if (shouldRepaintCache) { | |
1979 paint.begin(m_cache); | |
1980 areaToPaint = cacheAreaToRepaint; | |
1981 } else { | |
1982 paint.begin(m_buffer); | |
1983 areaToPaint = requestedPaintArea; | |
1984 } | |
1985 | |
1986 setPaintFont(paint); | |
1987 paint.setClipRect(areaToPaint); | |
1988 | |
1989 paint.setPen(getBackground()); | |
1990 paint.setBrush(getBackground()); | |
1991 paint.drawRect(areaToPaint); | |
1992 | |
1993 paint.setPen(getForeground()); | |
1994 paint.setBrush(Qt::NoBrush); | |
1995 | |
1996 for (LayerList::iterator i = scrollables.begin(); | |
1997 i != scrollables.end(); ++i) { | |
1998 | |
1999 paint.setRenderHint(QPainter::Antialiasing, false); | |
2000 paint.save(); | |
2001 | |
2002 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
2003 cerr << "Painting scrollable layer " << *i << " using proxy with shouldRepaintCache = " << shouldRepaintCache << ", dpratio = " << dpratio << ", areaToPaint = " << areaToPaint.x() << "," << areaToPaint.y() << " " << areaToPaint.width() << "x" << areaToPaint.height() << endl; | |
2004 #endif | |
2005 | |
2006 (*i)->paint(&proxy, paint, areaToPaint); | |
2007 | |
2008 paint.restore(); | |
2009 } | |
2010 | |
2011 paint.end(); | |
2012 | |
2013 if (shouldRepaintCache) { | |
2014 // and now we have | |
2015 m_cacheValid = true; | |
1964 m_cacheCentreFrame = m_centreFrame; | 2016 m_cacheCentreFrame = m_centreFrame; |
1965 m_cacheZoomLevel = m_zoomLevel; | 2017 m_cacheZoomLevel = m_zoomLevel; |
1966 } | 2018 } |
1967 | 2019 |
1968 #ifdef DEBUG_VIEW_WIDGET_PAINT | 2020 if (shouldUseCache) { |
1969 // cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << endl; | 2021 paint.begin(m_buffer); |
1970 #endif | 2022 paint.drawPixmap(requestedPaintArea, *m_cache, requestedPaintArea); |
1971 | |
1972 // Scrollable (cacheable) items first | |
1973 | |
1974 ViewProxy proxy(this, dpratio); | |
1975 | |
1976 if (!paintedCacheRect) { | |
1977 | |
1978 QRect rectToPaint; | |
1979 | |
1980 if (repaintCache) { | |
1981 paint.begin(m_cache); | |
1982 rectToPaint = scaledCacheRect; | |
1983 } else { | |
1984 paint.begin(m_buffer); | |
1985 rectToPaint = scaledCacheRect; | |
1986 } | |
1987 | |
1988 setPaintFont(paint); | |
1989 paint.setClipRect(rectToPaint); | |
1990 | |
1991 paint.setPen(getBackground()); | |
1992 paint.setBrush(getBackground()); | |
1993 paint.drawRect(rectToPaint); | |
1994 | |
1995 paint.setPen(getForeground()); | |
1996 paint.setBrush(Qt::NoBrush); | |
1997 | |
1998 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) { | |
1999 paint.setRenderHint(QPainter::Antialiasing, false); | |
2000 paint.save(); | |
2001 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
2002 cerr << "Painting scrollable layer " << *i << " using proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << rectToPaint.x() << "," << rectToPaint.y() << " " << rectToPaint.width() << "x" << rectToPaint.height() << endl; | |
2003 #endif | |
2004 (*i)->paint(&proxy, paint, rectToPaint); | |
2005 paint.restore(); | |
2006 } | |
2007 | |
2008 if (haveSelections && selectionCacheable) { | |
2009 drawSelections(paint); | |
2010 m_selectionCached = repaintCache; | |
2011 } | |
2012 | |
2013 paint.end(); | 2023 paint.end(); |
2014 | 2024 } |
2015 if (repaintCache) { | 2025 |
2016 cacheRect |= (e ? e->rect() : rect()); | 2026 // Now non-cacheable items. |
2017 scaledCacheRect = scaledRect(cacheRect, dpratio); | 2027 |
2018 paint.begin(m_buffer); | |
2019 paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect); | |
2020 paint.end(); | |
2021 } | |
2022 } | |
2023 | |
2024 // Now non-cacheable items. We always need to redraw the | |
2025 // non-cacheable items across at least the area we drew of the | |
2026 // cacheable items. | |
2027 | |
2028 nonCacheRect |= cacheRect; | |
2029 | |
2030 QRect scaledNonCacheRect = scaledRect(nonCacheRect, dpratio); | |
2031 | |
2032 paint.begin(m_buffer); | 2028 paint.begin(m_buffer); |
2033 paint.setClipRect(scaledNonCacheRect); | 2029 paint.setClipRect(requestedPaintArea); |
2034 setPaintFont(paint); | 2030 setPaintFont(paint); |
2035 if (scrollables.empty()) { | 2031 if (scrollables.empty()) { |
2036 paint.setPen(getBackground()); | 2032 paint.setPen(getBackground()); |
2037 paint.setBrush(getBackground()); | 2033 paint.setBrush(getBackground()); |
2038 paint.drawRect(scaledNonCacheRect); | 2034 paint.drawRect(requestedPaintArea); |
2039 } | 2035 } |
2040 | 2036 |
2041 paint.setPen(getForeground()); | 2037 paint.setPen(getForeground()); |
2042 paint.setBrush(Qt::NoBrush); | 2038 paint.setBrush(Qt::NoBrush); |
2043 | 2039 |
2044 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) { | 2040 for (LayerList::iterator i = nonScrollables.begin(); |
2041 i != nonScrollables.end(); ++i) { | |
2042 | |
2045 // Profiler profiler2("View::paintEvent non-cacheable"); | 2043 // Profiler profiler2("View::paintEvent non-cacheable"); |
2046 #ifdef DEBUG_VIEW_WIDGET_PAINT | 2044 #ifdef DEBUG_VIEW_WIDGET_PAINT |
2047 cerr << "Painting non-scrollable layer " << *i << " without proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << nonCacheRect.x() << "," << nonCacheRect.y() << " " << nonCacheRect.width() << "x" << nonCacheRect.height() << endl; | 2045 cerr << "Painting non-scrollable layer " << *i << " without proxy with shouldRepaintCache = " << shouldRepaintCache << ", dpratio = " << dpratio << ", requestedPaintArea = " << requestedPaintArea.x() << "," << requestedPaintArea.y() << " " << requestedPaintArea.width() << "x" << requestedPaintArea.height() << endl; |
2048 #endif | 2046 #endif |
2049 (*i)->paint(&proxy, paint, scaledNonCacheRect); | 2047 (*i)->paint(&proxy, paint, requestedPaintArea); |
2050 } | 2048 } |
2051 | 2049 |
2052 paint.end(); | 2050 paint.end(); |
2053 | 2051 |
2054 paint.begin(this); | 2052 // Now paint to widget from buffer: target rects from here on, |
2055 QRect finalPaintRect = e ? e->rect() : rect(); | 2053 // unlike all the preceding, are at formal (1x) resolution |
2056 paint.drawPixmap(finalPaintRect, *m_buffer, scaledRect(finalPaintRect, dpratio)); | |
2057 paint.end(); | |
2058 | 2054 |
2059 paint.begin(this); | 2055 paint.begin(this); |
2060 setPaintFont(paint); | 2056 setPaintFont(paint); |
2061 if (e) paint.setClipRect(e->rect()); | 2057 if (e) paint.setClipRect(e->rect()); |
2062 if (!m_selectionCached) { | 2058 |
2063 drawSelections(paint); | 2059 QRect finalPaintRect = e ? e->rect() : rect(); |
2064 } | 2060 paint.drawPixmap(finalPaintRect, *m_buffer, |
2061 scaledRect(finalPaintRect, dpratio)); | |
2062 | |
2063 drawSelections(paint); | |
2064 drawPlayPointer(paint); | |
2065 | |
2065 paint.end(); | 2066 paint.end(); |
2066 | |
2067 bool showPlayPointer = true; | |
2068 if (m_followPlay == PlaybackScrollContinuous) { | |
2069 showPlayPointer = false; | |
2070 } else if (m_playPointerFrame <= getStartFrame() || | |
2071 m_playPointerFrame >= getEndFrame()) { | |
2072 showPlayPointer = false; | |
2073 } else if (m_manager && !m_manager->isPlaying()) { | |
2074 if (m_playPointerFrame == getCentreFrame() && | |
2075 m_manager->shouldShowCentreLine() && | |
2076 m_followPlay != PlaybackIgnore) { | |
2077 // Don't show the play pointer when it is redundant with | |
2078 // the centre line | |
2079 showPlayPointer = false; | |
2080 } | |
2081 } | |
2082 | |
2083 if (showPlayPointer) { | |
2084 | |
2085 paint.begin(this); | |
2086 | |
2087 int playx = getXForFrame(m_playPointerFrame); | |
2088 | |
2089 paint.setPen(getForeground()); | |
2090 paint.drawLine(playx - 1, 0, playx - 1, height() - 1); | |
2091 paint.drawLine(playx + 1, 0, playx + 1, height() - 1); | |
2092 paint.drawPoint(playx, 0); | |
2093 paint.drawPoint(playx, height() - 1); | |
2094 paint.setPen(getBackground()); | |
2095 paint.drawLine(playx, 1, playx, height() - 2); | |
2096 | |
2097 paint.end(); | |
2098 } | |
2099 | 2067 |
2100 QFrame::paintEvent(e); | 2068 QFrame::paintEvent(e); |
2101 } | 2069 } |
2102 | 2070 |
2103 void | 2071 void |
2256 | 2224 |
2257 paint.restore(); | 2225 paint.restore(); |
2258 } | 2226 } |
2259 | 2227 |
2260 void | 2228 void |
2229 View::drawPlayPointer(QPainter &paint) | |
2230 { | |
2231 bool showPlayPointer = true; | |
2232 | |
2233 if (m_followPlay == PlaybackScrollContinuous) { | |
2234 showPlayPointer = false; | |
2235 } else if (m_playPointerFrame <= getStartFrame() || | |
2236 m_playPointerFrame >= getEndFrame()) { | |
2237 showPlayPointer = false; | |
2238 } else if (m_manager && !m_manager->isPlaying()) { | |
2239 if (m_playPointerFrame == getCentreFrame() && | |
2240 m_manager->shouldShowCentreLine() && | |
2241 m_followPlay != PlaybackIgnore) { | |
2242 // Don't show the play pointer when it is redundant with | |
2243 // the centre line | |
2244 showPlayPointer = false; | |
2245 } | |
2246 } | |
2247 | |
2248 if (showPlayPointer) { | |
2249 | |
2250 int playx = getXForFrame(m_playPointerFrame); | |
2251 | |
2252 paint.setPen(getForeground()); | |
2253 paint.drawLine(playx - 1, 0, playx - 1, height() - 1); | |
2254 paint.drawLine(playx + 1, 0, playx + 1, height() - 1); | |
2255 paint.drawPoint(playx, 0); | |
2256 paint.drawPoint(playx, height() - 1); | |
2257 paint.setPen(getBackground()); | |
2258 paint.drawLine(playx, 1, playx, height() - 2); | |
2259 } | |
2260 } | |
2261 | |
2262 void | |
2261 View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r, | 2263 View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r, |
2262 bool focus) const | 2264 bool focus) const |
2263 { | 2265 { |
2264 // SVDEBUG << "View::drawMeasurementRect(" << r.x() << "," << r.y() << " " | 2266 // SVDEBUG << "View::drawMeasurementRect(" << r.x() << "," << r.y() << " " |
2265 // << r.width() << "x" << r.height() << ")" << endl; | 2267 // << r.width() << "x" << r.height() << ")" << endl; |