diff layer/ScrollableImageCache.h @ 1031:55ac6ac1982e spectrogram-minor-refactor

Further fixes to the scrollable cache logic
author Chris Cannam
date Fri, 29 Jan 2016 18:51:05 +0000
parents 0be17aafa935
children 5144d7185fb5
line wrap: on
line diff
--- a/layer/ScrollableImageCache.h	Fri Jan 29 15:08:01 2016 +0000
+++ b/layer/ScrollableImageCache.h	Fri Jan 29 18:51:05 2016 +0000
@@ -53,11 +53,6 @@
 	return m_width > 0;
     }
 
-    bool spans(int left, int right) const {
-	return (getValidLeft() <= left &&
-		getValidRight() >= right);
-    }
-    
     QSize getSize() const {
 	return m_image.size();
     }
@@ -86,169 +81,57 @@
     int getZoomLevel() const {
 	return m_zoomLevel;
     }
+    
+    void setZoomLevel(int zoom) {
+	m_zoomLevel = zoom;
+	invalidate();
+    }
 
     sv_frame_t getStartFrame() const {
 	return m_startFrame;
     }
-    
-    void setZoomLevel(int zoom) {
-	m_zoomLevel = zoom;
+
+    /**
+     * Set the start frame and invalidate the cache. To scroll,
+     * i.e. to set the start frame while retaining cache validity
+     * where possible, use scrollTo() instead.
+     */
+    void setStartFrame(sv_frame_t frame) {
+	m_startFrame = frame;
 	invalidate();
     }
     
     const QImage &getImage() const {
 	return m_image;
     }
-    
-    void scrollTo(sv_frame_t newStartFrame) {
 
-	if (!m_v) throw std::logic_error("ScrollableImageCache: not associated with a LayerGeometryProvider");
-	
-	int dx = (m_v->getXForFrame(m_startFrame) -
-		  m_v->getXForFrame(newStartFrame));
+    /**
+     * Set the new start frame for the cache, if possible also moving
+     * along any existing valid data within the cache so that it
+     * continues to be valid for the new start frame.
+     */
+    void scrollTo(sv_frame_t newStartFrame);
 
-	m_startFrame = newStartFrame;
-	
-	if (!isValid()) {
-	    return;
-	}
-
-	int w = m_image.width();
-
-	if (dx == 0) {
-	    // haven't moved
-	    return;
-	}
-
-	if (dx <= -w || dx >= w) {
-	    // scrolled entirely off
-	    invalidate();
-	    return;
-	}
-	
-	// dx is in range, cache is scrollable
-
-	int dxp = dx;
-	if (dxp < 0) dxp = -dxp;
-
-	int copylen = (w - dxp) * int(sizeof(QRgb));
-	for (int y = 0; y < m_image.height(); ++y) {
-	    QRgb *line = (QRgb *)m_image.scanLine(y);
-	    if (dx < 0) {
-		memmove(line, line + dxp, copylen);
-	    } else {
-		memmove(line + dxp, line, copylen);
-	    }
-	}
-	
-	// update valid area
-        
-	int px = m_left;
-	int pw = m_width;
-	
-	px += dx;
-	
-	if (dx < 0) {
-	    // we scrolled left
-	    if (px < 0) {
-		pw += px;
-		px = 0;
-		if (pw < 0) {
-		    pw = 0;
-		}
-	    }
-	} else {
-	    // we scrolled right
-	    if (px + pw > w) {
-		pw = w - px;
-		if (pw < 0) {
-		    pw = 0;
-		}
-	    }
-	}
-
-	m_left = px;
-	m_width = pw;
-    }
-
-    void resizeToTouchValidArea(int &left, int &width,
-				bool &isLeftOfValidArea) const {
-	if (left < m_left) {
-	    isLeftOfValidArea = true;
-	    if (left + width < m_left + m_width) {
-		width = m_left - left;
-	    }
-	} else {
-	    isLeftOfValidArea = false;
-	    width = left + width - (m_left + m_width);
-	    left = m_left + m_width;
-	    if (width < 0) width = 0;
-	}
-    }
-    
+    /**
+     * Take a left coordinate and width describing a region, and
+     * adjust them so that they are contiguous with the cache valid
+     * region and so that the union of the adjusted region with the
+     * cache valid region contains the supplied region.
+     */
+    void adjustToTouchValidArea(int &left, int &width,
+				bool &isLeftOfValidArea) const;
+    /**
+     * Draw from an image onto the cache. The supplied image must have
+     * the same height as the cache and the full height is always
+     * drawn. The left and width parameters determine the target
+     * region of the cache, the imageLeft and imageWidth parameters
+     * the source region of the image.
+     */
     void drawImage(int left,
 		   int width,
 		   QImage image,
 		   int imageLeft,
-		   int imageWidth) {
-
-	if (image.height() != m_image.height()) {
-	    throw std::logic_error("Image height must match cache height in ScrollableImageCache::drawImage");
-	}
-	if (left < 0 || left + width > m_image.width()) {
-	    throw std::logic_error("Drawing area out of bounds in ScrollableImageCache::drawImage");
-	}
-	
-	QPainter painter(&m_image);
-	painter.drawImage(QRect(left, 0, width, m_image.height()),
-			  image,
-			  QRect(imageLeft, 0, imageWidth, image.height()));
-	painter.end();
-
-	if (!isValid()) {
-	    m_left = left;
-	    m_width = width;
-	    return;
-	}
-	
-	if (left < m_left) {
-	    if (left + width > m_left + m_width) {
-		// new image completely contains the old valid area --
-		// use the new area as is
-		m_left = left;
-		m_width = width;
-	    } else if (left + width < m_left) {
-		// new image completely off left of old valid area --
-		// we can't extend the valid area because the bit in
-		// between is not valid, so must use the new area only
-		m_left = left;
-		m_width = width;
-	    } else {
-		// new image overlaps old valid area on left side --
-		// use new left edge, and extend width to existing
-		// right edge
-		m_width = (m_left + m_width) - left;
-		m_left = left;
-	    }
-	} else {
-	    if (left > m_left + m_width) {
-		// new image completely off right of old valid area --
-		// we can't extend the valid area because the bit in
-		// between is not valid, so must use the new area only
-		m_left = left;
-		m_width = width;
-	    } else if (left + width > m_left + m_width) {
-		// new image overlaps old valid area on right side --
-		// use existing left edge, and extend width to new
-		// right edge
-		m_width = (left + width) - m_left;
-		// (m_left unchanged)
-	    } else {
-		// new image completely contained within old valid
-		// area -- leave the old area unchanged
-	    }
-	}
-    }
+		   int imageWidth);
     
 private:
     const LayerGeometryProvider *m_v;