changeset 1615:911330a28a7c

Where the "below" view represents only a subset of the "above" view, cut off the feature mappings at the outer edges of the "below" view - don't map everything outside this (it would all just map onto the same single points at beginning and end, which is excessive, confusing and not useful)
author Chris Cannam
date Thu, 02 Jul 2020 15:37:43 +0100
parents c6f5c822b10d
children cbbb411da977
files view/AlignmentView.cpp view/AlignmentView.h view/PaneStack.cpp
diffstat 3 files changed, 103 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/view/AlignmentView.cpp	Tue Jun 30 10:56:56 2020 +0100
+++ b/view/AlignmentView.cpp	Thu Jul 02 15:37:43 2020 +0100
@@ -29,7 +29,10 @@
 AlignmentView::AlignmentView(QWidget *w) :
     View(w, false),
     m_above(nullptr),
-    m_below(nullptr)
+    m_below(nullptr),
+    m_reference(nullptr),
+    m_leftmostAbove(-1),
+    m_rightmostAbove(-1)
 {
     setObjectName(tr("AlignmentView"));
 }
@@ -41,10 +44,11 @@
     SVCERR << "AlignmentView " << getId() << "::keyFramesChanged" << endl;
 #endif
     
-    // This is just a notification that we need to rebuild it - so all
-    // we do here is clear it, and it'll be rebuilt on demand later
-    QMutexLocker locker(&m_keyFrameMutex);
-    m_keyFrameMap.clear();
+    // This is just a notification that we need to rebuild - so all we
+    // do here is clear, and rebuild on demand later
+    QMutexLocker locker(&m_mapsMutex);
+    m_fromAboveMap.clear();
+    m_fromReferenceMap.clear();
 }
 
 void
@@ -86,7 +90,7 @@
 }
 
 void
-AlignmentView::setViewAbove(View *v)
+AlignmentView::setAboveView(View *v)
 {
     if (m_above) {
         disconnect(m_above, nullptr, this, nullptr);
@@ -113,7 +117,7 @@
 }
 
 void
-AlignmentView::setViewBelow(View *v)
+AlignmentView::setBelowView(View *v)
 {
     if (m_below) {
         disconnect(m_below, nullptr, this, nullptr);
@@ -140,6 +144,12 @@
 }
 
 void
+AlignmentView::setReferenceView(View *view)
+{
+    m_reference = view;
+}
+
+void
 AlignmentView::paintEvent(QPaintEvent *)
 {
     if (m_above == nullptr || m_below == nullptr || !m_manager) return;
@@ -167,28 +177,54 @@
 
     paint.fillRect(rect(), bg);
 
-    QMutexLocker locker(&m_keyFrameMutex);
+    QMutexLocker locker(&m_mapsMutex);
 
-    if (m_keyFrameMap.empty()) {
+    if (m_fromAboveMap.empty()) {
         reconnectModels();
-        buildKeyFrameMap();
+        buildMaps();
     }
 
 #ifdef DEBUG_ALIGNMENT_VIEW
     SVCERR << "AlignmentView " << getId() << "::paintEvent: painting "
-           << m_keyFrameMap.size() << " mappings" << endl;
+           << m_fromAboveMap.size() << " mappings" << endl;
 #endif
 
-    for (const auto &km: m_keyFrameMap) {
+    int w = width();
+    int h = height();
 
-        sv_frame_t af = km.first;
-        sv_frame_t bf = km.second;
+    if (m_leftmostAbove > 0) {
+    
+        for (const auto &km: m_fromAboveMap) {
 
-        int ax = m_above->getXForFrame(af);
-        int bx = m_below->getXForFrame(bf);
+            sv_frame_t af = km.first;
+            sv_frame_t bf = km.second;
+            
+            if (af < m_leftmostAbove || af > m_rightmostAbove) {
+                continue;
+            }
 
-        if (ax >= 0 || ax < width() || bx >= 0 || bx < width()) {
-            paint.drawLine(ax, 0, bx, height());
+            int ax = m_above->getXForFrame(af);
+            int bx = m_below->getXForFrame(bf);
+
+            if (ax >= 0 || ax < w || bx >= 0 || bx < w) {
+                paint.drawLine(ax, 0, bx, h);
+            }
+        }
+    } else if (m_reference != nullptr) {
+        // the below has nothing in common with the above: show things
+        // in common with the reference instead
+    
+        for (const auto &km: m_fromReferenceMap) {
+            
+            sv_frame_t af = km.first;
+            sv_frame_t bf = km.second;
+
+            int ax = m_reference->getXForFrame(af);
+            int bx = m_below->getXForFrame(bf);
+
+            if (ax >= 0 || ax < w || bx >= 0 || bx < w) {
+                paint.drawLine(ax, 0, bx, h);
+            }
         }
     }
 
@@ -227,10 +263,10 @@
 }
 
 void
-AlignmentView::buildKeyFrameMap()
+AlignmentView::buildMaps()
 {
 #ifdef DEBUG_ALIGNMENT_VIEW
-    SVCERR << "AlignmentView " << getId() << "::buildKeyFrameMap" << endl;
+    SVCERR << "AlignmentView " << getId() << "::buildMaps" << endl;
 #endif
     
     sv_frame_t resolution = 1;
@@ -240,13 +276,40 @@
         keyFramesBelow.insert(f);
     }
 
+    foreach(sv_frame_t f, keyFramesBelow) {
+        sv_frame_t rf = m_below->alignToReference(f);
+        m_fromReferenceMap.insert({ rf, f });
+    }
+    
     vector<sv_frame_t> keyFrames = getKeyFrames(m_above, resolution);
 
+    // These are the most extreme leftward and rightward frames in
+    // "above" that have distinct corresponding frames in
+    // "below". Anything left of m_leftmostAbove or right of
+    // m_rightmostAbove maps effectively off one end or the other of
+    // the below view. (They don't actually map off the ends, they
+    // just all map to the same first/last destination frame. But we
+    // don't want to display their mappings, as they're just noise.)
+    m_leftmostAbove = -1;
+    m_rightmostAbove = -1;
+
+    sv_frame_t prevRf = -1;
+    sv_frame_t prevBf = -1;
+    
     foreach (sv_frame_t f, keyFrames) {
 
         sv_frame_t rf = m_above->alignToReference(f);
         sv_frame_t bf = m_below->alignFromReference(rf);
 
+        if (prevBf > 0 && bf > prevBf) {
+            if (m_leftmostAbove < 0 && prevBf > 0 && bf > prevBf) {
+                m_leftmostAbove = prevRf;
+            }
+            m_rightmostAbove = rf;
+        }
+        prevRf = rf;
+        prevBf = bf;
+        
         bool mappedSomething = false;
         
         if (resolution > 1) {
@@ -258,7 +321,7 @@
 
                 for (sv_frame_t probe = bf + 1; probe <= bf1; ++probe) {
                     if (keyFramesBelow.find(probe) != keyFramesBelow.end()) {
-                        m_keyFrameMap.insert({ f, probe });
+                        m_fromAboveMap.insert({ f, probe });
                         mappedSomething = true;
                     }
                 }
@@ -266,13 +329,13 @@
         }
 
         if (!mappedSomething) {
-            m_keyFrameMap.insert({ f, bf });
+            m_fromAboveMap.insert({ f, bf });
         }
     }
 
 #ifdef DEBUG_ALIGNMENT_VIEW
-    SVCERR << "AlignmentView " << getId() << "::buildKeyFrameMap: have "
-           << m_keyFrameMap.size() << " mappings" << endl;
+    SVCERR << "AlignmentView " << getId() << "::buildMaps: have "
+           << m_fromAboveMap.size() << " mappings" << endl;
 #endif
 }
 
--- a/view/AlignmentView.h	Tue Jun 30 10:56:56 2020 +0100
+++ b/view/AlignmentView.h	Thu Jul 02 15:37:43 2020 +0100
@@ -26,8 +26,9 @@
     AlignmentView(QWidget *parent = 0);
     QString getPropertyContainerIconName() const override { return "alignment"; }
     
-    void setViewAbove(View *view);
-    void setViewBelow(View *view);
+    void setAboveView(View *view);
+    void setBelowView(View *view);
+    void setReferenceView(View *view);
 
 public slots:
     void globalCentreFrameChanged(sv_frame_t) override;
@@ -44,7 +45,7 @@
     void paintEvent(QPaintEvent *e) override;
     bool shouldLabelSelections() const override { return false; }
 
-    void buildKeyFrameMap();
+    void buildMaps();
 
     std::vector<sv_frame_t> getKeyFrames(View *, sv_frame_t &resolution);
     std::vector<sv_frame_t> getDefaultKeyFrames();
@@ -55,9 +56,13 @@
 
     View *m_above;
     View *m_below;
+    View *m_reference;
 
-    QMutex m_keyFrameMutex;
-    std::multimap<sv_frame_t, sv_frame_t> m_keyFrameMap;
+    QMutex m_mapsMutex;
+    std::multimap<sv_frame_t, sv_frame_t> m_fromAboveMap;
+    std::multimap<sv_frame_t, sv_frame_t> m_fromReferenceMap;
+    sv_frame_t m_leftmostAbove;
+    sv_frame_t m_rightmostAbove;
 };
 
 #endif
--- a/view/PaneStack.cpp	Tue Jun 30 10:56:56 2020 +0100
+++ b/view/PaneStack.cpp	Thu Jul 02 15:37:43 2020 +0100
@@ -221,8 +221,9 @@
         if (!(m_options & int(Option::ShowAlignmentViews))) {
             av->hide();
         } else {
-            av->setViewAbove(m_panes[i-1].pane);
-            av->setViewBelow(m_panes[i].pane);
+            av->setAboveView(m_panes[i-1].pane);
+            av->setBelowView(m_panes[i].pane);
+            av->setReferenceView(m_panes[0].pane);
             av->show();
         }
     }
@@ -236,8 +237,9 @@
     for (int i = 0; in_range_for(m_panes, i); ++i) {
         auto av = m_panes[i].alignmentView;
         if (!av) continue;
-        av->setViewAbove(nullptr);
-        av->setViewBelow(nullptr);
+        av->setAboveView(nullptr);
+        av->setBelowView(nullptr);
+        av->setReferenceView(nullptr);
     }
 }