changeset 842:8432d2551fb2 tonioni

Update subrepos and merge from default branch
author Chris Cannam
date Tue, 02 Sep 2014 16:23:48 +0100
parents 43256b925e15 (current diff) 532302d04571 (diff)
children 4a5d144bd5d0
files
diffstat 11 files changed, 270 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/layer/TimeRulerLayer.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/layer/TimeRulerLayer.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -237,6 +237,10 @@
 
     paint.save();
 
+    // Do not label time zero - we now overlay an opaque area over
+    // time < 0 which would cut it in half
+    int minlabel = 1; // ms
+
     while (1) {
 
         // frame is used to determine where to draw the lines, so it
@@ -262,7 +266,7 @@
             break;
         }
 
-	if (x >= rect.x() - 50) {
+	if (x >= rect.x() - 50 && ms >= minlabel) {
 
             RealTime rt = RealTime::fromMilliseconds(ms);
 
--- a/view/Overview.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/view/Overview.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -25,8 +25,6 @@
 //#define DEBUG_OVERVIEW 1
 
 
-
-
 Overview::Overview(QWidget *w) :
     View(w, false),
     m_clickedInRange(false)
@@ -54,8 +52,8 @@
 
     if (!zoomChanged) {
         if (m_modelTestTime.elapsed() < 1000) {
-            for (LayerList::const_iterator i = m_layers.begin();
-                 i != m_layers.end(); ++i) {
+            for (LayerList::const_iterator i = m_layerStack.begin();
+                 i != m_layerStack.end(); ++i) {
                 if ((*i)->getModel() &&
                     (!(*i)->getModel()->isOK() ||
                      !(*i)->getModel()->isReady())) {
--- a/view/Pane.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/view/Pane.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -202,7 +202,7 @@
 
     //!!! pull out into function (presumably in View)
     bool haveConstraint = false;
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end();
          ++i) {
         if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
             haveConstraint = true;
@@ -347,7 +347,7 @@
         return false;
     }
 
-    if (layer == getSelectedLayer() &&
+    if (layer == getInteractionLayer() &&
         !shouldIlluminateLocalSelection(discard, b0, b1)) {
 
         pos = m_identifyPoint;
@@ -372,7 +372,7 @@
                                    closeToLeft, closeToRight));
 
         if (!s.isEmpty()) {
-            if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) {
+            if (getInteractionLayer() && getInteractionLayer()->isLayerEditable()) {
             
                 pos = m_identifyPoint;
                 return true;
@@ -426,7 +426,7 @@
         m_mouseInWidget &&
         toolMode == ViewManager::MeasureMode) {
 
-        for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
+        for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
             --vi;
 
             std::vector<QRect> crosshairExtents;
@@ -447,7 +447,7 @@
     const Model *waveformModel = 0; // just for reporting purposes
     const Model *workModel = 0;
 
-    for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
+    for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
         --vi;
         if (!haveSomeTimeXAxis && (*vi)->hasTimeXAxis()) {
             haveSomeTimeXAxis = true;
@@ -586,8 +586,8 @@
 
             if (!hasValueExtents) {
 
-                for (LayerList::iterator vi = m_layers.end();
-                     vi != m_layers.begin(); ) {
+                for (LayerList::iterator vi = m_layerStack.end();
+                     vi != m_layerStack.begin(); ) {
                         
                     --vi;
                         
@@ -606,8 +606,8 @@
 
                 QString requireUnit = unit;
 
-                for (LayerList::iterator vi = m_layers.end();
-                     vi != m_layers.begin(); ) {
+                for (LayerList::iterator vi = m_layerStack.end();
+                     vi != m_layerStack.begin(); ) {
                         
                     --vi;
                         
@@ -738,9 +738,9 @@
     
     int y = height() - fontHeight + fontAscent - 6;
     
-    LayerList::iterator vi = m_layers.end();
+    LayerList::iterator vi = m_layerStack.end();
     
-    if (vi != m_layers.begin()) {
+    if (vi != m_layerStack.begin()) {
         
         switch ((*--vi)->getPreferredFrameCountPosition()) {
             
@@ -916,13 +916,13 @@
         lly -= 20;
     }
 
-    if (r.y() + r.height() < lly - int(m_layers.size()) * fontHeight) {
+    if (r.y() + r.height() < lly - int(m_layerStack.size()) * fontHeight) {
         return;
     }
 
     QStringList texts;
     std::vector<QPixmap> pixmaps;
-    for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
         texts.push_back((*i)->getLayerPresentationName());
 //        cerr << "Pane " << this << ": Layer presentation name for " << *i << ": "
 //                  << texts[texts.size()-1] << endl;
@@ -1093,7 +1093,7 @@
 
     if (m_scaleWidth > 0) {
 
-        for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
+        for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
             --vi;
             
             paint.save();
@@ -1127,7 +1127,7 @@
     int formerScaleWidth = m_scaleWidth;
             
     if (m_manager && m_manager->shouldShowVerticalScale()) {
-        for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
+        for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
             --vi;
             QPainter paint(image);
             m_scaleWidth = (*vi)->getVerticalScaleWidth
@@ -1164,7 +1164,7 @@
 
     int sw = 0;
     if (m_manager && m_manager->shouldShowVerticalScale()) {
-        for (LayerList::iterator vi = m_layers.end(); vi != m_layers.begin(); ) {
+        for (LayerList::iterator vi = m_layerStack.end(); vi != m_layerStack.begin(); ) {
             --vi;
             sw = (*vi)->getVerticalScaleWidth
                 (this, m_manager->shouldShowVerticalColourScale(), paint);
@@ -1277,10 +1277,10 @@
 Layer *
 Pane::getTopFlexiNoteLayer()
 {
-    for (int i = int(m_layers.size()) - 1; i >= 0; --i) {
-        if (LayerFactory::getInstance()->getLayerType(m_layers[i]) ==
+    for (int i = int(m_layerStack.size()) - 1; i >= 0; --i) {
+        if (LayerFactory::getInstance()->getLayerType(m_layerStack[i]) ==
             LayerFactory::FlexiNotes) {
-            return m_layers[i];
+            return m_layerStack[i];
         }
     }
     return 0;
@@ -1333,10 +1333,13 @@
             m_dragStartMinValue = dmin;
         }
 
-        // Schedule a play-head move to the mouse frame location. This
-        // will happen only if nothing else of interest happens
-        // (double-click, drag) before the timeout.
-        schedulePlaybackFrameMove(getFrameForX(e->x()));
+        if (m_followPlay == PlaybackScrollPage) {
+            // Schedule a play-head move to the mouse frame
+            // location. This will happen only if nothing else of
+            // interest happens (double-click, drag) before the
+            // timeout.
+            schedulePlaybackFrameMove(getFrameForX(e->x()));
+        }
 
     } else if (mode == ViewManager::SelectMode) {
 
@@ -1364,7 +1367,7 @@
             int resolution = 1;
             int snapFrame = mouseFrame;
     
-            Layer *layer = getSelectedLayer();
+            Layer *layer = getInteractionLayer();
             if (layer && !m_shiftPressed) {
                 layer->snapToFeatureFrame(this, snapFrame,
                                           resolution, Layer::SnapLeft);
@@ -1381,25 +1384,27 @@
 
             m_resizing = false;
 
-            // Schedule a play-head move to the mouse frame
-            // location. This will happen only if nothing else of
-            // interest happens (double-click, drag) before the
-            // timeout.
-            schedulePlaybackFrameMove(mouseFrame);
+            if (m_followPlay == PlaybackScrollPage) {
+                // Schedule a play-head move to the mouse frame
+                // location. This will happen only if nothing else of
+                // interest happens (double-click, drag) before the
+                // timeout.
+                schedulePlaybackFrameMove(mouseFrame);
+            }
         }
 
         update();
 
     } else if (mode == ViewManager::DrawMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->drawStart(this, e);
         }
 
     } else if (mode == ViewManager::EraseMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->eraseStart(this, e);
         }
@@ -1517,7 +1522,7 @@
 
     } else if (mode == ViewManager::DrawMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->drawEnd(this, e);
             update();
@@ -1525,7 +1530,7 @@
 
     } else if (mode == ViewManager::EraseMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->eraseEnd(this, e);
             update();
@@ -1552,7 +1557,7 @@
         
         if (m_editing) {
             if (!editSelectionEnd(e)) {
-                Layer *layer = getSelectedLayer();
+                Layer *layer = getInteractionLayer();
                 if (layer && layer->isLayerEditable()) {
                     layer->editEnd(this, e);
                     update();
@@ -1633,7 +1638,7 @@
 
             bool updating = false;
 
-            if (getSelectedLayer() &&
+            if (getInteractionLayer() &&
                 m_manager->shouldIlluminateLocalFeatures()) {
 
                 bool previouslyIdentifying = m_identifyFeatures;
@@ -1680,14 +1685,14 @@
 
     } else if (mode == ViewManager::DrawMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->drawDrag(this, e);
         }
 
     } else if (mode == ViewManager::EraseMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->eraseDrag(this, e);
         }
@@ -1737,7 +1742,7 @@
 
             if (!editSelectionDrag(e)) {
 
-                Layer *layer = getSelectedLayer();
+                Layer *layer = getInteractionLayer();
 
                 if (layer && layer->isLayerEditable()) {
 
@@ -1792,7 +1797,7 @@
                                        e->modifiers());
 
                 if (!editSelectionStart(&clickEvent)) {
-                    Layer *layer = getSelectedLayer();
+                    Layer *layer = getInteractionLayer();
                     if (layer && layer->isLayerEditable()) {
                         layer->editStart(this, &clickEvent);
                     }
@@ -1803,7 +1808,7 @@
 
             if (!editSelectionDrag(e)) {
 
-                Layer *layer = getSelectedLayer();
+                Layer *layer = getInteractionLayer();
 
                 if (layer && layer->isLayerEditable()) {
 
@@ -1875,8 +1880,8 @@
     float min, max;
     bool log;
     Layer *layer = 0;
-    for (LayerList::const_iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) { 
+    for (LayerList::const_iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) { 
         if ((*i)->getValueExtents(min, max, log, unit) &&
             (*i)->getDisplayExtents(min, max)) {
             layer = *i;
@@ -2074,7 +2079,7 @@
     int snapFrameLeft = mouseFrame;
     int snapFrameRight = mouseFrame;
     
-    Layer *layer = getSelectedLayer();
+    Layer *layer = getInteractionLayer();
     if (layer && !m_shiftPressed) {
         layer->snapToFeatureFrame(this, snapFrameLeft,
                                   resolution, Layer::SnapLeft);
@@ -2176,7 +2181,7 @@
     if (mode == ViewManager::NavigateMode ||
         mode == ViewManager::EditMode) {
 
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             if (layer->editOpen(this, e)) relocate = false;
         }
@@ -2206,7 +2211,7 @@
     
     if (mode == ViewManager::NoteEditMode) {
         std::cerr << "double click in note edit mode" << std::endl;
-        Layer *layer = getSelectedLayer();
+        Layer *layer = getInteractionLayer();
         if (layer && layer->isLayerEditable()) {
             layer->addNote(this, e); 
         }
@@ -2388,7 +2393,7 @@
 
     //!!! pull out into function (presumably in View)
     bool haveConstraint = false;
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end();
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end();
          ++i) {
         if ((*i)->getZoomConstraint() && !(*i)->supportsOtherZoomLevels()) {
             haveConstraint = true;
@@ -2578,7 +2583,7 @@
     if (m_editingSelection.isEmpty()) return false;
 
     int offset = m_mousePos.x() - m_clickPos.x();
-    Layer *layer = getSelectedLayer();
+    Layer *layer = getInteractionLayer();
 
     if (offset == 0 || !layer) {
         m_editingSelection = Selection();
@@ -2760,7 +2765,7 @@
     if (m_manager) mode = m_manager->getToolModeFor(this);
 
     bool editable = false;
-    Layer *layer = getSelectedLayer();
+    Layer *layer = getInteractionLayer();
     if (layer && layer->isLayerEditable()) {
         editable = true;
     }
--- a/view/View.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/view/View.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -44,11 +44,10 @@
 
 #include <unistd.h>
 
+//#define DEBUG_VIEW 1
 //#define DEBUG_VIEW_WIDGET_PAINT 1
 
 
-
-
 View::View(QWidget *w, bool showProgress) :
     QFrame(w),
     m_centreFrame(0),
@@ -165,7 +164,7 @@
 int
 View::getPropertyContainerCount() const
 {
-    return m_layers.size() + 1; // the 1 is for me
+    return m_fixedOrderLayers.size() + 1; // the 1 is for me
 }
 
 const PropertyContainer *
@@ -179,7 +178,7 @@
 View::getPropertyContainer(int i)
 {
     if (i == 0) return m_propertyContainer;
-    return m_layers[i-1];
+    return m_fixedOrderLayers[i-1];
 }
 
 bool
@@ -187,8 +186,8 @@
 {
     bool have = false;
 
-    for (LayerList::const_iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) { 
+    for (LayerList::const_iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) { 
 
         QString layerUnit;
         float layerMin = 0.0, layerMax = 0.0;
@@ -224,8 +223,8 @@
 {
     std::map<int, Layer *> sortedLayers;
 
-    for (LayerList::const_iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) { 
+    for (LayerList::const_iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) { 
         if ((*i)->needsTextLabelHeight()) {
             sortedLayers[getObjectExportId(*i)] = *i;
         }
@@ -260,17 +259,17 @@
 
     Layer *selectedLayer = 0;
 
-    for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 	if (*i == pc) {
 	    selectedLayer = *i;
-	    m_layers.erase(i);
+	    m_layerStack.erase(i);
 	    break;
 	}
     }
 
     if (selectedLayer) {
 	m_haveSelectedLayer = true;
-	m_layers.push_back(selectedLayer);
+	m_layerStack.push_back(selectedLayer);
 	update();
     } else {
 	m_haveSelectedLayer = false;
@@ -342,7 +341,7 @@
 
 	if (e) {
             int rf = alignToReference(f);
-#ifdef DEBUG_VIEW_WIDGET_PAINT
+#ifdef DEBUG_VIEW
             cerr << "View[" << this << "]::setCentreFrame(" << f
                       << "): emitting centreFrameChanged("
                       << rf << ")" << endl;
@@ -469,8 +468,8 @@
     Layer::ColourSignificance maxSignificance = Layer::ColourAbsent;
     bool mostSignificantHasDarkBackground = false;
     
-    for (LayerList::const_iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) {
 
         Layer::ColourSignificance s = (*i)->getLayerColourSignificance();
         bool light = (*i)->hasLightBackground();
@@ -533,7 +532,8 @@
     SingleColourLayer *scl = dynamic_cast<SingleColourLayer *>(layer);
     if (scl) scl->setDefaultColourFor(this);
 
-    m_layers.push_back(layer);
+    m_fixedOrderLayers.push_back(layer);
+    m_layerStack.push_back(layer);
 
     QProgressBar *pb = new QProgressBar(this);
     pb->setMinimum(0);
@@ -600,9 +600,20 @@
     delete m_cache;
     m_cache = 0;
 
-    for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::iterator i = m_fixedOrderLayers.begin();
+         i != m_fixedOrderLayers.end();
+         ++i) {
 	if (*i == layer) {
-	    m_layers.erase(i);
+	    m_fixedOrderLayers.erase(i);
+            break;
+        }
+    }
+
+    for (LayerList::iterator i = m_layerStack.begin(); 
+         i != m_layerStack.end();
+         ++i) {
+	if (*i == layer) {
+	    m_layerStack.erase(i);
 	    if (m_progressBars.find(layer) != m_progressBars.end()) {
 		delete m_progressBars[layer].bar;
                 delete m_progressBars[layer].cancel;
@@ -636,9 +647,13 @@
 }
 
 Layer *
-View::getSelectedLayer()
+View::getInteractionLayer()
 {
-    if (m_haveSelectedLayer && !m_layers.empty()) {
+    Layer *sl = getSelectedLayer();
+    if (sl && !(sl->isLayerDormant(this))) {
+        return sl;
+    }
+    if (!m_layerStack.empty()) {
         int n = getLayerCount();
         while (n > 0) {
             --n;
@@ -647,7 +662,21 @@
                 return layer;
             }
         }
-        return 0;
+    }
+    return 0;
+}
+
+const Layer *
+View::getInteractionLayer() const
+{
+    return const_cast<const Layer *>(const_cast<View *>(this)->getInteractionLayer());
+}
+
+Layer *
+View::getSelectedLayer()
+{
+    if (m_haveSelectedLayer && !m_layerStack.empty()) {
+        return getLayer(getLayerCount() - 1);
     } else {
 	return 0;
     }
@@ -970,7 +999,7 @@
 {
     if (m_followPan) {
         int f = alignFromReference(rf);
-#ifdef DEBUG_VIEW_WIDGET_PAINT
+#ifdef DEBUG_VIEW
         cerr << "View[" << this << "]::globalCentreFrameChanged(" << rf
                   << "): setting centre frame to " << f << endl;
 #endif
@@ -991,14 +1020,26 @@
 	if (sender() != m_manager) return;
     }
 
+#ifdef DEBUG_VIEW        
+    cerr << "View::viewManagerPlaybackFrameChanged(" << f << ")" << endl;
+#endif
+
     f = getAlignedPlaybackFrame();
 
+#ifdef DEBUG_VIEW
+    cerr << " -> aligned frame = " << af << endl;
+#endif
+
     movePlayPointer(f);
 }
 
 void
 View::movePlayPointer(int newFrame)
 {
+#ifdef DEBUG_VIEW
+    cerr << "View(" << this << ")::movePlayPointer(" << newFrame << ")" << endl;
+#endif
+
     if (m_playPointerFrame == newFrame) return;
     bool visibleChange =
         (getXForFrame(m_playPointerFrame) != getXForFrame(newFrame));
@@ -1151,7 +1192,7 @@
     bool first = true;
     int startFrame = 0;
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
 	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
 
@@ -1172,7 +1213,7 @@
     bool first = true;
     int endFrame = 0;
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
 	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
 
@@ -1198,7 +1239,7 @@
 
     //!!! nah, this wants to always return the sr of the main model!
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
 	    return (*i)->getModel()->getSampleRate();
 	}
@@ -1241,8 +1282,8 @@
     Model *alignedModel = 0;
     Model *goodModel = 0;
 
-    for (LayerList::const_iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) {
 
         Layer *layer = *i;
 
@@ -1294,19 +1335,9 @@
 
     Model *aligningModel = getAligningModel();
     if (!aligningModel) return pf;
-/*
-    Model *pm = m_manager->getPlaybackModel();
-
-//    cerr << "View[" << this << "]::getAlignedPlaybackFrame: pf = " << pf;
-
-    if (pm) {
-        pf = pm->alignToReference(pf);
-//        cerr << " -> " << pf;
-    }
-*/
+
     int af = aligningModel->alignFromReference(pf);
 
-//    cerr << ", aligned = " << af << endl;
     return af;
 }
 
@@ -1314,7 +1345,7 @@
 View::areLayersScrollable() const
 {
     // True iff all views are scrollable
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 	if (!(*i)->isLayerScrollable(this)) return false;
     }
     return true;
@@ -1331,7 +1362,7 @@
     LayerList scrollables;
     bool metUnscrollable = false;
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 //        SVDEBUG << "View::getScrollableBackLayers: calling isLayerDormant on layer " << *i << endl;
 //        cerr << "(name is " << (*i)->objectName() << ")"
 //                  << endl;
@@ -1367,7 +1398,7 @@
 
     bool started = false;
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 	if ((*i)->isLayerDormant(this)) continue;
 	if (!started && (*i)->isLayerScrollable(this)) {
 	    continue;
@@ -1398,7 +1429,7 @@
 
     PowerOfSqrtTwoZoomConstraint defaultZoomConstraint;
 
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
 	const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
 	if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
@@ -1422,7 +1453,7 @@
 bool
 View::areLayerColoursSignificant() const
 {
-    for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
+    for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 	if ((*i)->getLayerColourSignificance() ==
             Layer::ColourHasMeaningfulValue) return true;
         if ((*i)->isLayerOpaque()) break;
@@ -1433,8 +1464,8 @@
 bool
 View::hasTopLayerTimeXAxis() const
 {
-    LayerList::const_iterator i = m_layers.end();
-    if (i == m_layers.begin()) return false;
+    LayerList::const_iterator i = m_layerStack.end();
+    if (i == m_layerStack.begin()) return false;
     --i;
     return (*i)->hasTimeXAxis();
 }
@@ -1632,7 +1663,7 @@
 //    Profiler prof("View::paintEvent", false);
 //    cerr << "View::paintEvent: centre frame is " << m_centreFrame << endl;
 
-    if (m_layers.empty()) {
+    if (m_layerStack.empty()) {
 	QFrame::paintEvent(e);
 	return;
     }
@@ -2312,8 +2343,8 @@
 
     bool someLayersIncomplete = false;
 
-    for (LayerList::iterator i = m_layers.begin();
-         i != m_layers.end(); ++i) {
+    for (LayerList::iterator i = m_layerStack.begin();
+         i != m_layerStack.end(); ++i) {
 
         int c = (*i)->getCompletion(this);
         if (c < 100) {
@@ -2331,11 +2362,11 @@
 
         while (layerCompletion < 100) {
 
-            for (LayerList::iterator i = m_layers.begin();
-                 i != m_layers.end(); ++i) {
+            for (LayerList::iterator i = m_layerStack.begin();
+                 i != m_layerStack.end(); ++i) {
 
                 int c = (*i)->getCompletion(this);
-                if (i == m_layers.begin() || c < layerCompletion) {
+                if (i == m_layerStack.begin() || c < layerCompletion) {
                     layerCompletion = c;
                 }
             }
@@ -2378,8 +2409,8 @@
 	paint.setPen(getForeground());
 	paint.setBrush(Qt::NoBrush);
 
-	for (LayerList::iterator i = m_layers.begin();
-             i != m_layers.end(); ++i) {
+	for (LayerList::iterator i = m_layerStack.begin();
+             i != m_layerStack.end(); ++i) {
 		if(!((*i)->isLayerDormant(this))){
 
 		    paint.setRenderHint(QPainter::Antialiasing, false);
@@ -2474,11 +2505,11 @@
              "ignore")
 	.arg(extraAttributes);
 
-    for (int i = 0; i < (int)m_layers.size(); ++i) {
-        bool visible = !m_layers[i]->isLayerDormant(this);
-        m_layers[i]->toBriefXml(stream, indent + "  ",
-                                QString("visible=\"%1\"")
-                                .arg(visible ? "true" : "false"));
+    for (int i = 0; i < (int)m_fixedOrderLayers.size(); ++i) {
+        bool visible = !m_fixedOrderLayers[i]->isLayerDormant(this);
+        m_fixedOrderLayers[i]->toBriefXml(stream, indent + "  ",
+                                          QString("visible=\"%1\"")
+                                          .arg(visible ? "true" : "false"));
     }
 
     stream << indent + "</view>\n";
--- a/view/View.h	Fri Jul 18 15:06:04 2014 +0100
+++ b/view/View.h	Tue Sep 02 16:23:48 2014 +0100
@@ -145,37 +145,89 @@
      */
     virtual void scroll(bool right, bool lots, bool doEmit = true);
 
+    /**
+     * Add a layer to the view. (Normally this should be handled
+     * through some command abstraction instead of using this function
+     * directly.)
+     */
     virtual void addLayer(Layer *v);
-    virtual void removeLayer(Layer *v); // does not delete the layer
-    virtual int getLayerCount() const { return m_layers.size(); }
 
     /**
-     * Return a layer, counted in stacking order.  That is, layer 0 is
-     * the bottom layer and layer "getLayerCount()-1" is the top one.
+     * Remove a layer from the view. Does not delete the
+     * layer. (Normally this should be handled through some command
+     * abstraction instead of using this function directly.)
+     */
+    virtual void removeLayer(Layer *v);
+
+    /**
+     * Return the number of layers, regardless of whether visible or
+     * dormant, i.e. invisible, in this view.
+     */
+    virtual int getLayerCount() const { return m_layerStack.size(); }
+
+    /**
+     * Return the nth layer, counted in stacking order.  That is,
+     * layer 0 is the bottom layer and layer "getLayerCount()-1" is
+     * the top one. The returned layer may be visible or it may be
+     * dormant, i.e. invisible.
      */
     virtual Layer *getLayer(int n) {
-        if (n < int(m_layers.size())) return m_layers[n]; else return 0;
+        if (n < int(m_layerStack.size())) return m_layerStack[n];
+        else return 0;
     }
 
     /**
-     * Return the top layer.  This is the same as
-     * getLayer(getLayerCount()-1) if there is at least one layer, and
-     * 0 otherwise.
+     * Return the nth layer, counted in the order they were
+     * added. Unlike the stacking order used in getLayer(), which
+     * changes each time a layer is selected, this ordering remains
+     * fixed. The returned layer may be visible or it may be dormant,
+     * i.e. invisible.
      */
-    virtual Layer *getTopLayer() {
-        return m_layers.empty() ? 0 : m_layers[m_layers.size()-1];
+    virtual Layer *getFixedOrderLayer(int n) {
+        if (n < int(m_fixedOrderLayers.size())) return m_fixedOrderLayers[n];
+        else return 0;
     }
 
     /**
-     * Return the layer last selected by the user.  This is normally
-     * the top layer, the same as getLayer(getLayerCount()-1).
-     * However, if the user has selected the pane itself more recently
-     * than any of the layers on it, this function will return 0.  It
-     * will also return 0 if there are no layers.
+     * Return the layer currently active for tool interaction. This is
+     * the topmost non-dormant (i.e. visible) layer in the view. If
+     * there are no visible layers in the view, return 0.
+     */
+    virtual Layer *getInteractionLayer();
+
+    virtual const Layer *getInteractionLayer() const;
+
+    /**
+     * Return the layer most recently selected by the user. This is
+     * the layer that any non-tool-driven commands should operate on,
+     * in the case where this view is the "current" one.
+     *
+     * If the user has selected the view itself more recently than any
+     * of the layers on it, this function will return 0, and any
+     * non-tool-driven layer commands should be deactivated while this
+     * view is current. It will also return 0 if there are no layers
+     * in the view.
+     *
+     * Note that, unlike getInteractionLayer(), this could return an
+     * invisible (dormant) layer.
      */
     virtual Layer *getSelectedLayer();
+
     virtual const Layer *getSelectedLayer() const;
 
+    /**
+     * Return the "top" layer in the view, whether visible or dormant.
+     * This is the same as getLayer(getLayerCount()-1) if there is at
+     * least one layer, and 0 otherwise.
+     *
+     * For most purposes involving interaction or commands, you
+     * probably want either getInteractionLayer() or
+     * getSelectedLayer() instead.
+     */
+    virtual Layer *getTopLayer() {
+        return m_layerStack.empty() ? 0 : m_layerStack[m_layerStack.size()-1];
+    }
+
     virtual void setViewManager(ViewManager *m);
     virtual void setViewManager(ViewManager *m, int initialFrame);
     virtual ViewManager *getViewManager() const { return m_manager; }
@@ -236,6 +288,8 @@
 
     virtual int getPropertyContainerCount() const;
 
+    // The 0th property container is the view's own; the rest are the
+    // layers in fixed-order series
     virtual const PropertyContainer *getPropertyContainer(int i) const;
     virtual PropertyContainer *getPropertyContainer(int i);
 
@@ -368,7 +422,8 @@
 
     bool                m_deleting;
 
-    LayerList           m_layers; // I don't own these, but see dtor note above
+    LayerList           m_layerStack; // I don't own these, but see dtor note above
+    LayerList           m_fixedOrderLayers;
     bool                m_haveSelectedLayer;
 
     QString             m_lastError;
--- a/view/ViewManager.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/view/ViewManager.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -190,15 +190,35 @@
 int
 ViewManager::alignPlaybackFrameToReference(int frame) const
 {
-    if (!m_playbackModel) return frame;
-    else return m_playbackModel->alignToReference(frame);
+#ifdef DEBUG_VIEW_MANAGER
+    cerr << "ViewManager::alignPlaybackFrameToReference(" << frame << "): playback model is " << m_playbackModel << endl;
+#endif
+    if (!m_playbackModel) {
+        return frame;
+    } else {
+        int f = m_playbackModel->alignToReference(frame);
+#ifdef DEBUG_VIEW_MANAGER
+        cerr << "aligned frame = " << f << endl;
+#endif
+        return f;
+    }
 }
 
 int
 ViewManager::alignReferenceToPlaybackFrame(int frame) const
 {
-    if (!m_playbackModel) return frame;
-    else return m_playbackModel->alignFromReference(frame);
+#ifdef DEBUG_VIEW_MANAGER
+    cerr << "ViewManager::alignReferenceToPlaybackFrame(" << frame << "): playback model is " << m_playbackModel << endl;
+#endif
+    if (!m_playbackModel) {
+        return frame;
+    } else {
+        int f = m_playbackModel->alignFromReference(frame);
+#ifdef DEBUG_VIEW_MANAGER
+        cerr << "aligned frame = " << f << endl;
+#endif
+        return f;
+    }
 }
 
 bool
--- a/widgets/InteractiveFileFinder.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/widgets/InteractiveFileFinder.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -34,7 +34,8 @@
 
 InteractiveFileFinder::InteractiveFileFinder() :
     m_sessionExtension("sv"),
-    m_lastLocatedLocation("")
+    m_lastLocatedLocation(""),
+    m_parent(0)
 {
     SVDEBUG << "Registering interactive file finder" << endl;
     FileFinder::registerFileFinder(this);
@@ -45,6 +46,12 @@
 }
 
 void
+InteractiveFileFinder::setParentWidget(QWidget *parent)
+{
+    getInstance()->m_parent = parent;
+}
+
+void
 InteractiveFileFinder::setApplicationSessionExtension(QString extension)
 {
     m_sessionExtension = extension;
@@ -162,7 +169,7 @@
 
     // Use our own QFileDialog just for symmetry with getSaveFileName below
 
-    QFileDialog dialog;
+    QFileDialog dialog(m_parent);
     dialog.setNameFilters(filter.split('\n'));
     dialog.setWindowTitle(title);
     dialog.setDirectory(lastPath);
@@ -306,7 +313,7 @@
     // Use our own QFileDialog instead of static functions, as we may
     // need to adjust the file extension based on the selected filter
 
-    QFileDialog dialog;
+    QFileDialog dialog(m_parent);
 
     QStringList filters = filter.split('\n');
 
--- a/widgets/InteractiveFileFinder.h	Fri Jul 18 15:06:04 2014 +0100
+++ b/widgets/InteractiveFileFinder.h	Tue Sep 02 16:23:48 2014 +0100
@@ -44,6 +44,8 @@
 
     QString find(FileType type, QString location, QString lastKnownLocation = "");
 
+    static void setParentWidget(QWidget *);
+
     static InteractiveFileFinder *getInstance() { return &m_instance; }
 
 protected:
@@ -55,6 +57,8 @@
 
     QString m_sessionExtension;
     QString m_lastLocatedLocation;
+
+    QWidget *m_parent;
 };
 
 #endif
--- a/widgets/PluginParameterBox.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/widgets/PluginParameterBox.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -131,7 +131,9 @@
 
         QLabel *label = new QLabel(name);
         if (params[i].description != "") {
-            label->setToolTip(params[i].description.c_str());
+            label->setToolTip(QString("<qt>%1</qt>")
+                              .arg(params[i].description.c_str())
+                              .replace("\n", "<br>"));
         }
         m_layout->addWidget(label, i + offset, 0);
 
--- a/widgets/PropertyBox.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/widgets/PropertyBox.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -76,6 +76,8 @@
 
     m_layout = new QGridLayout;
     m_layout->setMargin(0);
+    m_layout->setHorizontalSpacing(2);
+    m_layout->setVerticalSpacing(1);
     m_mainWidget->setLayout(m_layout);
 
     PropertyContainer::PropertyList properties = m_container->getProperties();
--- a/widgets/PropertyStack.cpp	Fri Jul 18 15:06:04 2014 +0100
+++ b/widgets/PropertyStack.cpp	Tue Sep 02 16:23:48 2014 +0100
@@ -30,7 +30,7 @@
 
 #include <iostream>
 
-//#define DEBUG_PROPERTY_STACK 1
+#define DEBUG_PROPERTY_STACK 1
 
 PropertyStack::PropertyStack(QWidget *parent, View *client) :
     QTabWidget(parent),
@@ -85,7 +85,7 @@
     blockSignals(true);
 
 #ifdef DEBUG_PROPERTY_STACK
-    SVDEBUG << "PropertyStack::repopulate" << endl;
+    cerr << "PropertyStack[" << this << "]::repopulate" << endl;
 #endif
     
     while (count() > 0) {
@@ -101,6 +101,12 @@
 	PropertyContainer *container = m_client->getPropertyContainer(i);
 	QString name = container->getPropertyContainerName();
 	
+#ifdef DEBUG_PROPERTY_STACK
+        cerr << "PropertyStack[" << this << "]::repopulate: client " << m_client
+             << " returns container " << container << " (name " << name
+             << ") at position " << i << endl;
+#endif
+
 	PropertyBox *box = new PropertyBox(container);
 
 	connect(box, SIGNAL(showLayer(bool)), this, SLOT(showLayer(bool)));