annotate view/ViewProxy.h @ 1553:76e4302a3fc2

Fix note numbering - ensure stable across whole track (as it used to be, but without scanning all notes in paint in order to do that)
author Chris Cannam
date Fri, 22 Nov 2019 14:12:50 +0000
parents 4f8c72adbf43
children
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@1537 98 int getTextLabelYCoord(const Layer *layer, QPainter &paint) const override {
Chris@1537 99 return m_scaleFactor * m_view->getTextLabelYCoord(layer, paint);
Chris@919 100 }
Chris@1537 101 bool getVisibleExtentsForUnit(QString unit, double &min, double &max,
Chris@1537 102 bool &log) const override {
Chris@1537 103 return m_view->getVisibleExtentsForUnit(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 if (z.zone == ZoomLevel::FramesPerPixel) {
Chris@1326 108 z.level /= m_scaleFactor;
Chris@1326 109 if (z.level < 1) {
Chris@1326 110 z.level = 1;
Chris@1326 111 }
Chris@1326 112 } else {
Chris@1326 113 z.level *= m_scaleFactor;
Chris@1326 114 }
Chris@1266 115 return z;
Chris@919 116 }
Chris@1406 117 QRect getPaintRect() const override {
Chris@1266 118 QRect r = m_view->getPaintRect();
Chris@1266 119 return QRect(r.x() * m_scaleFactor,
Chris@1266 120 r.y() * m_scaleFactor,
Chris@1266 121 r.width() * m_scaleFactor,
Chris@1266 122 r.height() * m_scaleFactor);
Chris@919 123 }
Chris@1406 124 QSize getPaintSize() const override {
Chris@954 125 return getPaintRect().size();
Chris@954 126 }
Chris@1406 127 int getPaintWidth() const override {
Chris@954 128 return getPaintRect().width();
Chris@954 129 }
Chris@1406 130 int getPaintHeight() const override {
Chris@954 131 return getPaintRect().height();
Chris@954 132 }
Chris@1406 133 bool hasLightBackground() const override {
Chris@1266 134 return m_view->hasLightBackground();
Chris@919 135 }
Chris@1406 136 QColor getForeground() const override {
Chris@1266 137 return m_view->getForeground();
Chris@919 138 }
Chris@1406 139 QColor getBackground() const override {
Chris@1266 140 return m_view->getBackground();
Chris@919 141 }
Chris@1406 142 ViewManager *getViewManager() const override {
Chris@1266 143 return m_view->getViewManager();
Chris@919 144 }
Chris@1266 145
Chris@1406 146 bool shouldIlluminateLocalFeatures(const Layer *layer,
Chris@1406 147 QPoint &point) const override {
Chris@954 148 QPoint p;
Chris@1266 149 bool should = m_view->shouldIlluminateLocalFeatures(layer, p);
Chris@954 150 point = QPoint(p.x() * m_scaleFactor, p.y() * m_scaleFactor);
Chris@954 151 return should;
Chris@919 152 }
Chris@954 153
Chris@1406 154 bool shouldShowFeatureLabels() const override {
Chris@1266 155 return m_view->shouldShowFeatureLabels();
Chris@919 156 }
Chris@919 157
Chris@1406 158 void drawMeasurementRect(QPainter &p, const Layer *layer,
Chris@1406 159 QRect rect, bool focus) const override {
Chris@1266 160 m_view->drawMeasurementRect(p, layer, rect, focus);
Chris@919 161 }
Chris@919 162
Chris@1406 163 void updatePaintRect(QRect r) override {
Chris@1030 164 m_view->update(r.x() / m_scaleFactor,
Chris@1030 165 r.y() / m_scaleFactor,
Chris@1030 166 r.width() / m_scaleFactor,
Chris@1030 167 r.height() / m_scaleFactor);
Chris@1030 168 }
Chris@1401 169
Chris@1401 170 /**
Chris@1401 171 * Scale up a size in pixels for a hi-dpi display without pixel
Chris@1401 172 * doubling. This is like ViewManager::scalePixelSize, but taking
Chris@1401 173 * and returning floating-point values rather than integer
Chris@1401 174 * pixels. It is also a little more conservative - it never
Chris@1401 175 * shrinks the size, it can only increase or leave it unchanged.
Chris@1401 176 */
Chris@1406 177 double scaleSize(double size) const override {
Chris@1401 178 return m_view->scaleSize(size * m_scaleFactor);
Chris@1401 179 }
Chris@1401 180
Chris@1401 181 /**
Chris@1402 182 * Integer version of scaleSize.
Chris@1402 183 */
Chris@1406 184 int scalePixelSize(int size) const override {
Chris@1402 185 return m_view->scalePixelSize(size * m_scaleFactor);
Chris@1402 186 }
Chris@1402 187
Chris@1402 188 /**
Chris@1401 189 * Scale up pen width for a hi-dpi display without pixel doubling.
Chris@1401 190 * This is like scaleSize except that it also scales the
Chris@1401 191 * zero-width case.
Chris@1401 192 */
Chris@1406 193 double scalePenWidth(double width) const override {
Chris@1401 194 if (width <= 0) { // zero-width pen, produce a scaled one-pixel pen
Chris@1401 195 width = 1;
Chris@1401 196 }
Chris@1401 197 width *= sqrt(double(m_scaleFactor));
Chris@1401 198 return m_view->scalePenWidth(width);
Chris@1401 199 }
Chris@1401 200
Chris@1401 201 /**
Chris@1401 202 * Apply scalePenWidth to a pen.
Chris@1401 203 */
Chris@1406 204 QPen scalePen(QPen pen) const override {
Chris@1401 205 return QPen(pen.color(), scalePenWidth(pen.width()));
Chris@1401 206 }
Chris@1030 207
Chris@1406 208 View *getView() override { return m_view; }
Chris@1406 209 const View *getView() const override { return m_view; }
Chris@919 210
Chris@919 211 private:
Chris@919 212 View *m_view;
Chris@919 213 int m_scaleFactor;
Chris@1490 214 ModelId m_alignment;
Chris@1490 215
Chris@1490 216 sv_frame_t alignToReference(sv_frame_t frame) const {
Chris@1490 217 if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
Chris@1490 218 return am->toReference(frame);
Chris@1490 219 } else {
Chris@1490 220 return frame;
Chris@1490 221 }
Chris@1490 222 }
Chris@1490 223
Chris@1490 224 sv_frame_t alignFromReference(sv_frame_t frame) const {
Chris@1490 225 if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
Chris@1490 226 return am->fromReference(frame);
Chris@1490 227 } else {
Chris@1490 228 return frame;
Chris@1490 229 }
Chris@1490 230 }
Chris@919 231 };
Chris@919 232
Chris@919 233 #endif