annotate view/ViewProxy.h @ 1523:1ccb64bfb22b

Make the waveform layer do the expected thing when MergeChannels mode (i.e. butterfly mode) is enabled even if there is only 1 channel. This combination isn't actually available in the UI for SV, but it's useful for Sonic Lineup.
author Chris Cannam
date Wed, 25 Sep 2019 13:42:17 +0100
parents 2f505d843d14
children 4f8c72adbf43
rev   line source
Chris@919 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@919 2
Chris@919 3 /*
Chris@919 4 Sonic Visualiser
Chris@919 5 An audio file viewer and annotation editor.
Chris@919 6 Centre for Digital Music, Queen Mary, University of London.
Chris@919 7
Chris@919 8 This program is free software; you can redistribute it and/or
Chris@919 9 modify it under the terms of the GNU General Public License as
Chris@919 10 published by the Free Software Foundation; either version 2 of the
Chris@919 11 License, or (at your option) any later version. See the file
Chris@919 12 COPYING included with this distribution for more information.
Chris@919 13 */
Chris@919 14
Chris@919 15 #ifndef VIEW_PROXY_H
Chris@919 16 #define VIEW_PROXY_H
Chris@919 17
Chris@1077 18 #include "layer/LayerGeometryProvider.h"
Chris@919 19
Chris@1490 20 #include "data/model/AlignmentModel.h"
Chris@1490 21
Chris@919 22 class ViewProxy : public LayerGeometryProvider
Chris@919 23 {
Chris@919 24 public:
Chris@1490 25 /**
Chris@1490 26 * Create a standard ViewProxy for the given view, mapping using
Chris@1490 27 * the given scale factor. The scale factor is generally used with
Chris@1490 28 * pixel-doubled "retina" Mac displays and is usually 1 elsewhere.
Chris@1490 29 */
Chris@919 30 ViewProxy(View *view, int scaleFactor) :
Chris@1266 31 m_view(view), m_scaleFactor(scaleFactor) { }
Chris@919 32
Chris@1490 33 /**
Chris@1490 34 * Create a re-aligning ViewProxy for the given view, mapping
Chris@1490 35 * using the given scale factor. The scale factor is generally
Chris@1490 36 * used with pixel-doubled "retina" Mac displays and is usually 1
Chris@1490 37 * elsewhere.
Chris@1490 38 *
Chris@1490 39 * Coordinates are mapped through the given alignment model, such
Chris@1490 40 * that frame values passed from the caller are mapped "from
Chris@1490 41 * reference" by that alignment before being used by the view or
Chris@1490 42 * converted to pixel coordinates, and returned values are mapped
Chris@1490 43 * back "to reference" before being passed back to the caller.
Chris@1490 44 *
Chris@1490 45 * This form of proxy may be created specially for rendering a
Chris@1490 46 * single layer which comes from a different alignment to that of
Chris@1490 47 * the rest of the containing view.
Chris@1490 48 */
Chris@1490 49 ViewProxy(View *view, int scaleFactor, ModelId alignment) :
Chris@1490 50 m_view(view), m_scaleFactor(scaleFactor), m_alignment(alignment) { }
Chris@1490 51
Chris@1406 52 int getId() const override {
Chris@1044 53 return m_view->getId();
Chris@1044 54 }
Chris@1406 55 sv_frame_t getStartFrame() const override {
Chris@1490 56 return alignToReference(m_view->getStartFrame());
Chris@919 57 }
Chris@1406 58 sv_frame_t getCentreFrame() const override {
Chris@1490 59 return alignToReference(m_view->getCentreFrame());
Chris@919 60 }
Chris@1406 61 sv_frame_t getEndFrame() const override {
Chris@1490 62 return alignToReference(m_view->getEndFrame());
Chris@919 63 }
Chris@1406 64 int getXForFrame(sv_frame_t frame) const override {
Chris@950 65 //!!! not actually correct, if frame lies between view's pixels
Chris@1490 66 return m_scaleFactor * m_view->getXForFrame(alignFromReference(frame));
Chris@919 67 }
Chris@1406 68 sv_frame_t getFrameForX(int x) const override {
Chris@950 69 sv_frame_t f0 = m_view->getFrameForX(x / m_scaleFactor);
Chris@1491 70 if (m_scaleFactor == 1) return alignToReference(f0);
Chris@950 71 sv_frame_t f1 = m_view->getFrameForX((x / m_scaleFactor) + 1);
Chris@1490 72 sv_frame_t f = f0 + ((f1 - f0) * (x % m_scaleFactor)) / m_scaleFactor;
Chris@1490 73 return alignToReference(f);
Chris@919 74 }
Chris@1406 75 int getXForViewX(int viewx) const override {
Chris@1030 76 return viewx * m_scaleFactor;
Chris@1030 77 }
Chris@1406 78 int getViewXForX(int x) const override {
Chris@1030 79 return x / m_scaleFactor;
Chris@1030 80 }
Chris@1406 81 sv_frame_t getModelsStartFrame() const override {
Chris@1490 82 return alignToReference(m_view->getModelsStartFrame());
Chris@919 83 }
Chris@1406 84 sv_frame_t getModelsEndFrame() const override {
Chris@1490 85 return alignToReference(m_view->getModelsEndFrame());
Chris@919 86 }
Chris@1406 87 double getYForFrequency(double frequency,
Chris@1266 88 double minFreq, double maxFreq,
Chris@1406 89 bool logarithmic) const override {
Chris@1266 90 return m_scaleFactor *
Chris@1266 91 m_view->getYForFrequency(frequency, minFreq, maxFreq, logarithmic);
Chris@919 92 }
Chris@1406 93 double getFrequencyForY(double y, double minFreq, double maxFreq,
Chris@1406 94 bool logarithmic) const override {
Chris@1085 95 return m_view->getFrequencyForY
Chris@950 96 (y / m_scaleFactor, minFreq, maxFreq, logarithmic);
Chris@919 97 }
Chris@1406 98 int getTextLabelHeight(const Layer *layer, QPainter &paint) const override {
Chris@1266 99 return m_scaleFactor * m_view->getTextLabelHeight(layer, paint);
Chris@919 100 }
Chris@1406 101 bool getValueExtents(QString unit, double &min, double &max,
Chris@1406 102 bool &log) const override {
Chris@1266 103 return m_view->getValueExtents(unit, min, max, log);
Chris@919 104 }
Chris@1406 105 ZoomLevel getZoomLevel() const override {
Chris@1326 106 ZoomLevel z = m_view->getZoomLevel();
Chris@1326 107 //!!!
Chris@1329 108 // cerr << "getZoomLevel: from " << z << " to ";
Chris@1326 109 if (z.zone == ZoomLevel::FramesPerPixel) {
Chris@1326 110 z.level /= m_scaleFactor;
Chris@1326 111 if (z.level < 1) {
Chris@1326 112 z.level = 1;
Chris@1326 113 }
Chris@1326 114 } else {
Chris@1326 115 //!!!???
Chris@1326 116 z.level *= m_scaleFactor;
Chris@1326 117 }
Chris@1329 118 // cerr << z << endl;
Chris@1266 119 return z;
Chris@919 120 }
Chris@1406 121 QRect getPaintRect() const override {
Chris@1266 122 QRect r = m_view->getPaintRect();
Chris@1266 123 return QRect(r.x() * m_scaleFactor,
Chris@1266 124 r.y() * m_scaleFactor,
Chris@1266 125 r.width() * m_scaleFactor,
Chris@1266 126 r.height() * m_scaleFactor);
Chris@919 127 }
Chris@1406 128 QSize getPaintSize() const override {
Chris@954 129 return getPaintRect().size();
Chris@954 130 }
Chris@1406 131 int getPaintWidth() const override {
Chris@954 132 return getPaintRect().width();
Chris@954 133 }
Chris@1406 134 int getPaintHeight() const override {
Chris@954 135 return getPaintRect().height();
Chris@954 136 }
Chris@1406 137 bool hasLightBackground() const override {
Chris@1266 138 return m_view->hasLightBackground();
Chris@919 139 }
Chris@1406 140 QColor getForeground() const override {
Chris@1266 141 return m_view->getForeground();
Chris@919 142 }
Chris@1406 143 QColor getBackground() const override {
Chris@1266 144 return m_view->getBackground();
Chris@919 145 }
Chris@1406 146 ViewManager *getViewManager() const override {
Chris@1266 147 return m_view->getViewManager();
Chris@919 148 }
Chris@1266 149
Chris@1406 150 bool shouldIlluminateLocalFeatures(const Layer *layer,
Chris@1406 151 QPoint &point) const override {
Chris@954 152 QPoint p;
Chris@1266 153 bool should = m_view->shouldIlluminateLocalFeatures(layer, p);
Chris@954 154 point = QPoint(p.x() * m_scaleFactor, p.y() * m_scaleFactor);
Chris@954 155 return should;
Chris@919 156 }
Chris@954 157
Chris@1406 158 bool shouldShowFeatureLabels() const override {
Chris@1266 159 return m_view->shouldShowFeatureLabels();
Chris@919 160 }
Chris@919 161
Chris@1406 162 void drawMeasurementRect(QPainter &p, const Layer *layer,
Chris@1406 163 QRect rect, bool focus) const override {
Chris@1266 164 m_view->drawMeasurementRect(p, layer, rect, focus);
Chris@919 165 }
Chris@919 166
Chris@1406 167 void updatePaintRect(QRect r) override {
Chris@1030 168 m_view->update(r.x() / m_scaleFactor,
Chris@1030 169 r.y() / m_scaleFactor,
Chris@1030 170 r.width() / m_scaleFactor,
Chris@1030 171 r.height() / m_scaleFactor);
Chris@1030 172 }
Chris@1401 173
Chris@1401 174 /**
Chris@1401 175 * Scale up a size in pixels for a hi-dpi display without pixel
Chris@1401 176 * doubling. This is like ViewManager::scalePixelSize, but taking
Chris@1401 177 * and returning floating-point values rather than integer
Chris@1401 178 * pixels. It is also a little more conservative - it never
Chris@1401 179 * shrinks the size, it can only increase or leave it unchanged.
Chris@1401 180 */
Chris@1406 181 double scaleSize(double size) const override {
Chris@1401 182 return m_view->scaleSize(size * m_scaleFactor);
Chris@1401 183 }
Chris@1401 184
Chris@1401 185 /**
Chris@1402 186 * Integer version of scaleSize.
Chris@1402 187 */
Chris@1406 188 int scalePixelSize(int size) const override {
Chris@1402 189 return m_view->scalePixelSize(size * m_scaleFactor);
Chris@1402 190 }
Chris@1402 191
Chris@1402 192 /**
Chris@1401 193 * Scale up pen width for a hi-dpi display without pixel doubling.
Chris@1401 194 * This is like scaleSize except that it also scales the
Chris@1401 195 * zero-width case.
Chris@1401 196 */
Chris@1406 197 double scalePenWidth(double width) const override {
Chris@1401 198 if (width <= 0) { // zero-width pen, produce a scaled one-pixel pen
Chris@1401 199 width = 1;
Chris@1401 200 }
Chris@1401 201 width *= sqrt(double(m_scaleFactor));
Chris@1401 202 return m_view->scalePenWidth(width);
Chris@1401 203 }
Chris@1401 204
Chris@1401 205 /**
Chris@1401 206 * Apply scalePenWidth to a pen.
Chris@1401 207 */
Chris@1406 208 QPen scalePen(QPen pen) const override {
Chris@1401 209 return QPen(pen.color(), scalePenWidth(pen.width()));
Chris@1401 210 }
Chris@1030 211
Chris@1406 212 View *getView() override { return m_view; }
Chris@1406 213 const View *getView() const override { return m_view; }
Chris@919 214
Chris@919 215 private:
Chris@919 216 View *m_view;
Chris@919 217 int m_scaleFactor;
Chris@1490 218 ModelId m_alignment;
Chris@1490 219
Chris@1490 220 sv_frame_t alignToReference(sv_frame_t frame) const {
Chris@1490 221 if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
Chris@1490 222 return am->toReference(frame);
Chris@1490 223 } else {
Chris@1490 224 return frame;
Chris@1490 225 }
Chris@1490 226 }
Chris@1490 227
Chris@1490 228 sv_frame_t alignFromReference(sv_frame_t frame) const {
Chris@1490 229 if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
Chris@1490 230 return am->fromReference(frame);
Chris@1490 231 } else {
Chris@1490 232 return frame;
Chris@1490 233 }
Chris@1490 234 }
Chris@919 235 };
Chris@919 236
Chris@919 237 #endif