annotate layer/ScrollableImageCache.cpp @ 1605:ae2d5f8ff005

When asked to render the whole view width, we need to wait for the layers to be ready before we can determine what the width is
author Chris Cannam
date Thu, 30 Apr 2020 14:47:13 +0100
parents a34a2a25907c
children
rev   line source
Chris@1033 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1033 2
Chris@1033 3 /*
Chris@1033 4 Sonic Visualiser
Chris@1033 5 An audio file viewer and annotation editor.
Chris@1033 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1033 7
Chris@1033 8 This program is free software; you can redistribute it and/or
Chris@1033 9 modify it under the terms of the GNU General Public License as
Chris@1033 10 published by the Free Software Foundation; either version 2 of the
Chris@1033 11 License, or (at your option) any later version. See the file
Chris@1033 12 COPYING included with this distribution for more information.
Chris@1033 13 */
Chris@1033 14
Chris@1033 15 #include "ScrollableImageCache.h"
Chris@1033 16
Chris@1164 17 #include "base/HitCount.h"
Chris@1164 18
Chris@1033 19 #include <iostream>
Chris@1033 20 using namespace std;
Chris@1033 21
Chris@1143 22 //#define DEBUG_SCROLLABLE_IMAGE_CACHE 1
Chris@1033 23
Chris@1033 24 void
Chris@1113 25 ScrollableImageCache::scrollTo(const LayerGeometryProvider *v,
Chris@1113 26 sv_frame_t newStartFrame)
Chris@1033 27 {
Chris@1164 28 static HitCount count("ScrollableImageCache: scrolling");
Chris@1164 29
Chris@1122 30 int dx = (v->getXForFrame(m_startFrame) -
Chris@1266 31 v->getXForFrame(newStartFrame));
Chris@1122 32
Chris@1122 33 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1122 34 cerr << "ScrollableImageCache::scrollTo: start frame " << m_startFrame
Chris@1266 35 << " -> " << newStartFrame << ", dx = " << dx << endl;
Chris@1122 36 #endif
Chris@1122 37
Chris@1079 38 if (m_startFrame == newStartFrame) {
Chris@1266 39 // haven't moved
Chris@1164 40 count.hit();
Chris@1079 41 return;
Chris@1079 42 }
Chris@1266 43
Chris@1033 44 m_startFrame = newStartFrame;
Chris@1266 45
Chris@1033 46 if (!isValid()) {
Chris@1164 47 count.miss();
Chris@1266 48 return;
Chris@1033 49 }
Chris@1033 50
Chris@1033 51 int w = m_image.width();
Chris@1033 52
Chris@1033 53 if (dx == 0) {
Chris@1266 54 // haven't moved visibly (even though start frame may have changed)
Chris@1164 55 count.hit();
Chris@1266 56 return;
Chris@1033 57 }
Chris@1033 58
Chris@1033 59 if (dx <= -w || dx >= w) {
Chris@1266 60 // scrolled entirely off
Chris@1266 61 invalidate();
Chris@1164 62 count.miss();
Chris@1266 63 return;
Chris@1033 64 }
Chris@1164 65
Chris@1164 66 count.partial();
Chris@1266 67
Chris@1033 68 // dx is in range, cache is scrollable
Chris@1033 69
Chris@1033 70 int dxp = dx;
Chris@1033 71 if (dxp < 0) dxp = -dxp;
Chris@1033 72
Chris@1033 73 int copylen = (w - dxp) * int(sizeof(QRgb));
Chris@1033 74 for (int y = 0; y < m_image.height(); ++y) {
Chris@1266 75 QRgb *line = (QRgb *)m_image.scanLine(y);
Chris@1266 76 if (dx < 0) {
Chris@1266 77 memmove(line, line + dxp, copylen);
Chris@1266 78 } else {
Chris@1266 79 memmove(line + dxp, line, copylen);
Chris@1266 80 }
Chris@1033 81 }
Chris@1266 82
Chris@1033 83 // update valid area
Chris@1033 84
Chris@1118 85 int px = m_validLeft;
Chris@1118 86 int pw = m_validWidth;
Chris@1266 87
Chris@1033 88 px += dx;
Chris@1266 89
Chris@1033 90 if (dx < 0) {
Chris@1266 91 // we scrolled left
Chris@1266 92 if (px < 0) {
Chris@1266 93 pw += px;
Chris@1266 94 px = 0;
Chris@1266 95 if (pw < 0) {
Chris@1266 96 pw = 0;
Chris@1266 97 }
Chris@1266 98 }
Chris@1033 99 } else {
Chris@1266 100 // we scrolled right
Chris@1266 101 if (px + pw > w) {
Chris@1266 102 pw = w - px;
Chris@1266 103 if (pw < 0) {
Chris@1266 104 pw = 0;
Chris@1266 105 }
Chris@1266 106 }
Chris@1033 107 }
Chris@1033 108
Chris@1118 109 m_validLeft = px;
Chris@1118 110 m_validWidth = pw;
Chris@1033 111 }
Chris@1033 112
Chris@1033 113 void
Chris@1033 114 ScrollableImageCache::adjustToTouchValidArea(int &left, int &width,
Chris@1266 115 bool &isLeftOfValidArea) const
Chris@1033 116 {
Chris@1036 117 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 118 cerr << "ScrollableImageCache::adjustToTouchValidArea: left " << left
Chris@1036 119 << ", width " << width << endl;
Chris@1118 120 cerr << "ScrollableImageCache: my left " << m_validLeft
Chris@1118 121 << ", width " << m_validWidth << " so right " << (m_validLeft + m_validWidth) << endl;
Chris@1036 122 #endif
Chris@1118 123 if (left < m_validLeft) {
Chris@1266 124 isLeftOfValidArea = true;
Chris@1266 125 if (left + width <= m_validLeft + m_validWidth) {
Chris@1266 126 width = m_validLeft - left;
Chris@1266 127 }
Chris@1036 128 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 129 cerr << "ScrollableImageCache: we're left of valid area, adjusted width to " << width << endl;
Chris@1036 130 #endif
Chris@1033 131 } else {
Chris@1266 132 isLeftOfValidArea = false;
Chris@1266 133 width = left + width - (m_validLeft + m_validWidth);
Chris@1266 134 left = m_validLeft + m_validWidth;
Chris@1266 135 if (width < 0) width = 0;
Chris@1036 136 #ifdef DEBUG_SCROLLABLE_IMAGE_CACHE
Chris@1036 137 cerr << "ScrollableImageCache: we're right of valid area, adjusted left to " << left << ", width to " << width << endl;
Chris@1036 138 #endif
Chris@1033 139 }
Chris@1033 140 }
Chris@1033 141
Chris@1033 142 void
Chris@1033 143 ScrollableImageCache::drawImage(int left,
Chris@1266 144 int width,
Chris@1266 145 QImage image,
Chris@1266 146 int imageLeft,
Chris@1266 147 int imageWidth)
Chris@1033 148 {
Chris@1033 149 if (image.height() != m_image.height()) {
Chris@1266 150 cerr << "ScrollableImageCache::drawImage: ERROR: Supplied image height "
Chris@1266 151 << image.height() << " does not match cache height "
Chris@1266 152 << m_image.height() << endl;
Chris@1266 153 throw std::logic_error("Image height must match cache height in ScrollableImageCache::drawImage");
Chris@1033 154 }
Chris@1033 155 if (left < 0 || width < 0 || left + width > m_image.width()) {
Chris@1266 156 cerr << "ScrollableImageCache::drawImage: ERROR: Target area (left = "
Chris@1266 157 << left << ", width = " << width << ", so right = " << left + width
Chris@1040 158 << ") out of bounds for cache of width " << m_image.width() << endl;
Chris@1266 159 throw std::logic_error("Target area out of bounds in ScrollableImageCache::drawImage");
Chris@1033 160 }
Chris@1033 161 if (imageLeft < 0 || imageWidth < 0 ||
Chris@1266 162 imageLeft + imageWidth > image.width()) {
Chris@1266 163 cerr << "ScrollableImageCache::drawImage: ERROR: Source area (left = "
Chris@1266 164 << imageLeft << ", width = " << imageWidth << ", so right = "
Chris@1040 165 << imageLeft + imageWidth << ") out of bounds for image of "
Chris@1266 166 << "width " << image.width() << endl;
Chris@1266 167 throw std::logic_error("Source area out of bounds in ScrollableImageCache::drawImage");
Chris@1033 168 }
Chris@1266 169
Chris@1033 170 QPainter painter(&m_image);
Chris@1033 171 painter.drawImage(QRect(left, 0, width, m_image.height()),
Chris@1266 172 image,
Chris@1266 173 QRect(imageLeft, 0, imageWidth, image.height()));
Chris@1033 174 painter.end();
Chris@1033 175
Chris@1033 176 if (!isValid()) {
Chris@1266 177 m_validLeft = left;
Chris@1266 178 m_validWidth = width;
Chris@1266 179 return;
Chris@1033 180 }
Chris@1266 181
Chris@1118 182 if (left < m_validLeft) {
Chris@1266 183 if (left + width > m_validLeft + m_validWidth) {
Chris@1266 184 // new image completely contains the old valid area --
Chris@1266 185 // use the new area as is
Chris@1266 186 m_validLeft = left;
Chris@1266 187 m_validWidth = width;
Chris@1266 188 } else if (left + width < m_validLeft) {
Chris@1266 189 // new image completely off left of old valid area --
Chris@1266 190 // we can't extend the valid area because the bit in
Chris@1266 191 // between is not valid, so must use the new area only
Chris@1266 192 m_validLeft = left;
Chris@1266 193 m_validWidth = width;
Chris@1266 194 } else {
Chris@1266 195 // new image overlaps old valid area on left side --
Chris@1266 196 // use new left edge, and extend width to existing
Chris@1266 197 // right edge
Chris@1266 198 m_validWidth = (m_validLeft + m_validWidth) - left;
Chris@1266 199 m_validLeft = left;
Chris@1266 200 }
Chris@1033 201 } else {
Chris@1266 202 if (left > m_validLeft + m_validWidth) {
Chris@1266 203 // new image completely off right of old valid area --
Chris@1266 204 // we can't extend the valid area because the bit in
Chris@1266 205 // between is not valid, so must use the new area only
Chris@1266 206 m_validLeft = left;
Chris@1266 207 m_validWidth = width;
Chris@1266 208 } else if (left + width > m_validLeft + m_validWidth) {
Chris@1266 209 // new image overlaps old valid area on right side --
Chris@1266 210 // use existing left edge, and extend width to new
Chris@1266 211 // right edge
Chris@1266 212 m_validWidth = (left + width) - m_validLeft;
Chris@1266 213 // (m_validLeft unchanged)
Chris@1266 214 } else {
Chris@1266 215 // new image completely contained within old valid
Chris@1266 216 // area -- leave the old area unchanged
Chris@1266 217 }
Chris@1033 218 }
Chris@1033 219 }
Chris@1033 220