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
|