1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 /* 4 Sonic Visualiser 5 An audio file viewer and annotation editor. 6 Centre for Digital Music, Queen Mary, University of London. 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. See the file 12 COPYING included with this distribution for more information. 13 */ 14 15 #ifndef SCROLLABLE_IMAGE_CACHE_H 16 #define SCROLLABLE_IMAGE_CACHE_H 17 18 #include "base/BaseTypes.h" 19 20 #include "LayerGeometryProvider.h" 21 22 #include <QImage> 23 #include <QRect> 24 #include <QPainter> 25 26 /** 27 * A cached image for a view that scrolls horizontally, such as a 28 * spectrogram. The cache object holds an image, reports the size of 29 * the image (likely the same as the underlying view, but it's the 30 * caller's responsibility to set the size appropriately), can scroll 31 * the image, and can report and update which contiguous horizontal 32 * range of the image is valid. 33 * 34 * The only way to *update* the valid area in a cache is to draw to it 35 * using the drawImage call. 36 */ 37 class ScrollableImageCache 38 { 39 public: ScrollableImageCache()40 ScrollableImageCache() : 41 m_validLeft(0), 42 m_validWidth(0), 43 m_startFrame(0) 44 {} 45 invalidate()46 void invalidate() { 47 m_validWidth = 0; 48 } 49 isValid()50 bool isValid() const { 51 return m_validWidth > 0; 52 } 53 getSize()54 QSize getSize() const { 55 return m_image.size(); 56 } 57 58 /** 59 * Set the size of the cache. If the new size differs from the 60 * current size, the cache is invalidated. 61 */ resize(QSize newSize)62 void resize(QSize newSize) { 63 if (getSize() != newSize) { 64 m_image = QImage(newSize, QImage::Format_ARGB32_Premultiplied); 65 invalidate(); 66 } 67 } 68 getValidLeft()69 int getValidLeft() const { 70 return m_validLeft; 71 } 72 getValidWidth()73 int getValidWidth() const { 74 return m_validWidth; 75 } 76 getValidRight()77 int getValidRight() const { 78 return m_validLeft + m_validWidth; 79 } 80 getValidArea()81 QRect getValidArea() const { 82 return QRect(m_validLeft, 0, m_validWidth, m_image.height()); 83 } 84 getZoomLevel()85 ZoomLevel getZoomLevel() const { 86 return m_zoomLevel; 87 } 88 89 /** 90 * Set the zoom level. If the new zoom level differs from the 91 * current one, the cache is invalidated. (Determining whether to 92 * invalidate the cache here is the only thing the zoom level is 93 * used for.) 94 */ setZoomLevel(ZoomLevel zoom)95 void setZoomLevel(ZoomLevel zoom) { 96 using namespace std::rel_ops; 97 if (m_zoomLevel != zoom) { 98 m_zoomLevel = zoom; 99 invalidate(); 100 } 101 } 102 getStartFrame()103 sv_frame_t getStartFrame() const { 104 return m_startFrame; 105 } 106 107 /** 108 * Set the start frame. If the new start frame differs from the 109 * current one, the cache is invalidated. To scroll, i.e. to set 110 * the start frame while retaining cache validity where possible, 111 * use scrollTo() instead. 112 */ setStartFrame(sv_frame_t frame)113 void setStartFrame(sv_frame_t frame) { 114 if (m_startFrame != frame) { 115 m_startFrame = frame; 116 invalidate(); 117 } 118 } 119 getImage()120 const QImage &getImage() const { 121 return m_image; 122 } 123 124 /** 125 * Set the new start frame for the cache, according to the 126 * geometry of the supplied LayerGeometryProvider, if possible 127 * also moving along any existing valid data within the cache so 128 * that it continues to be valid for the new start frame. 129 */ 130 void scrollTo(const LayerGeometryProvider *v, sv_frame_t newStartFrame); 131 132 /** 133 * Take a left coordinate and width describing a region, and 134 * adjust them so that they are contiguous with the cache valid 135 * region and so that the union of the adjusted region with the 136 * cache valid region contains the supplied region. Does not 137 * modify anything about the cache, only about the arguments. 138 */ 139 void adjustToTouchValidArea(int &left, int &width, 140 bool &isLeftOfValidArea) const; 141 142 /** 143 * Draw from an image onto the cache. The supplied image must have 144 * the same height as the cache and the full height is always 145 * drawn. The left and width parameters determine the target 146 * region of the cache, the imageLeft and imageWidth parameters 147 * the source region of the image. 148 */ 149 void drawImage(int left, 150 int width, 151 QImage image, 152 int imageLeft, 153 int imageWidth); 154 155 private: 156 QImage m_image; 157 int m_validLeft; 158 int m_validWidth; 159 sv_frame_t m_startFrame; 160 ZoomLevel m_zoomLevel; 161 }; 162 163 #endif 164