File: ViewProxy.h

package info (click to toggle)
sonic-visualiser 5.2.1-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 24,640 kB
  • sloc: cpp: 158,888; ansic: 11,920; sh: 1,785; makefile: 517; xml: 64; perl: 31
file content (284 lines) | stat: -rw-r--r-- 9,994 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.
*/

#ifndef VIEW_PROXY_H
#define VIEW_PROXY_H

#include "layer/LayerGeometryProvider.h"

#include "data/model/AlignmentModel.h"

namespace sv {

class ViewProxy : public LayerGeometryProvider
{
public:
    struct Parameters {
        /**
         * The view for which this is a proxy. The ViewProxy is
         * created on-the-fly to capture the (horizontal) position and
         * zoom of the view and its display scale factor at the time
         * of construction, then used during rendering and discarded.
         */
        View *view;

        /**
         * The centre frame of the view at the time of
         * construction. This is the centre frame that should be used
         * throughout a single render cycle.
         */
        sv_frame_t centreFrame;

        /**
         * The zoom level of the view at the time of
         * construction. This is the zoom level that should be used
         * throughout a single render cycle.
         */
        ZoomLevel zoomLevel;

        /**
         * The display scale factor for the view. This is generally
         * used with pixel-doubled "retina" Mac displays and is
         * usually 1 elsewhere.
         */
        int scaleFactor;

        /**
         * An optional alignment model. If this is supplied,
         * coordinates will be mapped through it, such that frame
         * values passed from the caller are mapped "from reference"
         * by that alignment before being used by the view or
         * converted to pixel coordinates, and returned values are
         * mapped back "to reference" before being passed back to the
         * caller.
         *
         * A proxy using an alignment model may be created specially
         * for rendering a single layer which comes from a different
         * alignment to that of the rest of the containing view.
         */
        ModelId alignmentModelId;
    };
    
    /**
     * Create a standard ViewProxy for the given view, using the given
     * parameters. See the parameter documentation above.
     */
    ViewProxy(Parameters params) :
        m_view(params.view),
        m_centreFrame(params.centreFrame),
        m_rawZoomLevel(params.zoomLevel),
        m_scaleFactor(params.scaleFactor),
        m_alignment(params.alignmentModelId) {
    }
    
    int getId() const override {
        return m_view->getId();
    }
    int getScaleFactor() const override {
        return m_scaleFactor;
    }
    sv_frame_t getStartFrame() const override {
        return getFrameForX(0);
    }
    sv_frame_t getCentreFrame() const override {
        return alignToReference(m_centreFrame);
    }
    sv_frame_t getEndFrame() const override {
        return getFrameForX(getPaintWidth()) - 1;
    }
    int getXForFrame(sv_frame_t frame) const override {
        //!!! not actually correct, if frame lies between view's pixels
        return m_scaleFactor *
            m_view->getXForFrameWith(alignFromReference(frame),
                                     m_centreFrame, m_rawZoomLevel);
    }
    sv_frame_t getFrameForX(int x) const override {
        sv_frame_t f0 = m_view->getFrameForXWith(x / m_scaleFactor,
                                                 m_centreFrame, m_rawZoomLevel);
        if (m_scaleFactor == 1) return alignToReference(f0);
        sv_frame_t f1 = m_view->getFrameForXWith((x / m_scaleFactor) + 1,
                                                 m_centreFrame, m_rawZoomLevel);
        sv_frame_t f = f0 + ((f1 - f0) * (x % m_scaleFactor)) / m_scaleFactor;
        return alignToReference(f);
    }
    int getXForViewX(int viewx) const override {
        return viewx * m_scaleFactor;
    }
    int getViewXForX(int x) const override {
        return x / m_scaleFactor;
    }
    sv_frame_t getModelsStartFrame() const override {
        return alignToReference(m_view->getModelsStartFrame());
    }
    sv_frame_t getModelsEndFrame() const override {
        return alignToReference(m_view->getModelsEndFrame());
    }
    double getYForFrequency(double frequency,
                            double minFreq, double maxFreq, 
                            FrequencyMapping mapping) const override {
        return m_scaleFactor *
            m_view->getYForFrequency(frequency, minFreq, maxFreq, mapping);
    }
    double getFrequencyForY(double y, double minFreq, double maxFreq,
                            FrequencyMapping mapping) const override {
        return m_view->getFrequencyForY
            (y / m_scaleFactor, minFreq, maxFreq, mapping);
    }
    int getTextLabelYCoord(const Layer *layer, QPainter &paint) const override {
        return m_scaleFactor * m_view->getTextLabelYCoord(layer, paint);
    }
    CoordinateScale getEffectiveVerticalExtentsForLayer(const Layer *layer) const override {
        return m_view->getEffectiveVerticalExtentsForLayer(layer);
    }
    CoordinateScale getEffectiveVerticalExtents(QString unit = {}) const override {
        return m_view->getEffectiveVerticalExtents(unit);
    }
    ZoomLevel getRoundedZoomLevel() const override {
        ZoomLevel z = m_rawZoomLevel;
        if (z.zone == ZoomLevel::FramesPerPixel) {
            z.level /= m_scaleFactor;
            if (z.level < 1) {
                z.level = 1;
            }
        } else {
            z.level *= m_scaleFactor;
        }
        return z;
    }
    ZoomLevel getRawZoomLevel() const override {
        return m_rawZoomLevel;
    }
    QRect getPaintRect() const override {
        QRect r = m_view->getPaintRect();
        return QRect(r.x() * m_scaleFactor,
                     r.y() * m_scaleFactor,
                     r.width() * m_scaleFactor,
                     r.height() * m_scaleFactor);
    }
    QSize getPaintSize() const override {
        QSize s = m_view->getPaintSize();
        return QSize(s.width() * m_scaleFactor,
                     s.height() * m_scaleFactor);
    }
    int getPaintWidth() const override {
        return m_view->getPaintWidth() * m_scaleFactor;
    }
    int getPaintHeight() const override { 
        return m_view->getPaintHeight() * m_scaleFactor;
    }
    bool hasLightBackground() const override {
        return m_view->hasLightBackground();
    }
    QColor getForeground() const override {
        return m_view->getForeground();
    }
    QColor getBackground() const override {
        return m_view->getBackground();
    }
    ViewManager *getViewManager() const override {
        return m_view->getViewManager();
    }
        
    bool shouldIlluminateLocalFeatures(const Layer *layer,
                                               QPoint &point) const override {
        QPoint p;
        bool should = m_view->shouldIlluminateLocalFeatures(layer, p);
        point = QPoint(p.x() * m_scaleFactor, p.y() * m_scaleFactor);
        return should;
    }

    bool shouldShowFeatureLabels() const override {
        return m_view->shouldShowFeatureLabels();
    }

    void drawMeasurementRect(QPainter &p, const Layer *layer,
                                     QRect rect, bool focus) const override {
        m_view->drawMeasurementRect(p, layer, rect, focus);
    }

    void updatePaintRect(QRect r) override {
        m_view->updatePaintRect(QRect(r.x() / m_scaleFactor,
                                      r.y() / m_scaleFactor,
                                      r.width() / m_scaleFactor,
                                      r.height() / m_scaleFactor));
    }

    /**
     * Scale up a size in pixels for a hi-dpi display without pixel
     * doubling. This is like ViewManager::scalePixelSize, but taking
     * and returning floating-point values rather than integer
     * pixels. It is also a little more conservative - it never
     * shrinks the size, it can only increase or leave it unchanged.
     */
    double scaleSize(double size) const override {
        return m_view->scaleSize(size * m_scaleFactor);
    }

    /**
     * Integer version of scaleSize.
     */
    int scalePixelSize(int size) const override {
        return m_view->scalePixelSize(size * m_scaleFactor);
    }
    
    /**
     * Scale up pen width for a hi-dpi display without pixel doubling.
     * This is like scaleSize except that it also scales the
     * zero-width case.
     */
    double scalePenWidth(double width) const override {
        if (width <= 0) { // zero-width pen, produce a scaled one-pixel pen
            width = 1;
        }
        width *= sqrt(double(m_scaleFactor));
        return m_view->scalePenWidth(width);
    }

    /**
     * Apply scalePenWidth to a pen.
     */
    QPen scalePen(QPen pen) const override {
        return QPen(pen.color(), scalePenWidth(pen.width()));
    }
    
    View *getView() override { return m_view; }
    const View *getView() const override { return m_view; }

private:
    View *m_view;
    sv_frame_t m_centreFrame;
    ZoomLevel m_rawZoomLevel;
    int m_scaleFactor;
    ModelId m_alignment;

    sv_frame_t alignToReference(sv_frame_t frame) const {
        if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
            return am->toReference(frame);
        } else {
            return frame;
        }
    }

    sv_frame_t alignFromReference(sv_frame_t frame) const {
        if (auto am = ModelById::getAs<AlignmentModel>(m_alignment)) {
            return am->fromReference(frame);
        } else {
            return frame;
        }
    }
};

} // end namespace sv

#endif