Chris@1030: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@1030: Chris@1030: /* Chris@1030: Sonic Visualiser Chris@1030: An audio file viewer and annotation editor. Chris@1030: Centre for Digital Music, Queen Mary, University of London. Chris@1030: Chris@1030: This program is free software; you can redistribute it and/or Chris@1030: modify it under the terms of the GNU General Public License as Chris@1030: published by the Free Software Foundation; either version 2 of the Chris@1030: License, or (at your option) any later version. See the file Chris@1030: COPYING included with this distribution for more information. Chris@1030: */ Chris@1030: Chris@1030: #ifndef SCROLLABLE_IMAGE_CACHE_H Chris@1030: #define SCROLLABLE_IMAGE_CACHE_H Chris@1030: Chris@1030: #include "base/BaseTypes.h" Chris@1030: Chris@1077: #include "LayerGeometryProvider.h" Chris@1030: Chris@1030: #include Chris@1030: #include Chris@1030: #include Chris@1030: Chris@1030: /** Chris@1118: * A cached image for a view that scrolls horizontally, such as a Chris@1030: * spectrogram. The cache object holds an image, reports the size of Chris@1030: * the image (likely the same as the underlying view, but it's the Chris@1030: * caller's responsibility to set the size appropriately), can scroll Chris@1030: * the image, and can report and update which contiguous horizontal Chris@1030: * range of the image is valid. Chris@1030: * Chris@1030: * The only way to *update* the valid area in a cache is to draw to it Chris@1030: * using the drawImage call. Chris@1030: */ Chris@1030: class ScrollableImageCache Chris@1030: { Chris@1030: public: Chris@1090: ScrollableImageCache() : Chris@1266: m_validLeft(0), Chris@1266: m_validWidth(0), Chris@1325: m_startFrame(0) Chris@1030: {} Chris@1030: Chris@1030: void invalidate() { Chris@1266: m_validWidth = 0; Chris@1030: } Chris@1030: Chris@1030: bool isValid() const { Chris@1266: return m_validWidth > 0; Chris@1030: } Chris@1030: Chris@1030: QSize getSize() const { Chris@1266: return m_image.size(); Chris@1030: } Chris@1118: Chris@1118: /** Chris@1118: * Set the size of the cache. If the new size differs from the Chris@1118: * current size, the cache is invalidated. Chris@1118: */ Chris@1030: void resize(QSize newSize) { Chris@1079: if (getSize() != newSize) { Chris@1079: m_image = QImage(newSize, QImage::Format_ARGB32_Premultiplied); Chris@1079: invalidate(); Chris@1079: } Chris@1030: } Chris@1266: Chris@1030: int getValidLeft() const { Chris@1266: return m_validLeft; Chris@1030: } Chris@1030: Chris@1030: int getValidWidth() const { Chris@1266: return m_validWidth; Chris@1030: } Chris@1030: Chris@1030: int getValidRight() const { Chris@1266: return m_validLeft + m_validWidth; Chris@1030: } Chris@1030: Chris@1030: QRect getValidArea() const { Chris@1266: return QRect(m_validLeft, 0, m_validWidth, m_image.height()); Chris@1030: } Chris@1030: Chris@1325: ZoomLevel getZoomLevel() const { Chris@1266: return m_zoomLevel; Chris@1030: } Chris@1118: Chris@1118: /** Chris@1118: * Set the zoom level. If the new zoom level differs from the Chris@1118: * current one, the cache is invalidated. (Determining whether to Chris@1118: * invalidate the cache here is the only thing the zoom level is Chris@1118: * used for.) Chris@1118: */ Chris@1325: void setZoomLevel(ZoomLevel zoom) { Chris@1325: using namespace std::rel_ops; Chris@1079: if (m_zoomLevel != zoom) { Chris@1079: m_zoomLevel = zoom; Chris@1079: invalidate(); Chris@1079: } Chris@1031: } Chris@1030: Chris@1030: sv_frame_t getStartFrame() const { Chris@1266: return m_startFrame; Chris@1030: } Chris@1031: Chris@1031: /** Chris@1118: * Set the start frame. If the new start frame differs from the Chris@1118: * current one, the cache is invalidated. To scroll, i.e. to set Chris@1118: * the start frame while retaining cache validity where possible, Chris@1118: * use scrollTo() instead. Chris@1031: */ Chris@1031: void setStartFrame(sv_frame_t frame) { Chris@1079: if (m_startFrame != frame) { Chris@1079: m_startFrame = frame; Chris@1079: invalidate(); Chris@1079: } Chris@1030: } Chris@1030: Chris@1030: const QImage &getImage() const { Chris@1266: return m_image; Chris@1030: } Chris@1030: Chris@1031: /** Chris@1090: * Set the new start frame for the cache, according to the Chris@1090: * geometry of the supplied LayerGeometryProvider, if possible Chris@1090: * also moving along any existing valid data within the cache so Chris@1090: * that it continues to be valid for the new start frame. Chris@1031: */ Chris@1113: void scrollTo(const LayerGeometryProvider *v, sv_frame_t newStartFrame); Chris@1030: Chris@1031: /** Chris@1031: * Take a left coordinate and width describing a region, and Chris@1031: * adjust them so that they are contiguous with the cache valid Chris@1031: * region and so that the union of the adjusted region with the Chris@1081: * cache valid region contains the supplied region. Does not Chris@1081: * modify anything about the cache, only about the arguments. Chris@1031: */ Chris@1031: void adjustToTouchValidArea(int &left, int &width, Chris@1266: bool &isLeftOfValidArea) const; Chris@1081: Chris@1031: /** Chris@1031: * Draw from an image onto the cache. The supplied image must have Chris@1031: * the same height as the cache and the full height is always Chris@1031: * drawn. The left and width parameters determine the target Chris@1031: * region of the cache, the imageLeft and imageWidth parameters Chris@1031: * the source region of the image. Chris@1031: */ Chris@1030: void drawImage(int left, Chris@1266: int width, Chris@1266: QImage image, Chris@1266: int imageLeft, Chris@1266: int imageWidth); Chris@1030: Chris@1030: private: Chris@1030: QImage m_image; Chris@1118: int m_validLeft; Chris@1118: int m_validWidth; Chris@1030: sv_frame_t m_startFrame; Chris@1325: ZoomLevel m_zoomLevel; Chris@1030: }; Chris@1030: Chris@1030: #endif