diff layer/TimeRulerLayer.cpp @ 271:1a49bd0d8375

* Change a number of keyboard shortcuts -- get rid of all the Alt+ shortcuts and introduce a few more Ctrl+ ones instead, as well as a number of plain single keypresses * Add Playback menu * Add time-ruler support for snap to feature, use it in ffwd/rewind (rewind still needs fixing) * restore layer hierarchy window prior to making it work correctly
author Chris Cannam
date Thu, 28 Jun 2007 14:50:58 +0000
parents 28c8e8e3c537
children 87e4c880b4c8
line wrap: on
line diff
--- a/layer/TimeRulerLayer.cpp	Tue Jun 26 14:57:29 2007 +0000
+++ b/layer/TimeRulerLayer.cpp	Thu Jun 28 14:50:58 2007 +0000
@@ -22,6 +22,7 @@
 #include <QPainter>
 
 #include <iostream>
+#include <cmath>
 
 using std::cerr;
 using std::endl;
@@ -133,6 +134,143 @@
     }
 }
 
+bool
+TimeRulerLayer::snapToFeatureFrame(View *v, int &frame,
+                                   size_t &resolution, SnapType snap) const
+{
+    if (!m_model) {
+        resolution = 1;
+        return false;
+    }
+
+    bool q;
+    int tick = getMajorTickSpacing(v, q);
+    RealTime rtick = RealTime::fromMilliseconds(tick);
+    int rate = m_model->getSampleRate();
+    
+    RealTime rt = RealTime::frame2RealTime(frame, rate);
+    double ratio = rt / rtick;
+
+    int rounded = lrint(ratio);
+    RealTime rdrt = rtick * rounded;
+
+    int left = RealTime::realTime2Frame(rdrt, rate);
+    resolution = RealTime::realTime2Frame(rtick, rate);
+    int right = left + resolution;
+
+    switch (snap) {
+
+    case SnapLeft:
+        frame = left;
+        break;
+
+    case SnapRight:
+        frame = right;
+        break;
+        
+    case SnapNearest:
+    {
+        if (abs(frame - left) > abs(right - frame)) {
+            frame = right;
+        } else {
+            frame = left;
+        }
+        break;
+    }
+
+    case SnapNeighbouring:
+    {
+        int dl = -1, dr = -1;
+        int x = v->getXForFrame(frame);
+
+        if (left > v->getStartFrame() &&
+            left < v->getEndFrame()) {
+            dl = abs(v->getXForFrame(left) - x);
+        }
+
+        if (right > v->getStartFrame() &&
+            right < v->getEndFrame()) {
+            dr = abs(v->getXForFrame(right) - x);
+        }
+
+        int fuzz = 2;
+
+        if (dl >= 0 && dr >= 0) {
+            if (dl < dr) {
+                if (dl <= fuzz) {
+                    frame = left;
+                }
+            } else {
+                if (dr < fuzz) {
+                    frame = right;
+                }
+            }
+        } else if (dl >= 0) {
+            if (dl <= fuzz) {
+                frame = left;
+            }
+        } else if (dr >= 0) {
+            if (dr <= fuzz) {
+                frame = right;
+            }
+        }
+    }
+    }
+
+    return true;
+}
+
+int
+TimeRulerLayer::getMajorTickSpacing(View *v, bool &quarterTicks) const
+{
+    // return value is in milliseconds
+
+    if (!m_model || !v) return 1000;
+
+    int sampleRate = m_model->getSampleRate();
+    if (!sampleRate) return 1000;
+
+    long startFrame = v->getStartFrame();
+    long endFrame = v->getEndFrame();
+
+    int minPixelSpacing = 50;
+
+    RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate);
+    RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate);
+
+    int count = v->width() / minPixelSpacing;
+    if (count < 1) count = 1;
+    RealTime rtGap = (rtEnd - rtStart) / count;
+
+    int incms;
+    quarterTicks = false;
+
+    if (rtGap.sec > 0) {
+	incms = 1000;
+	int s = rtGap.sec;
+	if (s > 0) { incms *= 5; s /= 5; }
+	if (s > 0) { incms *= 2; s /= 2; }
+	if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; }
+	if (s > 0) { incms *= 5; s /= 5; quarterTicks = false; }
+	if (s > 0) { incms *= 2; s /= 2; }
+	if (s > 0) { incms *= 6; s /= 6; quarterTicks = true; }
+	while (s > 0) {
+	    incms *= 10;
+	    s /= 10;
+	    quarterTicks = false;
+	}
+    } else {
+	incms = 1;
+	int ms = rtGap.msec();
+	if (ms > 0) { incms *= 10; ms /= 10; }
+	if (ms > 0) { incms *= 10; ms /= 10; }
+	if (ms > 0) { incms *= 5; ms /= 5; }
+	if (ms > 0) { incms *= 2; ms /= 2; }
+    }
+
+    return incms;
+}
+
 void
 TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const
 {
@@ -151,8 +289,6 @@
 
     long rectStart = startFrame + (rect.x() - 100) * zoomLevel;
     long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel;
-//    if (rectStart < startFrame) rectStart = startFrame;
-//    if (rectEnd > endFrame) rectEnd = endFrame;
 
 //    std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl;
     paint.save();
@@ -160,40 +296,8 @@
 
     int minPixelSpacing = 50;
 
-    RealTime rtStart = RealTime::frame2RealTime(startFrame, sampleRate);
-    RealTime rtEnd = RealTime::frame2RealTime(endFrame, sampleRate);
-//    cerr << "startFrame " << startFrame << ", endFrame " << v->getEndFrame() << ", rtStart " << rtStart << ", rtEnd " << rtEnd << endl;
-    int count = v->width() / minPixelSpacing;
-    if (count < 1) count = 1;
-    RealTime rtGap = (rtEnd - rtStart) / count;
-//    cerr << "rtGap is " << rtGap << endl;
-
-    int incms;
     bool quarter = false;
-
-    if (rtGap.sec > 0) {
-	incms = 1000;
-	int s = rtGap.sec;
-	if (s > 0) { incms *= 5; s /= 5; }
-	if (s > 0) { incms *= 2; s /= 2; }
-	if (s > 0) { incms *= 6; s /= 6; quarter = true; }
-	if (s > 0) { incms *= 5; s /= 5; quarter = false; }
-	if (s > 0) { incms *= 2; s /= 2; }
-	if (s > 0) { incms *= 6; s /= 6; quarter = true; }
-	while (s > 0) {
-	    incms *= 10;
-	    s /= 10;
-	    quarter = false;
-	}
-    } else {
-	incms = 1;
-	int ms = rtGap.msec();
-	if (ms > 0) { incms *= 10; ms /= 10; }
-	if (ms > 0) { incms *= 10; ms /= 10; }
-	if (ms > 0) { incms *= 5; ms /= 5; }
-	if (ms > 0) { incms *= 2; ms /= 2; }
-    }
-//    cerr << "incms is " << incms << endl;
+    int incms = getMajorTickSpacing(v, quarter);
 
     RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate);
     long ms = rt.sec * 1000 + rt.msec();