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@1030: * A cached image for a view that scrolls horizontally, primarily the 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@1030: m_left(0), Chris@1030: m_width(0), Chris@1030: m_startFrame(0), Chris@1030: m_zoomLevel(0) Chris@1030: {} Chris@1030: Chris@1030: void invalidate() { Chris@1030: m_width = 0; Chris@1030: } Chris@1030: Chris@1030: bool isValid() const { Chris@1030: return m_width > 0; Chris@1030: } Chris@1030: Chris@1030: QSize getSize() const { Chris@1030: return m_image.size(); Chris@1030: } Chris@1030: 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@1030: Chris@1030: int getValidLeft() const { Chris@1030: return m_left; Chris@1030: } Chris@1030: Chris@1030: int getValidWidth() const { Chris@1030: return m_width; Chris@1030: } Chris@1030: Chris@1030: int getValidRight() const { Chris@1030: return m_left + m_width; Chris@1030: } Chris@1030: Chris@1030: QRect getValidArea() const { Chris@1030: return QRect(m_left, 0, m_width, m_image.height()); Chris@1030: } Chris@1030: Chris@1030: int getZoomLevel() const { Chris@1030: return m_zoomLevel; Chris@1030: } Chris@1031: Chris@1031: void setZoomLevel(int zoom) { 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@1030: return m_startFrame; Chris@1030: } Chris@1031: Chris@1031: /** Chris@1031: * Set the start frame and invalidate the cache. To scroll, Chris@1031: * i.e. to set the start frame while retaining cache validity Chris@1031: * where possible, 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@1030: 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@1031: 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@1030: int width, Chris@1030: QImage image, Chris@1030: int imageLeft, Chris@1031: int imageWidth); Chris@1030: Chris@1030: private: Chris@1030: QImage m_image; Chris@1030: int m_left; // of valid region Chris@1030: int m_width; // of valid region Chris@1030: sv_frame_t m_startFrame; Chris@1030: int m_zoomLevel; Chris@1030: }; Chris@1030: Chris@1030: #endif