changeset 1547:e6362cf5ff1d

Pass a y-coord, optionally, to Layer::snapToFeatureFrame. This is necessary for BoxLayer which needs to coordinate its snaps with the box it is highlighting for editing. Then in BoxLayer, merge getPointToDrag and getLocalPoints into a single getLocalPoint and use this throughout.
author Chris Cannam
date Thu, 17 Oct 2019 11:12:54 +0100
parents ec837d223bd9
children bd6af89982d7
files layer/BoxLayer.cpp layer/BoxLayer.h layer/Colour3DPlotLayer.cpp layer/Colour3DPlotLayer.h layer/FlexiNoteLayer.cpp layer/FlexiNoteLayer.h layer/ImageLayer.cpp layer/ImageLayer.h layer/Layer.h layer/NoteLayer.cpp layer/NoteLayer.h layer/RegionLayer.cpp layer/RegionLayer.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/TextLayer.cpp layer/TextLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeRulerLayer.cpp layer/TimeRulerLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h view/Pane.cpp
diffstat 24 files changed, 125 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/layer/BoxLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/BoxLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -239,36 +239,12 @@
     }
 }
 
-EventVector
-BoxLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
+bool
+BoxLayer::getLocalPoint(LayerGeometryProvider *v, int x, int y,
+                        Event &point) const
 {
     auto model = ModelById::getAs<BoxModel>(m_model);
-    if (!model) return EventVector();
-
-    sv_frame_t frame = v->getFrameForX(x);
-
-    EventVector local = model->getEventsCovering(frame);
-    if (!local.empty()) return local;
-
-    int fuzz = ViewManager::scalePixelSize(2);
-    sv_frame_t start = v->getFrameForX(x - fuzz);
-    sv_frame_t end = v->getFrameForX(x + fuzz);
-
-    local = model->getEventsStartingWithin(frame, end - frame);
-    if (!local.empty()) return local;
-
-    local = model->getEventsSpanning(start, frame - start);
-    if (!local.empty()) return local;
-
-    return {};
-}
-
-bool
-BoxLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y,
-                         Event &point) const
-{
-    auto model = ModelById::getAs<BoxModel>(m_model);
-    if (!model) return false;
+    if (!model || !model->isReady()) return false;
 
     sv_frame_t frame = v->getFrameForX(x);
 
@@ -308,9 +284,10 @@
     } else {
         int nearestDistance = -1;
         for (const auto &p: onPoints) {
+            const auto r = getRange(p);
             int distance = std::min
-                (getYForValue(v, p.getValue()) - y,
-                 getYForValue(v, p.getValue() + fabsf(p.getLevel())) - y);
+                (getYForValue(v, r.first) - y,
+                 getYForValue(v, r.second) - y);
             if (distance < 0) distance = -distance;
             if (nearestDistance == -1 || distance < nearestDistance) {
                 nearestDistance = distance;
@@ -343,14 +320,12 @@
 BoxLayer::getFeatureDescription(LayerGeometryProvider *v,
                                 QPoint &pos) const
 {
-    int x = pos.x();
-
     auto model = ModelById::getAs<BoxModel>(m_model);
     if (!model || !model->getSampleRate()) return "";
-
-    EventVector points = getLocalPoints(v, x);
-
-    if (points.empty()) {
+    
+    Event box;
+    
+    if (!getLocalPoint(v, pos.x(), pos.y(), box)) {
         if (!model->isReady()) {
             return tr("In progress");
         } else {
@@ -358,32 +333,17 @@
         }
     }
 
-    Event box;
-    EventVector::iterator i;
-
-    for (i = points.begin(); i != points.end(); ++i) {
-
-        int y0 = getYForValue(v, i->getValue());
-        int y1 = getYForValue(v, i->getValue() + fabsf(i->getLevel()));
-
-        if (pos.y() >= y0 && pos.y() <= y1) {
-            box = *i;
-            break;
-        }
-    }
-
-    if (i == points.end()) return tr("No local points");
-
     RealTime rt = RealTime::frame2RealTime(box.getFrame(),
                                            model->getSampleRate());
     RealTime rd = RealTime::frame2RealTime(box.getDuration(),
                                            model->getSampleRate());
     
     QString rangeText;
-
+    auto r = getRange(box);
+    
     rangeText = tr("%1 %2 - %3 %4")
-        .arg(box.getValue()).arg(getScaleUnits())
-        .arg(box.getValue() + fabsf(box.getLevel())).arg(getScaleUnits());
+        .arg(r.first).arg(getScaleUnits())
+        .arg(r.second).arg(getScaleUnits());
 
     QString text;
 
@@ -409,11 +369,12 @@
 BoxLayer::snapToFeatureFrame(LayerGeometryProvider *v,
                              sv_frame_t &frame,
                              int &resolution,
-                             SnapType snap) const
+                             SnapType snap,
+                             int ycoord) const
 {
     auto model = ModelById::getAs<BoxModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
@@ -425,57 +386,52 @@
 
     resolution = model->getResolution();
 
+    Event containing;
+
+    if (getLocalPoint(v, v->getXForFrame(frame), ycoord, containing)) {
+
+        switch (snap) {
+
+        case SnapLeft:
+        case SnapNeighbouring:
+            frame = containing.getFrame();
+            return true;
+
+        case SnapRight:
+            frame = containing.getFrame() + containing.getDuration();
+            return true;
+        }
+    }
+    
     if (snap == SnapNeighbouring) {
-        EventVector points = getLocalPoints(v, v->getXForFrame(frame));
-        if (points.empty()) return false;
-        frame = points.begin()->getFrame();
-        return true;
+        return false;
     }    
 
-    // Normally we snap to the start frame of whichever event we
-    // find. However here, for SnapRight only, if the end frame of
-    // whichever event we would have snapped to had we been snapping
-    // left is closer than the start frame of the next event to the
-    // right, then we snap to that frame instead. Clear?
+    // We aren't actually contained (in time) by any single event, so
+    // seek the next one in the relevant direction
+
+    Event e;
     
-    Event left;
-    bool haveLeft = false;
-    if (model->getNearestEventMatching
-        (frame, [](Event) { return true; }, EventSeries::Backward, left)) {
-        haveLeft = true;
-    }
+    if (snap == SnapLeft) {
+        if (model->getNearestEventMatching
+            (frame, [](Event) { return true; }, EventSeries::Backward, e)) {
 
-    if (snap == SnapLeft) {
-        frame = left.getFrame();
-        return haveLeft;
-    }
-
-    Event right;
-    bool haveRight = false;
-    if (model->getNearestEventMatching
-        (frame, [](Event) { return true; }, EventSeries::Forward, right)) {
-        haveRight = true;
-    }
-
-    if (haveLeft) {
-        sv_frame_t leftEnd = left.getFrame() + left.getDuration();
-        if (leftEnd > frame) {
-            if (haveRight) {
-                if (leftEnd - frame < right.getFrame() - frame) {
-                    frame = leftEnd;
-                } else {
-                    frame = right.getFrame();
-                }
+            if (e.getFrame() + e.getDuration() < frame) {
+                frame = e.getFrame() + e.getDuration();
             } else {
-                frame = leftEnd;
+                frame = e.getFrame();
             }
             return true;
         }
     }
+    
+    if (snap == SnapRight) {
+        if (model->getNearestEventMatching
+            (frame, [](Event) { return true; }, EventSeries::Forward, e)) {
 
-    if (haveRight) {
-        frame = right.getFrame();
-        return true;
+            frame = e.getFrame();
+            return true;
+        }
     }
 
     return false;
@@ -607,8 +563,8 @@
     bool shouldIlluminate = false;
 
     if (v->shouldIlluminateLocalFeatures(this, localPos)) {
-        shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
-                                          illuminatePoint);
+        shouldIlluminate = getLocalPoint(v, localPos.x(), localPos.y(),
+                                         illuminatePoint);
     }
 
     paint.save();
@@ -620,11 +576,12 @@
          i != points.end(); ++i) {
 
         const Event &p(*i);
+        const auto r = getRange(p);
 
         int x = v->getXForFrame(p.getFrame());
         int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
-        int y = getYForValue(v, p.getValue());
-        int h = getYForValue(v, p.getValue() + fabsf(p.getLevel())) - y;
+        int y = getYForValue(v, r.first);
+        int h = getYForValue(v, r.second) - y;
         int ex = x + w;
         int gap = v->scalePixelSize(2);
 
@@ -655,11 +612,11 @@
             if (abs(h) > 2 * fm.height()) {
             
                 QString y0label = QString("%1 %2")
-                    .arg(p.getValue())
+                    .arg(r.first)
                     .arg(getScaleUnits());
 
                 QString y1label = QString("%1 %2")
-                    .arg(p.getValue() + fabsf(p.getLevel()))
+                    .arg(r.second)
                     .arg(getScaleUnits());
 
                 PaintAssistant::drawVisibleText
@@ -677,9 +634,9 @@
             } else {
             
                 QString ylabel = QString("%1 %2 - %3 %4")
-                    .arg(p.getValue())
+                    .arg(r.first)
                     .arg(getScaleUnits())
-                    .arg(p.getValue() + fabsf(p.getLevel()))
+                    .arg(r.second)
                     .arg(getScaleUnits());
 
                 PaintAssistant::drawVisibleText
@@ -880,7 +837,7 @@
     auto model = ModelById::getAs<BoxModel>(m_model);
     if (!model) return;
 
-    if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
+    if (!getLocalPoint(v, e->x(), e->y(), m_editingPoint)) return;
 
     if (m_editingCommand) {
         finish(m_editingCommand);
@@ -904,7 +861,7 @@
     m_editing = false;
 
     Event p(0);
-    if (!getPointToDrag(v, e->x(), e->y(), p)) return;
+    if (!getLocalPoint(v, e->x(), e->y(), p)) return;
     if (p.getFrame() != m_editingPoint.getFrame() ||
         p.getValue() != m_editingPoint.getValue()) return;
 
@@ -924,7 +881,7 @@
     auto model = ModelById::getAs<BoxModel>(m_model);
     if (!model) return;
 
-    if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) {
+    if (!getLocalPoint(v, e->x(), e->y(), m_editingPoint)) {
         return;
     }
 
@@ -1008,7 +965,7 @@
     if (!model) return false;
 
     Event region(0);
-    if (!getPointToDrag(v, e->x(), e->y(), region)) return false;
+    if (!getLocalPoint(v, e->x(), e->y(), region)) return false;
 
     ItemEditDialog::LabelOptions labelOptions;
     labelOptions.valueLabel = tr("Minimum Value");
--- a/layer/BoxLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/BoxLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -46,7 +46,7 @@
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                             int &resolution,
-                            SnapType snap) const override;
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
@@ -118,9 +118,12 @@
 protected:
     void getScaleExtents(LayerGeometryProvider *, double &min, double &max, bool &log) const;
 
-    EventVector getLocalPoints(LayerGeometryProvider *v, int x) const;
-
-    bool getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &) const;
+    // Return the event that "most closely contains" the given
+    // coordinates, if any; or the closest event that spans the given
+    // x coordinate in the time axis; or false otherwise. This
+    // subsumes the uses of both getPointToDrag and getLocalPoints in
+    // some other layer implementations.
+    bool getLocalPoint(LayerGeometryProvider *v, int x, int y, Event &) const;
 
     ModelId m_model;
     bool m_editing;
--- a/layer/Colour3DPlotLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/Colour3DPlotLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -1215,13 +1215,15 @@
 }
 
 bool
-Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
+Colour3DPlotLayer::snapToFeatureFrame(LayerGeometryProvider *v,
+                                      sv_frame_t &frame,
                                       int &resolution,
-                                      SnapType snap) const
+                                      SnapType snap,
+                                      int ycoord) const
 {
     auto model = ModelById::getAs<DenseThreeDimensionalModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     resolution = model->getResolution();
--- a/layer/Colour3DPlotLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/Colour3DPlotLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -64,7 +64,7 @@
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, 
                             int &resolution,
-                            SnapType snap) const override;
+                            SnapType snap, int ycoord) const override;
 
     void setLayerDormant(const LayerGeometryProvider *v,
                          bool dormant) override;
--- a/layer/FlexiNoteLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/FlexiNoteLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -586,11 +586,11 @@
 bool
 FlexiNoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                                    int &resolution,
-                                   SnapType snap) const
+                                   SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<NoteModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     resolution = model->getResolution();
--- a/layer/FlexiNoteLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/FlexiNoteLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -44,8 +44,8 @@
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                    int &resolution,
-                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/layer/ImageLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/ImageLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -222,11 +222,11 @@
 bool
 ImageLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                                int &resolution,
-                               SnapType snap) const
+                               SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<ImageModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     resolution = model->getResolution();
--- a/layer/ImageLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/ImageLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -44,7 +44,7 @@
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                             int &resolution,
-                            SnapType snap) const override;
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/layer/Layer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/Layer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -185,6 +185,13 @@
      * would be used in an editing operation through calls to
      * editStart etc.
      *
+     * If ycoord is non-negative, it contains the y coordinate at
+     * which the interaction that prompts this snap is taking place
+     * (e.g. of the mouse press used for a selection action). Layers
+     * that have objects at multiple different heights may choose to
+     * use this information. If the current action has no particular y
+     * coordinate associated with it, ycoord will be passed as -1.
+     *
      * Return true if a suitable feature was found and frame adjusted
      * accordingly.  Return false if no suitable feature was available
      * (and leave frame unmodified).  If returning true, also return
@@ -193,7 +200,8 @@
     virtual bool snapToFeatureFrame(LayerGeometryProvider * /* v */,
                                     sv_frame_t & /* frame */,
                                     int &resolution,
-                                    SnapType /* snap */) const {
+                                    SnapType /* snap */,
+                                    int /* ycoord */) const {
         resolution = 1;
         return false;
     }
--- a/layer/NoteLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/NoteLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -547,11 +547,11 @@
 bool
 NoteLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                               int &resolution,
-                              SnapType snap) const
+                              SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<NoteModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
--- a/layer/NoteLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/NoteLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -43,8 +43,8 @@
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                    int &resolution,
-                                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/layer/RegionLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/RegionLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -466,11 +466,11 @@
 bool
 RegionLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                                 int &resolution,
-                                SnapType snap) const
+                                SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<RegionModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
--- a/layer/RegionLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/RegionLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -49,7 +49,7 @@
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                             int &resolution,
-                            SnapType snap) const override;
+                            SnapType snap, int ycoord) const override;
     bool snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame,
                               int &resolution,
                               SnapType snap) const override;
--- a/layer/SpectrogramLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/SpectrogramLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -1844,7 +1844,7 @@
 SpectrogramLayer::snapToFeatureFrame(LayerGeometryProvider *,
                                      sv_frame_t &frame,
                                      int &resolution,
-                                     SnapType snap) const
+                                     SnapType snap, int) const
 {
     resolution = getWindowIncrement();
     sv_frame_t left = (frame / resolution) * resolution;
--- a/layer/SpectrogramLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/SpectrogramLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -78,8 +78,8 @@
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                    int &resolution,
-                                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
 
     void measureDoubleClick(LayerGeometryProvider *, QMouseEvent *) override;
 
--- a/layer/TextLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TextLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -238,11 +238,11 @@
 bool
 TextLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                               int &resolution,
-                              SnapType snap) const
+                              SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<TextModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
--- a/layer/TextLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TextLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -37,8 +37,8 @@
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                    int &resolution,
-                                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/layer/TimeInstantLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeInstantLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -277,11 +277,11 @@
 bool
 TimeInstantLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
                                      int &resolution,
-                                     SnapType snap) const
+                                     SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<SparseOneDimensionalModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
--- a/layer/TimeInstantLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeInstantLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -39,8 +39,8 @@
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                    int &resolution,
-                                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/layer/TimeRulerLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeRulerLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -51,7 +51,7 @@
 
 bool
 TimeRulerLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                   int &resolution, SnapType snap) const
+                                   int &resolution, SnapType snap, int) const
 {
     auto model = ModelById::get(m_model);
     if (!model) {
--- a/layer/TimeRulerLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeRulerLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -41,7 +41,8 @@
     void setLabelHeight(LabelHeight h) { m_labelHeight = h; }
     LabelHeight getLabelHeight() const { return m_labelHeight; }
 
-    bool snapToFeatureFrame(LayerGeometryProvider *, sv_frame_t &, int &, SnapType) const override;
+    bool snapToFeatureFrame(LayerGeometryProvider *, sv_frame_t &, int &,
+                            SnapType, int) const override;
 
     ColourSignificance getLayerColourSignificance() const override {
         return ColourIrrelevant;
--- a/layer/TimeValueLayer.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeValueLayer.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -687,11 +687,11 @@
 TimeValueLayer::snapToFeatureFrame(LayerGeometryProvider *v,
                                    sv_frame_t &frame,
                                    int &resolution,
-                                   SnapType snap) const
+                                   SnapType snap, int ycoord) const
 {
     auto model = ModelById::getAs<SparseTimeValueModel>(m_model);
     if (!model) {
-        return Layer::snapToFeatureFrame(v, frame, resolution, snap);
+        return Layer::snapToFeatureFrame(v, frame, resolution, snap, ycoord);
     }
 
     // SnapLeft / SnapRight: return frame of nearest feature in that
--- a/layer/TimeValueLayer.h	Thu Oct 17 10:26:21 2019 +0100
+++ b/layer/TimeValueLayer.h	Thu Oct 17 11:12:54 2019 +0100
@@ -46,11 +46,11 @@
     QString getLabelPreceding(sv_frame_t) const override;
 
     bool snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
-                                    int &resolution,
-                                    SnapType snap) const override;
+                            int &resolution,
+                            SnapType snap, int ycoord) const override;
     bool snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame,
-                                      int &resolution,
-                                      SnapType snap) const override;
+                              int &resolution,
+                              SnapType snap) const override;
 
     void drawStart(LayerGeometryProvider *v, QMouseEvent *) override;
     void drawDrag(LayerGeometryProvider *v, QMouseEvent *) override;
--- a/view/Pane.cpp	Thu Oct 17 10:26:21 2019 +0100
+++ b/view/Pane.cpp	Thu Oct 17 11:12:54 2019 +0100
@@ -1440,7 +1440,7 @@
             if (layer && !m_shiftPressed &&
                 !qobject_cast<TimeRulerLayer *>(layer)) { // don't snap to secs
                 layer->snapToFeatureFrame(this, snapFrame,
-                                          resolution, Layer::SnapLeft);
+                                          resolution, Layer::SnapLeft, e->y());
             }
         
             if (snapFrame < 0) snapFrame = 0;
@@ -2173,9 +2173,9 @@
     if (layer && !m_shiftPressed &&
         !qobject_cast<TimeRulerLayer *>(layer)) { // don't snap to secs
         layer->snapToFeatureFrame(this, snapFrameLeft,
-                                  resolution, Layer::SnapLeft);
+                                  resolution, Layer::SnapLeft, e->y());
         layer->snapToFeatureFrame(this, snapFrameRight,
-                                  resolution, Layer::SnapRight);
+                                  resolution, Layer::SnapRight, e->y());
     }
         
 //        cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << endl;