annotate view/ViewProxy.h @ 1546:ec837d223bd9

Update getPointToDrag to prefer boxes that are containing the mouse position in height as well as width
author Chris Cannam
date Thu, 17 Oct 2019 10:26:21 +0100
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