changeset 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 61a704654497
children 87e4c880b4c8
files layer/TimeRulerLayer.cpp layer/TimeRulerLayer.h view/PaneStack.cpp view/PaneStack.h view/ViewManager.cpp view/ViewManager.h widgets/AudioDial.h widgets/LayerTree.cpp
diffstat 8 files changed, 188 insertions(+), 39 deletions(-) [+]
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();
--- a/layer/TimeRulerLayer.h	Tue Jun 26 14:57:29 2007 +0000
+++ b/layer/TimeRulerLayer.h	Thu Jun 28 14:50:58 2007 +0000
@@ -44,6 +44,8 @@
     void setLabelHeight(LabelHeight h) { m_labelHeight = h; }
     LabelHeight getLabelHeight() const { return m_labelHeight; }
 
+    virtual bool snapToFeatureFrame(View *, int &, size_t &, SnapType) const;
+
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
@@ -66,6 +68,8 @@
     Model *m_model;
     QColor m_colour;
     LabelHeight m_labelHeight;
+
+    int getMajorTickSpacing(View *, bool &quarterTicks) const;
 };
 
 #endif
--- a/view/PaneStack.cpp	Tue Jun 26 14:57:29 2007 +0000
+++ b/view/PaneStack.cpp	Thu Jun 28 14:50:58 2007 +0000
@@ -115,6 +115,9 @@
     connect(pane, SIGNAL(rightButtonMenuRequested(QPoint)),
             this, SLOT(rightButtonMenuRequested(QPoint)));
 
+    emit paneAdded(pane);
+    emit paneAdded();
+
     if (!m_currentPane) {
 	setCurrentPane(pane);
     }
@@ -208,6 +211,8 @@
 	}
     }
 
+    emit paneAboutToBeDeleted(pane);
+
     delete pane->parent();
 
     if (m_currentPane == pane) {
@@ -217,6 +222,8 @@
 	    setCurrentPane(0);
 	}
     }
+
+    emit paneDeleted();
 }
 
 int
--- a/view/PaneStack.h	Tue Jun 26 14:57:29 2007 +0000
+++ b/view/PaneStack.h	Thu Jun 28 14:50:58 2007 +0000
@@ -72,6 +72,11 @@
     void propertyStacksResized();
     void contextHelpChanged(const QString &);
 
+    void paneAdded(Pane *pane);
+    void paneAdded();
+    void paneAboutToBeDeleted(Pane *pane);
+    void paneDeleted();
+
 public slots:
     void propertyContainerAdded(PropertyContainer *);
     void propertyContainerRemoved(PropertyContainer *);
--- a/view/ViewManager.cpp	Tue Jun 26 14:57:29 2007 +0000
+++ b/view/ViewManager.cpp	Thu Jun 28 14:50:58 2007 +0000
@@ -188,6 +188,26 @@
     CommandHistory::getInstance()->addCommand(command);
 }
 
+size_t
+ViewManager::constrainFrameToSelection(size_t frame) const
+{
+    MultiSelection::SelectionList sl = getSelections();
+    if (sl.empty()) return frame;
+
+    size_t selectionStartFrame = sl.begin()->getStartFrame();
+    if (frame < selectionStartFrame) {
+        frame = selectionStartFrame;
+        return frame;
+    }
+
+    MultiSelection::SelectionList::iterator i = sl.end();
+    --i;
+    size_t selectionEndFrame = i->getEndFrame();
+    if (frame > selectionEndFrame) frame = selectionEndFrame;
+
+    return frame;
+}
+
 void
 ViewManager::signalSelectionChange()
 {
--- a/view/ViewManager.h	Tue Jun 26 14:57:29 2007 +0000
+++ b/view/ViewManager.h	Thu Jun 28 14:50:58 2007 +0000
@@ -76,6 +76,7 @@
     void addSelection(const Selection &selection);
     void removeSelection(const Selection &selection);
     void clearSelections();
+    size_t constrainFrameToSelection(size_t frame) const;
 
     /**
      * Return the selection that contains a given frame.
--- a/widgets/AudioDial.h	Tue Jun 26 14:57:29 2007 +0000
+++ b/widgets/AudioDial.h	Thu Jun 28 14:50:58 2007 +0000
@@ -75,6 +75,8 @@
     const RangeMapper *rangeMapper() const { return m_rangeMapper; }
     float mappedValue() const;
 
+    int defaultValue() const { return m_defaultValue; }
+
     void setShowToolTip(bool show);
 
 signals:
--- a/widgets/LayerTree.cpp	Tue Jun 26 14:57:29 2007 +0000
+++ b/widgets/LayerTree.cpp	Thu Jun 28 14:50:58 2007 +0000
@@ -27,9 +27,11 @@
 class ViewObjectAssoc : public QObject
 {
 public:
-    ViewObjectAssoc(QObject *parent, View *v, QObject *o) :
-	QObject(parent), view(v), object(o) {
+    ViewObjectAssoc(View *v, QObject *o) :
+	QObject(0), view(v), object(o) {
 	++extantCount;
+	std::cerr << "ViewObjectAssoc (now " << extantCount << " extant)"
+		  << std::endl;
     }
 
     virtual ~ViewObjectAssoc() {
@@ -50,6 +52,8 @@
     QAbstractItemModel(parent),
     m_stack(stack)
 {
+    connect(stack, SIGNAL(paneAdded()), this, SIGNAL(layoutChanged()));
+    connect(stack, SIGNAL(paneDeleted()), this, SIGNAL(layoutChanged()));
 }
 
 LayerTreeModel::~LayerTreeModel()
@@ -156,12 +160,14 @@
 	    if (column == 0) {
 		std::cerr << "parent is pane, returning layer" << std::endl;
 		ViewObjectAssoc *assoc = new ViewObjectAssoc
-		    (const_cast<LayerTreeModel *>(this), pane, layer);
+//		    (const_cast<LayerTreeModel *>(this), pane, layer);
+		    (pane, layer);
 		return createIndex(row, column, assoc);
 	    } else {
 		std::cerr << "parent is pane, column != 0, returning model" << std::endl;
 		ViewObjectAssoc *assoc = new ViewObjectAssoc
-		    (const_cast<LayerTreeModel *>(this), pane, layer->getModel());
+//		    (const_cast<LayerTreeModel *>(this), pane, layer->getModel());
+		    (pane, layer->getModel());
 		return createIndex(row, column, assoc);
 	    }		
 	}