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
|