diff view/View.cpp @ 1324:13d9b422f7fe zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:31 +0100
parents 57d192e26331 769d7890203b
children 97c68bffbda6
line wrap: on
line diff
--- a/view/View.cpp	Mon Dec 12 15:18:52 2016 +0000
+++ b/view/View.cpp	Mon Sep 17 13:51:31 2018 +0100
@@ -41,6 +41,7 @@
 #include <QMessageBox>
 #include <QPushButton>
 #include <QSettings>
+#include <QSvgGenerator>
 
 #include <iostream>
 #include <cassert>
@@ -79,6 +80,8 @@
 
     m_deleting = true;
     delete m_propertyContainer;
+    delete m_cache;
+    delete m_buffer;
 }
 
 PropertyContainer::PropertyList
@@ -111,14 +114,14 @@
 
 int
 View::getPropertyRangeAndValue(const PropertyContainer::PropertyName &name,
-			       int *min, int *max, int *deflt) const
+                               int *min, int *max, int *deflt) const
 {
     if (deflt) *deflt = 1;
     if (name == "Global Scroll") return m_followPan;
     if (name == "Global Zoom") return m_followZoom;
     if (name == "Follow Playback") {
-	if (min) *min = 0;
-	if (max) *max = 2;
+        if (min) *min = 0;
+        if (max) *max = 2;
         if (deflt) *deflt = int(PlaybackScrollPageWithCentre);
         switch (m_followPlay) {
         case PlaybackScrollContinuous: return 0;
@@ -134,15 +137,15 @@
 
 QString
 View::getPropertyValueLabel(const PropertyContainer::PropertyName &name,
-			    int value) const
+                            int value) const
 {
     if (name == "Follow Playback") {
-	switch (value) {
-	default:
-	case 0: return tr("Scroll");
-	case 1: return tr("Page");
-	case 2: return tr("Off");
-	}
+        switch (value) {
+        default:
+        case 0: return tr("Scroll");
+        case 1: return tr("Page");
+        case 2: return tr("Off");
+        }
     }
     return tr("<unknown>");
 }
@@ -151,16 +154,16 @@
 View::setProperty(const PropertyContainer::PropertyName &name, int value)
 {
     if (name == "Global Scroll") {
-	setFollowGlobalPan(value != 0);
+        setFollowGlobalPan(value != 0);
     } else if (name == "Global Zoom") {
-	setFollowGlobalZoom(value != 0);
+        setFollowGlobalZoom(value != 0);
     } else if (name == "Follow Playback") {
-	switch (value) {
-	default:
-	case 0: setPlaybackFollow(PlaybackScrollContinuous); break;
-	case 1: setPlaybackFollow(PlaybackScrollPageWithCentre); break;
-	case 2: setPlaybackFollow(PlaybackIgnore); break;
-	}
+        switch (value) {
+        default:
+        case 0: setPlaybackFollow(PlaybackScrollContinuous); break;
+        case 1: setPlaybackFollow(PlaybackScrollPageWithCentre); break;
+        case 2: setPlaybackFollow(PlaybackIgnore); break;
+        }
     }
 }
 
@@ -174,7 +177,7 @@
 View::getPropertyContainer(int i) const
 {
     return (const PropertyContainer *)(((View *)this)->
-				       getPropertyContainer(i));
+                                       getPropertyContainer(i));
 }
 
 PropertyContainer *
@@ -233,11 +236,11 @@
         }
     }
 
-    int y = 15 + paint.fontMetrics().ascent();
+    int y = ViewManager::scalePixelSize(15) + paint.fontMetrics().ascent();
 
     for (std::map<int, Layer *>::const_iterator i = sortedLayers.begin();
          i != sortedLayers.end(); ++i) {
-        if (i->second == layer) return y;
+        if (i->second == layer) break;
         y += paint.fontMetrics().height();
     }
 
@@ -250,11 +253,11 @@
     if (client != this) return;
     
     if (pc == m_propertyContainer) {
-	if (m_haveSelectedLayer) {
-	    m_haveSelectedLayer = false;
-	    update();
-	}
-	return;
+        if (m_haveSelectedLayer) {
+            m_haveSelectedLayer = false;
+            update();
+        }
+        return;
     }
 
     delete m_cache;
@@ -263,19 +266,19 @@
     Layer *selectedLayer = 0;
 
     for (LayerList::iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
-	if (*i == pc) {
-	    selectedLayer = *i;
-	    m_layerStack.erase(i);
-	    break;
-	}
+        if (*i == pc) {
+            selectedLayer = *i;
+            m_layerStack.erase(i);
+            break;
+        }
     }
 
     if (selectedLayer) {
-	m_haveSelectedLayer = true;
-	m_layerStack.push_back(selectedLayer);
-	update();
+        m_haveSelectedLayer = true;
+        m_layerStack.push_back(selectedLayer);
+        update();
     } else {
-	m_haveSelectedLayer = false;
+        m_haveSelectedLayer = false;
     }
 
     emit propertyContainerSelected(pc);
@@ -326,23 +329,23 @@
 
     if (m_centreFrame != f) {
 
-	int formerPixel = int(m_centreFrame / m_zoomLevel);
-
-	m_centreFrame = f;
-
-	int newPixel = int(m_centreFrame / m_zoomLevel);
-	
-	if (newPixel != formerPixel) {
+        int formerPixel = int(m_centreFrame / m_zoomLevel);
+
+        m_centreFrame = f;
+
+        int newPixel = int(m_centreFrame / m_zoomLevel);
+        
+        if (newPixel != formerPixel) {
 
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-	    cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << endl;
+            cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << endl;
 #endif
-	    update();
-
-	    changeVisible = true;
-	}
-
-	if (e) {
+            update();
+
+            changeVisible = true;
+        }
+
+        if (e) {
             sv_frame_t rf = alignToReference(f);
 #ifdef DEBUG_VIEW
             cerr << "View[" << this << "]::setCentreFrame(" << f
@@ -380,9 +383,9 @@
 
 double
 View::getYForFrequency(double frequency,
-		       double minf,
-		       double maxf, 
-		       bool logarithmic) const
+                       double minf,
+                       double maxf, 
+                       bool logarithmic) const
 {
     Profiler profiler("View::getYForFrequency");
 
@@ -390,57 +393,57 @@
 
     if (logarithmic) {
 
-	static double lastminf = 0.0, lastmaxf = 0.0;
-	static double logminf = 0.0, logmaxf = 0.0;
-
-	if (lastminf != minf) {
-	    lastminf = (minf == 0.0 ? 1.0 : minf);
-	    logminf = log10(minf);
-	}
-	if (lastmaxf != maxf) {
-	    lastmaxf = (maxf < lastminf ? lastminf : maxf);
-	    logmaxf = log10(maxf);
-	}
-
-	if (logminf == logmaxf) return 0;
-	return h - (h * (log10(frequency) - logminf)) / (logmaxf - logminf);
+        static double lastminf = 0.0, lastmaxf = 0.0;
+        static double logminf = 0.0, logmaxf = 0.0;
+
+        if (lastminf != minf) {
+            lastminf = (minf == 0.0 ? 1.0 : minf);
+            logminf = log10(minf);
+        }
+        if (lastmaxf != maxf) {
+            lastmaxf = (maxf < lastminf ? lastminf : maxf);
+            logmaxf = log10(maxf);
+        }
+
+        if (logminf == logmaxf) return 0;
+        return h - (h * (log10(frequency) - logminf)) / (logmaxf - logminf);
 
     } else {
-	
-	if (minf == maxf) return 0;
-	return h - (h * (frequency - minf)) / (maxf - minf);
+        
+        if (minf == maxf) return 0;
+        return h - (h * (frequency - minf)) / (maxf - minf);
     }
 }
 
 double
 View::getFrequencyForY(double y,
-		       double minf,
-		       double maxf,
-		       bool logarithmic) const
+                       double minf,
+                       double maxf,
+                       bool logarithmic) const
 {
     double h = height();
 
     if (logarithmic) {
 
-	static double lastminf = 0.0, lastmaxf = 0.0;
-	static double logminf = 0.0, logmaxf = 0.0;
-
-	if (lastminf != minf) {
-	    lastminf = (minf == 0.0 ? 1.0 : minf);
-	    logminf = log10(minf);
-	}
-	if (lastmaxf != maxf) {
-	    lastmaxf = (maxf < lastminf ? lastminf : maxf);
-	    logmaxf = log10(maxf);
-	}
-
-	if (logminf == logmaxf) return 0;
-	return pow(10.0, logminf + ((logmaxf - logminf) * (h - y)) / h);
+        static double lastminf = 0.0, lastmaxf = 0.0;
+        static double logminf = 0.0, logmaxf = 0.0;
+
+        if (lastminf != minf) {
+            lastminf = (minf == 0.0 ? 1.0 : minf);
+            logminf = log10(minf);
+        }
+        if (lastmaxf != maxf) {
+            lastmaxf = (maxf < lastminf ? lastminf : maxf);
+            logmaxf = log10(maxf);
+        }
+
+        if (logminf == logmaxf) return 0;
+        return pow(10.0, logminf + ((logmaxf - logminf) * (h - y)) / h);
 
     } else {
 
-	if (minf == maxf) return 0;
-	return minf + ((h - y) * (maxf - minf)) / h;
+        if (minf == maxf) return 0;
+        return minf + ((h - y) * (maxf - minf)) / h;
     }
 }
 
@@ -448,7 +451,7 @@
 View::getZoomLevel() const
 {
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-//	cout << "zoom level: " << m_zoomLevel << endl;
+//        cout << "zoom level: " << m_zoomLevel << endl;
 #endif
     return m_zoomLevel;
 }
@@ -479,9 +482,9 @@
     if (z < dpratio) return;
     if (z < 1) z = 1;
     if (m_zoomLevel != int(z)) {
-	m_zoomLevel = z;
-	emit zoomLevelChanged(z, m_followZoom);
-	update();
+        m_zoomLevel = z;
+        emit zoomLevelChanged(z, m_followZoom);
+        update();
     }
 }
 
@@ -508,7 +511,7 @@
         }
     }
 
-    if (int(maxSignificance) >= int(Layer::ColourAndBackgroundSignificant)) {
+    if (int(maxSignificance) >= int(Layer::ColourDistinguishes)) {
         return !mostSignificantHasDarkBackground;
     } else {
         return !darkPalette;
@@ -593,23 +596,23 @@
     pb->hide();
     
     connect(layer, SIGNAL(layerParametersChanged()),
-	    this,    SLOT(layerParametersChanged()));
+            this,    SLOT(layerParametersChanged()));
     connect(layer, SIGNAL(layerParameterRangesChanged()),
-	    this,    SLOT(layerParameterRangesChanged()));
+            this,    SLOT(layerParameterRangesChanged()));
     connect(layer, SIGNAL(layerMeasurementRectsChanged()),
-	    this,    SLOT(layerMeasurementRectsChanged()));
+            this,    SLOT(layerMeasurementRectsChanged()));
     connect(layer, SIGNAL(layerNameChanged()),
-	    this,    SLOT(layerNameChanged()));
+            this,    SLOT(layerNameChanged()));
     connect(layer, SIGNAL(modelChanged()),
-	    this,    SLOT(modelChanged()));
+            this,    SLOT(modelChanged()));
     connect(layer, SIGNAL(modelCompletionChanged()),
-	    this,    SLOT(modelCompletionChanged()));
+            this,    SLOT(modelCompletionChanged()));
     connect(layer, SIGNAL(modelAlignmentCompletionChanged()),
-	    this,    SLOT(modelAlignmentCompletionChanged()));
+            this,    SLOT(modelAlignmentCompletionChanged()));
     connect(layer, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
-	    this,    SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
+            this,    SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
     connect(layer, SIGNAL(modelReplaced()),
-	    this,    SLOT(modelReplaced()));
+            this,    SLOT(modelReplaced()));
 
     update();
 
@@ -620,7 +623,7 @@
 View::removeLayer(Layer *layer)
 {
     if (m_deleting) {
-	return;
+        return;
     }
 
     delete m_cache;
@@ -629,8 +632,8 @@
     for (LayerList::iterator i = m_fixedOrderLayers.begin();
          i != m_fixedOrderLayers.end();
          ++i) {
-	if (*i == layer) {
-	    m_fixedOrderLayers.erase(i);
+        if (*i == layer) {
+            m_fixedOrderLayers.erase(i);
             break;
         }
     }
@@ -638,16 +641,16 @@
     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;
+        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;
-		delete m_progressBars[layer].checkTimer;
-		m_progressBars.erase(layer);
-	    }
-	    break;
-	}
+                delete m_progressBars[layer].checkTimer;
+                m_progressBars.erase(layer);
+            }
+            break;
+        }
     }
     
     disconnect(layer, SIGNAL(layerParametersChanged()),
@@ -704,7 +707,7 @@
     if (m_haveSelectedLayer && !m_layerStack.empty()) {
         return getLayer(getLayerCount() - 1);
     } else {
-	return 0;
+        return 0;
     }
 }
 
@@ -718,36 +721,36 @@
 View::setViewManager(ViewManager *manager)
 {
     if (m_manager) {
-	m_manager->disconnect(this, SLOT(globalCentreFrameChanged(sv_frame_t)));
-	m_manager->disconnect(this, SLOT(viewCentreFrameChanged(View *, sv_frame_t)));
-	m_manager->disconnect(this, SLOT(viewManagerPlaybackFrameChanged(sv_frame_t)));
-	m_manager->disconnect(this, SLOT(viewZoomLevelChanged(View *, ZoomLevel, bool)));
+        m_manager->disconnect(this, SLOT(globalCentreFrameChanged(sv_frame_t)));
+        m_manager->disconnect(this, SLOT(viewCentreFrameChanged(View *, sv_frame_t)));
+        m_manager->disconnect(this, SLOT(viewManagerPlaybackFrameChanged(sv_frame_t)));
+        m_manager->disconnect(this, SLOT(viewZoomLevelChanged(View *, ZoomLevel, bool)));
         m_manager->disconnect(this, SLOT(toolModeChanged()));
         m_manager->disconnect(this, SLOT(selectionChanged()));
         m_manager->disconnect(this, SLOT(overlayModeChanged()));
         m_manager->disconnect(this, SLOT(zoomWheelsEnabledChanged()));
         disconnect(m_manager, SLOT(viewCentreFrameChanged(sv_frame_t, bool, PlaybackFollowMode)));
-	disconnect(m_manager, SLOT(zoomLevelChanged(ZoomLevel, bool)));
+        disconnect(m_manager, SLOT(zoomLevelChanged(ZoomLevel, bool)));
     }
 
     m_manager = manager;
 
     connect(m_manager, SIGNAL(globalCentreFrameChanged(sv_frame_t)),
-	    this, SLOT(globalCentreFrameChanged(sv_frame_t)));
+            this, SLOT(globalCentreFrameChanged(sv_frame_t)));
     connect(m_manager, SIGNAL(viewCentreFrameChanged(View *, sv_frame_t)),
-	    this, SLOT(viewCentreFrameChanged(View *, sv_frame_t)));
+            this, SLOT(viewCentreFrameChanged(View *, sv_frame_t)));
     connect(m_manager, SIGNAL(playbackFrameChanged(sv_frame_t)),
-	    this, SLOT(viewManagerPlaybackFrameChanged(sv_frame_t)));
+            this, SLOT(viewManagerPlaybackFrameChanged(sv_frame_t)));
 
     connect(m_manager, SIGNAL(viewZoomLevelChanged(View *, ZoomLevel, bool)),
-	    this, SLOT(viewZoomLevelChanged(View *, ZoomLevel, bool)));
+            this, SLOT(viewZoomLevelChanged(View *, ZoomLevel, bool)));
 
     connect(m_manager, SIGNAL(toolModeChanged()),
-	    this, SLOT(toolModeChanged()));
+            this, SLOT(toolModeChanged()));
     connect(m_manager, SIGNAL(selectionChanged()),
-	    this, SLOT(selectionChanged()));
+            this, SLOT(selectionChanged()));
     connect(m_manager, SIGNAL(inProgressSelectionChanged()),
-	    this, SLOT(selectionChanged()));
+            this, SLOT(selectionChanged()));
     connect(m_manager, SIGNAL(overlayModeChanged()),
             this, SLOT(overlayModeChanged()));
     connect(m_manager, SIGNAL(showCentreLineChanged()),
@@ -761,7 +764,7 @@
                                                    PlaybackFollowMode)));
 
     connect(this, SIGNAL(zoomLevelChanged(ZoomLevel, bool)),
-	    m_manager, SLOT(viewZoomLevelChanged(ZoomLevel, bool)));
+            m_manager, SLOT(viewZoomLevelChanged(ZoomLevel, bool)));
 
     switch (m_followPlay) {
         
@@ -833,16 +836,16 @@
     bool discard;
     LayerList scrollables = getScrollableBackLayers(false, discard);
     for (LayerList::const_iterator i = scrollables.begin();
-	 i != scrollables.end(); ++i) {
-	if (*i == obj || (*i)->getModel() == obj) {
-	    recreate = true;
-	    break;
-	}
+         i != scrollables.end(); ++i) {
+        if (*i == obj || (*i)->getModel() == obj) {
+            recreate = true;
+            break;
+        }
     }
 
     if (recreate) {
-	delete m_cache;
-	m_cache = 0;
+        delete m_cache;
+        m_cache = 0;
     }
 
     emit layerModelChanged();
@@ -865,12 +868,12 @@
 #endif
 
     if (myStartFrame > 0 && endFrame < myStartFrame) {
-	checkProgress(obj);
-	return;
+        checkProgress(obj);
+        return;
     }
     if (startFrame > myEndFrame) {
-	checkProgress(obj);
-	return;
+        checkProgress(obj);
+        return;
     }
 
     // If the model that has changed is not used by any of the cached
@@ -881,16 +884,16 @@
     bool discard;
     LayerList scrollables = getScrollableBackLayers(false, discard);
     for (LayerList::const_iterator i = scrollables.begin();
-	 i != scrollables.end(); ++i) {
-	if (*i == obj || (*i)->getModel() == obj) {
-	    recreate = true;
-	    break;
-	}
+         i != scrollables.end(); ++i) {
+        if (*i == obj || (*i)->getModel() == obj) {
+            recreate = true;
+            break;
+        }
     }
 
     if (recreate) {
-	delete m_cache;
-	m_cache = 0;
+        delete m_cache;
+        m_cache = 0;
     }
 
     if (startFrame < myStartFrame) startFrame = myStartFrame;
@@ -945,7 +948,7 @@
     update();
 
     if (layer) {
-	emit propertyContainerPropertyChanged(layer);
+        emit propertyContainerPropertyChanged(layer);
     }
 }
 
@@ -993,7 +996,7 @@
 View::viewManagerPlaybackFrameChanged(sv_frame_t f)
 {
     if (m_manager) {
-	if (sender() != m_manager) return;
+        if (sender() != m_manager) return;
     }
 
 #ifdef DEBUG_VIEW        
@@ -1028,7 +1031,7 @@
          (QApplication::keyboardModifiers() & Qt::AltModifier));
 
     bool pointerInVisibleArea =
-	long(m_playPointerFrame) >= getStartFrame() &&
+        long(m_playPointerFrame) >= getStartFrame() &&
         (m_playPointerFrame < getEndFrame() ||
          // include old pointer location so we know to refresh when moving out
          oldPlayPointerFrame < getEndFrame());
@@ -1036,10 +1039,10 @@
     switch (m_followPlay) {
 
     case PlaybackScrollContinuous:
-	if (!somethingGoingOn) {
-	    setCentreFrame(m_playPointerFrame, false);
-	}
-	break;
+        if (!somethingGoingOn) {
+            setCentreFrame(m_playPointerFrame, false);
+        }
+        break;
 
     case PlaybackScrollPage:
     case PlaybackScrollPageWithCentre:
@@ -1114,11 +1117,11 @@
         break;
 
     case PlaybackIgnore:
-	if (m_playPointerFrame >= getStartFrame() &&
+        if (m_playPointerFrame >= getStartFrame() &&
             m_playPointerFrame < getEndFrame()) {
-	    update();
-	}
-	break;
+            update();
+        }
+        break;
     }
 }
 
@@ -1137,9 +1140,9 @@
 View::selectionChanged()
 {
     if (m_selectionCached) {
-	delete m_cache;
-	m_cache = 0;
-	m_selectionCached = false;
+        delete m_cache;
+        m_cache = 0;
+        m_selectionCached = false;
     }
     update();
 }
@@ -1170,15 +1173,15 @@
 
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
-	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
-
-	    sv_frame_t thisStartFrame = (*i)->getModel()->getStartFrame();
-
-	    if (first || thisStartFrame < startFrame) {
-		startFrame = thisStartFrame;
-	    }
-	    first = false;
-	}
+        if ((*i)->getModel() && (*i)->getModel()->isOK()) {
+
+            sv_frame_t thisStartFrame = (*i)->getModel()->getStartFrame();
+
+            if (first || thisStartFrame < startFrame) {
+                startFrame = thisStartFrame;
+            }
+            first = false;
+        }
     }
     return startFrame;
 }
@@ -1191,15 +1194,15 @@
 
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
-	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
-
-	    sv_frame_t thisEndFrame = (*i)->getModel()->getEndFrame();
-
-	    if (first || thisEndFrame > endFrame) {
-		endFrame = thisEndFrame;
-	    }
-	    first = false;
-	}
+        if ((*i)->getModel() && (*i)->getModel()->isOK()) {
+
+            sv_frame_t thisEndFrame = (*i)->getModel()->getEndFrame();
+
+            if (first || thisEndFrame > endFrame) {
+                endFrame = thisEndFrame;
+            }
+            first = false;
+        }
     }
 
     if (first) return getModelsStartFrame();
@@ -1216,9 +1219,9 @@
     //!!! nah, this wants to always return the sr of the main model!
 
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
-	if ((*i)->getModel() && (*i)->getModel()->isOK()) {
-	    return (*i)->getModel()->getSampleRate();
-	}
+        if ((*i)->getModel() && (*i)->getModel()->isOK()) {
+            return (*i)->getModel()->getSampleRate();
+        }
     }
     return 0;
 }
@@ -1323,7 +1326,7 @@
 {
     // True iff all views are scrollable
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
-	if (!(*i)->isLayerScrollable(this)) return false;
+        if (!(*i)->isLayerScrollable(this)) return false;
     }
     return true;
 }
@@ -1344,13 +1347,13 @@
 //        cerr << "(name is " << (*i)->objectName() << ")"
 //                  << endl;
 //        SVDEBUG << "View::getScrollableBackLayers: I am " << this << endl;
-	if ((*i)->isLayerDormant(this)) continue;
-	if ((*i)->isLayerOpaque()) {
-	    // You can't see anything behind an opaque layer!
-	    scrollables.clear();
+        if ((*i)->isLayerDormant(this)) continue;
+        if ((*i)->isLayerOpaque()) {
+            // You can't see anything behind an opaque layer!
+            scrollables.clear();
             if (metUnscrollable) break;
-	}
-	if (!metUnscrollable && (*i)->isLayerScrollable(this)) {
+        }
+        if (!metUnscrollable && (*i)->isLayerScrollable(this)) {
             scrollables.push_back(*i);
         } else {
             metUnscrollable = true;
@@ -1358,8 +1361,8 @@
     }
 
     if (testChanged && scrollables != m_lastScrollableBackLayers) {
-	m_lastScrollableBackLayers = scrollables;
-	changed = true;
+        m_lastScrollableBackLayers = scrollables;
+        changed = true;
     }
     return scrollables;
 }
@@ -1376,21 +1379,21 @@
     bool started = false;
 
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
-	if ((*i)->isLayerDormant(this)) continue;
-	if (!started && (*i)->isLayerScrollable(this)) {
-	    continue;
-	}
-	started = true;
-	if ((*i)->isLayerOpaque()) {
-	    // You can't see anything behind an opaque layer!
-	    nonScrollables.clear();
-	}
-	nonScrollables.push_back(*i);
+        if ((*i)->isLayerDormant(this)) continue;
+        if (!started && (*i)->isLayerScrollable(this)) {
+            continue;
+        }
+        started = true;
+        if ((*i)->isLayerOpaque()) {
+            // You can't see anything behind an opaque layer!
+            nonScrollables.clear();
+        }
+        nonScrollables.push_back(*i);
     }
 
     if (testChanged && nonScrollables != m_lastNonScrollableBackLayers) {
-	m_lastNonScrollableBackLayers = nonScrollables;
-	changed = true;
+        m_lastNonScrollableBackLayers = nonScrollables;
+        changed = true;
     }
 
     return nonScrollables;
@@ -1398,7 +1401,7 @@
 
 int
 View::getZoomConstraintBlockSize(int blockSize,
-				 ZoomConstraint::RoundingDirection dir)
+                                 ZoomConstraint::RoundingDirection dir)
     const
 {
     int candidate = blockSize;
@@ -1408,20 +1411,20 @@
 
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
 
-	const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
-	if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
-
-	int thisBlockSize =
-	    zoomConstraint->getNearestBlockSize(blockSize, dir);
-
-	// Go for the block size that's furthest from the one
-	// passed in.  Most of the time, that's what we want.
-	if (!haveCandidate ||
-	    (thisBlockSize > blockSize && thisBlockSize > candidate) ||
-	    (thisBlockSize < blockSize && thisBlockSize < candidate)) {
-	    candidate = thisBlockSize;
-	    haveCandidate = true;
-	}
+        const ZoomConstraint *zoomConstraint = (*i)->getZoomConstraint();
+        if (!zoomConstraint) zoomConstraint = &defaultZoomConstraint;
+
+        int thisBlockSize =
+            zoomConstraint->getNearestBlockSize(blockSize, dir);
+
+        // Go for the block size that's furthest from the one
+        // passed in.  Most of the time, that's what we want.
+        if (!haveCandidate ||
+            (thisBlockSize > blockSize && thisBlockSize > candidate) ||
+            (thisBlockSize < blockSize && thisBlockSize < candidate)) {
+            candidate = thisBlockSize;
+            haveCandidate = true;
+        }
     }
 
     return candidate;
@@ -1431,7 +1434,7 @@
 View::areLayerColoursSignificant() const
 {
     for (LayerList::const_iterator i = m_layerStack.begin(); i != m_layerStack.end(); ++i) {
-	if ((*i)->getLayerColourSignificance() ==
+        if ((*i)->getLayerColourSignificance() ==
             Layer::ColourHasMeaningfulValue) return true;
         if ((*i)->isLayerOpaque()) break;
     }
@@ -1453,15 +1456,15 @@
     ZoomLevel newZoomLevel = m_zoomLevel;
 
     if (in) {
-	newZoomLevel = getZoomConstraintLevel(m_zoomLevel.decremented(),
+        newZoomLevel = getZoomConstraintLevel(m_zoomLevel.decremented(),
                                               ZoomConstraint::RoundDown);
     } else {
-	newZoomLevel = getZoomConstraintLevel(m_zoomLevel.incremented(),
+        newZoomLevel = getZoomConstraintLevel(m_zoomLevel.incremented(),
                                               ZoomConstraint::RoundUp);
     }
 
     if (newZoomLevel != m_zoomLevel) {
-	setZoomLevel(newZoomLevel);
+        setZoomLevel(newZoomLevel);
     }
 }
 
@@ -1470,18 +1473,18 @@
 {
     sv_frame_t delta;
     if (lots) {
-	delta = (getEndFrame() - getStartFrame()) / 2;
+        delta = (getEndFrame() - getStartFrame()) / 2;
     } else {
-	delta = (getEndFrame() - getStartFrame()) / 20;
+        delta = (getEndFrame() - getStartFrame()) / 20;
     }
     if (right) delta = -delta;
 
     if (m_centreFrame < delta) {
-	setCentreFrame(0, e);
+        setCentreFrame(0, e);
     } else if (m_centreFrame - delta >= getModelsEndFrame()) {
-	setCentreFrame(getModelsEndFrame(), e);
+        setCentreFrame(getModelsEndFrame(), e);
     } else {
-	setCentreFrame(m_centreFrame - delta, e);
+        setCentreFrame(m_centreFrame - delta, e);
     }
 }
 
@@ -1492,7 +1495,7 @@
     if (!cancel) return;
 
     for (ProgressMap::iterator i = m_progressBars.begin();
-	 i != m_progressBars.end(); ++i) {
+         i != m_progressBars.end(); ++i) {
 
         if (i->second.cancel == cancel) {
 
@@ -1512,19 +1515,19 @@
     int ph = height();
 
     for (ProgressMap::iterator i = m_progressBars.begin();
-	 i != m_progressBars.end(); ++i) {
+         i != m_progressBars.end(); ++i) {
 
         QProgressBar *pb = i->second.bar;
         QPushButton *cancel = i->second.cancel;
 
-	if (i->first == object) {
+        if (i->first == object) {
 
             // The timer is used to test for stalls.  If the progress
             // bar does not get updated for some length of time, the
             // timer prompts it to go back into "indeterminate" mode
             QTimer *timer = i->second.checkTimer;
 
-	    int completion = i->first->getCompletion(this);
+            int completion = i->first->getCompletion(this);
             QString text = i->first->getPropertyContainerName();
             QString error = i->first->getError(this);
 
@@ -1559,13 +1562,13 @@
                 update(); // ensure duration &c gets updated
             }
 
-	    if (completion >= 100) {
-
-		pb->hide();
+            if (completion >= 100) {
+
+                pb->hide();
                 cancel->hide();
                 timer->stop();
 
-	    } else {
+            } else {
 
 //                cerr << "progress = " << completion << endl;
 
@@ -1578,19 +1581,19 @@
                 cancel->move(0, ph - pb->height()/2 - 10);
                 cancel->show();
 
-		pb->setValue(completion);
-		pb->move(20, ph - pb->height());
-
-		pb->show();
-		pb->update();
-
-		ph -= pb->height();
-	    }
-	} else {
-	    if (pb->isVisible()) {
-		ph -= pb->height();
-	    }
-	}
+                pb->setValue(completion);
+                pb->move(20, ph - pb->height());
+
+                pb->show();
+                pb->update();
+
+                ph -= pb->height();
+            }
+        } else {
+            if (pb->isVisible()) {
+                ph -= pb->height();
+            }
+        }
     }
 }
 
@@ -1617,7 +1620,7 @@
 View::getProgressBarWidth() const
 {
     for (ProgressMap::const_iterator i = m_progressBars.begin();
-	 i != m_progressBars.end(); ++i) {
+         i != m_progressBars.end(); ++i) {
         if (i->second.bar && i->second.bar->isVisible()) {
             return i->second.bar->width();
         }
@@ -1657,8 +1660,8 @@
 //    cerr << "View::paintEvent: centre frame is " << m_centreFrame << endl;
 
     if (m_layerStack.empty()) {
-	QFrame::paintEvent(e);
-	return;
+        QFrame::paintEvent(e);
+        return;
     }
 
     // ensure our constraints are met
@@ -1667,7 +1670,7 @@
   zoom levels?
 
     m_zoomLevel = getZoomConstraintBlockSize(m_zoomLevel,
-					     ZoomConstraint::RoundUp);
+                                             ZoomConstraint::RoundUp);
 */
 
     QPainter paint;
@@ -1677,10 +1680,10 @@
     QRect cacheRect(rect());
 
     if (e) {
-	cacheRect &= e->rect();
+        cacheRect &= e->rect();
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-	cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
-		  << ", my rect " << width() << "x" << height() << endl;
+        cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height()
+                  << ", my rect " << width() << "x" << height() << endl;
 #endif
     }
 
@@ -1731,17 +1734,17 @@
 
 #ifdef DEBUG_VIEW_WIDGET_PAINT
     cerr << "View(" << this << ")::paintEvent: have " << scrollables.size()
-	      << " scrollable back layers and " << nonScrollables.size()
-	      << " non-scrollable front layers" << endl;
+              << " scrollable back layers and " << nonScrollables.size()
+              << " non-scrollable front layers" << endl;
     cerr << "haveSelections " << haveSelections << ", selectionCacheable "
-	      << selectionCacheable << ", m_selectionCached " << m_selectionCached << endl;
+              << selectionCacheable << ", m_selectionCached " << m_selectionCached << endl;
 #endif
 
     if (layersChanged || scrollables.empty() ||
-	(haveSelections && (selectionCacheable != m_selectionCached))) {
-	delete m_cache;
-	m_cache = 0;
-	m_selectionCached = false;
+        (haveSelections && (selectionCacheable != m_selectionCached))) {
+        delete m_cache;
+        m_cache = 0;
+        m_selectionCached = false;
     }
 
     QSize scaledCacheSize(scaledSize(size(), dpratio));
@@ -1759,75 +1762,75 @@
                   << m_cacheZoomLevel << ", zoom " << m_zoomLevel << endl;
 #endif
 
-	if (!m_cache ||
-	    m_cacheZoomLevel != m_zoomLevel ||
+        if (!m_cache ||
+            m_cacheZoomLevel != m_zoomLevel ||
             scaledCacheSize != m_cache->size()) {
 
-	    // cache is not valid
-
-	    if (cacheRect.width() < width()/10) {
-		delete m_cache;
+            // cache is not valid
+
+            if (cacheRect.width() < width()/10) {
+                delete m_cache;
                 m_cache = 0;
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-		cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl;
+                cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << endl;
 #endif
-	    } else {
-		delete m_cache;
-		m_cache = new QPixmap(scaledCacheSize);
+            } else {
+                delete m_cache;
+                m_cache = new QPixmap(scaledCacheSize);
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-		cerr << "View(" << this << ")::paintEvent: recreated cache" << endl;
+                cerr << "View(" << this << ")::paintEvent: recreated cache" << endl;
 #endif
-		cacheRect = rect();
-		repaintCache = true;
-	    }
-
-	} else if (m_cacheCentreFrame != m_centreFrame) {
-
-	    int dx =
-		getXForFrame(m_cacheCentreFrame) -
-		getXForFrame(m_centreFrame);
-
-	    if (dx > -width() && dx < width()) {
-		static QPixmap *tmpPixmap = 0;
-		if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) {
-		    delete tmpPixmap;
-		    tmpPixmap = new QPixmap(scaledCacheSize);
-		}
-		paint.begin(tmpPixmap);
-		paint.drawPixmap(0, 0, *m_cache);
-		paint.end();
-		paint.begin(m_cache);
-		paint.drawPixmap(dx, 0, *tmpPixmap);
-		paint.end();
-		if (dx < 0) {
-		    cacheRect = QRect(width() + dx, 0, -dx, height());
-		} else {
-		    cacheRect = QRect(0, 0, dx, height());
-		}
+                cacheRect = rect();
+                repaintCache = true;
+            }
+
+        } else if (m_cacheCentreFrame != m_centreFrame) {
+
+            int dx =
+                getXForFrame(m_cacheCentreFrame) -
+                getXForFrame(m_centreFrame);
+
+            if (dx > -width() && dx < width()) {
+                static QPixmap *tmpPixmap = 0;
+                if (!tmpPixmap || tmpPixmap->size() != scaledCacheSize) {
+                    delete tmpPixmap;
+                    tmpPixmap = new QPixmap(scaledCacheSize);
+                }
+                paint.begin(tmpPixmap);
+                paint.drawPixmap(0, 0, *m_cache);
+                paint.end();
+                paint.begin(m_cache);
+                paint.drawPixmap(dx, 0, *tmpPixmap);
+                paint.end();
+                if (dx < 0) {
+                    cacheRect = QRect(width() + dx, 0, -dx, height());
+                } else {
+                    cacheRect = QRect(0, 0, dx, height());
+                }
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-		cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << endl;
+                cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << endl;
 #endif
-	    } else {
-		cacheRect = rect();
+            } else {
+                cacheRect = rect();
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-		cerr << "View(" << this << ")::paintEvent: scrolling too far" << endl;
+                cerr << "View(" << this << ")::paintEvent: scrolling too far" << endl;
 #endif
-	    }
-	    repaintCache = true;
-
-	} else {
+            }
+            repaintCache = true;
+
+        } else {
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-	    cerr << "View(" << this << ")::paintEvent: cache is good" << endl;
+            cerr << "View(" << this << ")::paintEvent: cache is good" << endl;
 #endif
-	    paint.begin(m_buffer);
-	    paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
-	    paint.end();
-	    QFrame::paintEvent(e);
-	    paintedCacheRect = true;
-	}
-
-	m_cacheCentreFrame = m_centreFrame;
-	m_cacheZoomLevel = m_zoomLevel;
+            paint.begin(m_buffer);
+            paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
+            paint.end();
+            QFrame::paintEvent(e);
+            paintedCacheRect = true;
+        }
+
+        m_cacheCentreFrame = m_centreFrame;
+        m_cacheZoomLevel = m_zoomLevel;
     }
 
 #ifdef DEBUG_VIEW_WIDGET_PAINT
@@ -1842,7 +1845,7 @@
 
         QRect rectToPaint;
 
-	if (repaintCache) {
+        if (repaintCache) {
             paint.begin(m_cache);
             rectToPaint = scaledCacheRect;
         } else {
@@ -1851,39 +1854,39 @@
         }
 
         setPaintFont(paint);
-	paint.setClipRect(rectToPaint);
+        paint.setClipRect(rectToPaint);
 
         paint.setPen(getBackground());
         paint.setBrush(getBackground());
-	paint.drawRect(rectToPaint);
-
-	paint.setPen(getForeground());
-	paint.setBrush(Qt::NoBrush);
-	
-	for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
-	    paint.setRenderHint(QPainter::Antialiasing, false);
-	    paint.save();
+        paint.drawRect(rectToPaint);
+
+        paint.setPen(getForeground());
+        paint.setBrush(Qt::NoBrush);
+        
+        for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) {
+            paint.setRenderHint(QPainter::Antialiasing, false);
+            paint.save();
 #ifdef DEBUG_VIEW_WIDGET_PAINT
             cerr << "Painting scrollable layer " << *i << " using proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << rectToPaint.x() << "," << rectToPaint.y() << " " << rectToPaint.width() << "x" << rectToPaint.height() << endl;
 #endif
             (*i)->paint(&proxy, paint, rectToPaint);
-	    paint.restore();
-	}
-
-	if (haveSelections && selectionCacheable) {
-	    drawSelections(paint);
-	    m_selectionCached = repaintCache;
-	}
-	
-	paint.end();
-
-	if (repaintCache) {
-	    cacheRect |= (e ? e->rect() : rect());
+            paint.restore();
+        }
+
+        if (haveSelections && selectionCacheable) {
+            drawSelections(paint);
+            m_selectionCached = repaintCache;
+        }
+        
+        paint.end();
+
+        if (repaintCache) {
+            cacheRect |= (e ? e->rect() : rect());
             scaledCacheRect = scaledRect(cacheRect, dpratio);
-	    paint.begin(m_buffer);
-	    paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
-	    paint.end();
-	}
+            paint.begin(m_buffer);
+            paint.drawPixmap(scaledCacheRect, *m_cache, scaledCacheRect);
+            paint.end();
+        }
     }
 
     // Now non-cacheable items.  We always need to redraw the
@@ -1900,20 +1903,20 @@
     if (scrollables.empty()) {
         paint.setPen(getBackground());
         paint.setBrush(getBackground());
-	paint.drawRect(scaledNonCacheRect);
+        paint.drawRect(scaledNonCacheRect);
     }
-	
+        
     paint.setPen(getForeground());
     paint.setBrush(Qt::NoBrush);
-	
+        
     for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) {
 //        Profiler profiler2("View::paintEvent non-cacheable");
 #ifdef DEBUG_VIEW_WIDGET_PAINT
         cerr << "Painting non-scrollable layer " << *i << " without proxy with repaintCache = " << repaintCache << ", dpratio = " << dpratio << ", rectToPaint = " << nonCacheRect.x() << "," << nonCacheRect.y() << " " << nonCacheRect.width() << "x" << nonCacheRect.height() << endl;
 #endif
-	(*i)->paint(&proxy, paint, scaledNonCacheRect);
+        (*i)->paint(&proxy, paint, scaledNonCacheRect);
     }
-	
+        
     paint.end();
     
     paint.begin(this);
@@ -1925,7 +1928,7 @@
     setPaintFont(paint);
     if (e) paint.setClipRect(e->rect());
     if (!m_selectionCached) {
-	drawSelections(paint);
+        drawSelections(paint);
     }
     paint.end();
 
@@ -1947,7 +1950,7 @@
     
     if (showPlayPointer) {
 
-	paint.begin(this);
+        paint.begin(this);
 
         int playx = getXForFrame(m_playPointerFrame);
         
@@ -1959,7 +1962,7 @@
         paint.setPen(getBackground());
         paint.drawLine(playx, 1, playx, height() - 2);
 
-	paint.end();
+        paint.end();
     }
 
     QFrame::paintEvent(e);
@@ -1973,14 +1976,14 @@
     MultiSelection::SelectionList selections;
 
     if (m_manager) {
-	selections = m_manager->getSelections();
-	if (m_manager->haveInProgressSelection()) {
-	    bool exclusive;
-	    Selection inProgressSelection =
-		m_manager->getInProgressSelection(exclusive);
-	    if (exclusive) selections.clear();
-	    selections.insert(inProgressSelection);
-	}
+        selections = m_manager->getSelections();
+        if (m_manager->haveInProgressSelection()) {
+            bool exclusive;
+            Selection inProgressSelection =
+                m_manager->getInProgressSelection(exclusive);
+            if (exclusive) selections.clear();
+            selections.insert(inProgressSelection);
+        }
     }
 
     paint.save();
@@ -2000,113 +2003,123 @@
     bool closeToLeft, closeToRight;
 
     if (shouldIlluminateLocalSelection(localPos, closeToLeft, closeToRight)) {
-	illuminateFrame = getFrameForX(localPos.x());
+        illuminateFrame = getFrameForX(localPos.x());
     }
 
     const QFontMetrics &metrics = paint.fontMetrics();
 
     for (MultiSelection::SelectionList::iterator i = selections.begin();
-	 i != selections.end(); ++i) {
-
-	int p0 = getXForFrame(alignFromReference(i->getStartFrame()));
-	int p1 = getXForFrame(alignFromReference(i->getEndFrame()));
-
-	if (p1 < 0 || p0 > width()) continue;
+         i != selections.end(); ++i) {
+
+        int p0 = getXForFrame(alignFromReference(i->getStartFrame()));
+        int p1 = getXForFrame(alignFromReference(i->getEndFrame()));
+
+        if (p1 < 0 || p0 > width()) continue;
 
 #ifdef DEBUG_VIEW_WIDGET_PAINT
-	SVDEBUG << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << endl;
+        SVDEBUG << "View::drawSelections: " << p0 << ",-1 [" << (p1-p0) << "x" << (height()+1) << "]" << endl;
 #endif
 
-	bool illuminateThis =
-	    (illuminateFrame >= 0 && i->contains(illuminateFrame));
-
-	paint.setPen(QColor(150, 150, 255));
+        bool illuminateThis =
+            (illuminateFrame >= 0 && i->contains(illuminateFrame));
+
+        double h = height();
+        double penWidth = PaintAssistant::scalePenWidth(1.0);
+        double half = penWidth/2.0;
+
+        paint.setPen(QPen(QColor(150, 150, 255), penWidth));
 
         if (translucent && shouldLabelSelections()) {
-            paint.drawRect(p0, -1, p1 - p0, height() + 1);
+            paint.drawRect(QRectF(p0, -penWidth, p1 - p0, h + 2*penWidth));
         } else {
             // Make the top & bottom lines of the box visible if we
             // are lacking some of the other visual cues.  There's no
             // particular logic to this, it's just a question of what
             // I happen to think looks nice.
-            paint.drawRect(p0, 0, p1 - p0, height() - 1);
+            paint.drawRect(QRectF(p0, half, p1 - p0, h - penWidth));
         }
 
-	if (illuminateThis) {
-	    paint.save();
-            paint.setPen(QPen(getForeground(), 2));
-	    if (closeToLeft) {
-		paint.drawLine(p0, 1, p1, 1);
-		paint.drawLine(p0, 0, p0, height());
-		paint.drawLine(p0, height() - 1, p1, height() - 1);
-	    } else if (closeToRight) {
-		paint.drawLine(p0, 1, p1, 1);
-		paint.drawLine(p1, 0, p1, height());
-		paint.drawLine(p0, height() - 1, p1, height() - 1);
-	    } else {
-		paint.setBrush(Qt::NoBrush);
-		paint.drawRect(p0, 1, p1 - p0, height() - 2);
-	    }
-	    paint.restore();
-	}
-
-	if (sampleRate && shouldLabelSelections() && m_manager &&
+        if (illuminateThis) {
+            paint.save();
+            penWidth = PaintAssistant::scalePenWidth(2.0);
+            half = penWidth/2.0;
+            paint.setPen(QPen(getForeground(), penWidth));
+            if (closeToLeft) {
+                paint.drawLine(QLineF(p0, half, p1, half));
+                paint.drawLine(QLineF(p0, half, p0, h - half));
+                paint.drawLine(QLineF(p0, h - half, p1, h - half));
+            } else if (closeToRight) {
+                paint.drawLine(QLineF(p0, half, p1, half));
+                paint.drawLine(QLineF(p1, half, p1, h - half));
+                paint.drawLine(QLineF(p0, h - half, p1, h - half));
+            } else {
+                paint.setBrush(Qt::NoBrush);
+                paint.drawRect(QRectF(p0, half, p1 - p0, h - penWidth));
+            }
+            paint.restore();
+        }
+
+        if (sampleRate && shouldLabelSelections() && m_manager &&
             m_manager->shouldShowSelectionExtents()) {
-	    
-	    QString startText = QString("%1 / %2")
-		.arg(QString::fromStdString
-		     (RealTime::frame2RealTime
-		      (i->getStartFrame(), sampleRate).toText(true)))
-		.arg(i->getStartFrame());
-	    
-	    QString endText = QString(" %1 / %2")
-		.arg(QString::fromStdString
-		     (RealTime::frame2RealTime
-		      (i->getEndFrame(), sampleRate).toText(true)))
-		.arg(i->getEndFrame());
-	    
-	    QString durationText = QString("(%1 / %2) ")
-		.arg(QString::fromStdString
-		     (RealTime::frame2RealTime
-		      (i->getEndFrame() - i->getStartFrame(), sampleRate)
-		      .toText(true)))
-		.arg(i->getEndFrame() - i->getStartFrame());
-
-	    int sw = metrics.width(startText),
-		ew = metrics.width(endText),
-		dw = metrics.width(durationText);
-
-	    int sy = metrics.ascent() + metrics.height() + 4;
-	    int ey = sy;
-	    int dy = sy + metrics.height();
-
-	    int sx = p0 + 2;
-	    int ex = sx;
-	    int dx = sx;
+            
+            QString startText = QString("%1 / %2")
+                .arg(QString::fromStdString
+                     (RealTime::frame2RealTime
+                      (i->getStartFrame(), sampleRate).toText(true)))
+                .arg(i->getStartFrame());
+            
+            QString endText = QString(" %1 / %2")
+                .arg(QString::fromStdString
+                     (RealTime::frame2RealTime
+                      (i->getEndFrame(), sampleRate).toText(true)))
+                .arg(i->getEndFrame());
+            
+            QString durationText = QString("(%1 / %2) ")
+                .arg(QString::fromStdString
+                     (RealTime::frame2RealTime
+                      (i->getEndFrame() - i->getStartFrame(), sampleRate)
+                      .toText(true)))
+                .arg(i->getEndFrame() - i->getStartFrame());
+
+            int sw = metrics.width(startText),
+                ew = metrics.width(endText),
+                dw = metrics.width(durationText);
+
+            int sy = metrics.ascent() + metrics.height() + 4;
+            int ey = sy;
+            int dy = sy + metrics.height();
+
+            int sx = p0 + 2;
+            int ex = sx;
+            int dx = sx;
 
             bool durationBothEnds = true;
 
-	    if (sw + ew > (p1 - p0)) {
-		ey += metrics.height();
-		dy += metrics.height();
+            if (sw + ew > (p1 - p0)) {
+                ey += metrics.height();
+                dy += metrics.height();
                 durationBothEnds = false;
-	    }
-
-	    if (ew < (p1 - p0)) {
-		ex = p1 - 2 - ew;
-	    }
-
-	    if (dw < (p1 - p0)) {
-		dx = p1 - 2 - dw;
-	    }
-
-	    paint.drawText(sx, sy, startText);
-	    paint.drawText(ex, ey, endText);
-	    paint.drawText(dx, dy, durationText);
+            }
+
+            if (ew < (p1 - p0)) {
+                ex = p1 - 2 - ew;
+            }
+
+            if (dw < (p1 - p0)) {
+                dx = p1 - 2 - dw;
+            }
+
+            PaintAssistant::drawVisibleText(this, paint, sx, sy, startText,
+                                            PaintAssistant::OutlinedText);
+            PaintAssistant::drawVisibleText(this, paint, ex, ey, endText,
+                                            PaintAssistant::OutlinedText);
+            PaintAssistant::drawVisibleText(this, paint, dx, dy, durationText,
+                                            PaintAssistant::OutlinedText);
             if (durationBothEnds) {
-                paint.drawText(sx, dy, durationText);
+                PaintAssistant::drawVisibleText(this, paint, sx, dy, durationText,
+                                                PaintAssistant::OutlinedText);
             }
-	}
+        }
     }
 
     paint.restore();
@@ -2424,12 +2437,12 @@
         paint.setPen(getBackground());
         paint.setBrush(getBackground());
 
-	paint.drawRect(QRect(xorigin + x, 0, width(), height()));
-
-	paint.setPen(getForeground());
-	paint.setBrush(Qt::NoBrush);
-
-	for (LayerList::iterator i = m_layerStack.begin();
+        paint.drawRect(QRect(xorigin + x, 0, width(), height()));
+
+        paint.setPen(getForeground());
+        paint.setBrush(Qt::NoBrush);
+
+        for (LayerList::iterator i = m_layerStack.begin();
              i != m_layerStack.end(); ++i) {
             if (!((*i)->isLayerDormant(this))){
 
@@ -2448,7 +2461,7 @@
 
                 paint.restore();
             }
-	}
+        }
     }
 
     m_centreFrame = origCentreFrame;
@@ -2457,16 +2470,16 @@
 }
 
 QImage *
-View::toNewImage()
+View::renderToNewImage()
 {
     sv_frame_t f0 = getModelsStartFrame();
     sv_frame_t f1 = getModelsEndFrame();
 
-    return toNewImage(f0, f1);
+    return renderPartToNewImage(f0, f1);
 }
 
 QImage *
-View::toNewImage(sv_frame_t f0, sv_frame_t f1)
+View::renderPartToNewImage(sv_frame_t f0, sv_frame_t f1)
 {
     int x0 = int(f0 / getZoomLevel());
     int x1 = int(f1 / getZoomLevel());
@@ -2485,16 +2498,16 @@
 }
 
 QSize
-View::getImageSize()
+View::getRenderedImageSize()
 {
     sv_frame_t f0 = getModelsStartFrame();
     sv_frame_t f1 = getModelsEndFrame();
 
-    return getImageSize(f0, f1);
+    return getRenderedPartImageSize(f0, f1);
 }
     
 QSize
-View::getImageSize(sv_frame_t f0, sv_frame_t f1)
+View::getRenderedPartImageSize(sv_frame_t f0, sv_frame_t f1)
 {
     int x0 = int(f0 / getZoomLevel());
     int x1 = int(f1 / getZoomLevel());
@@ -2502,6 +2515,35 @@
     return QSize(x1 - x0, height());
 }
 
+bool
+View::renderToSvgFile(QString filename)
+{
+    sv_frame_t f0 = getModelsStartFrame();
+    sv_frame_t f1 = getModelsEndFrame();
+
+    return renderPartToSvgFile(filename, f0, f1);
+}
+
+bool
+View::renderPartToSvgFile(QString filename, sv_frame_t f0, sv_frame_t f1)
+{
+    int x0 = int(f0 / getZoomLevel());
+    int x1 = int(f1 / getZoomLevel());
+
+    QSvgGenerator generator;
+    generator.setFileName(filename);
+    generator.setSize(QSize(x1 - x0, height()));
+    generator.setViewBox(QRect(0, 0, x1 - x0, height()));
+    generator.setTitle(tr("Exported image from %1")
+                       .arg(QApplication::applicationName()));
+    
+    QPainter paint;
+    paint.begin(&generator);
+    bool result = render(paint, 0, f0, f1);
+    paint.end();
+    return result;
+}
+
 void
 View::toXml(QTextStream &stream,
             QString indent, QString extraAttributes) const
@@ -2515,15 +2557,15 @@
                       "followZoom=\"%4\" "
                       "tracking=\"%5\" "
                       " %6>\n")
-	.arg(m_centreFrame)
-	.arg(m_zoomLevel)
-	.arg(m_followPan)
-	.arg(m_followZoom)
-	.arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
-	     m_followPlay == PlaybackScrollPageWithCentre ? "page" :
-	     m_followPlay == PlaybackScrollPage ? "daw" :
+        .arg(m_centreFrame)
+        .arg(m_zoomLevel)
+        .arg(m_followPan)
+        .arg(m_followZoom)
+        .arg(m_followPlay == PlaybackScrollContinuous ? "scroll" :
+             m_followPlay == PlaybackScrollPageWithCentre ? "page" :
+             m_followPlay == PlaybackScrollPage ? "daw" :
              "ignore")
-	.arg(extraAttributes);
+        .arg(extraAttributes);
 
     for (int i = 0; i < (int)m_fixedOrderLayers.size(); ++i) {
         bool visible = !m_fixedOrderLayers[i]->isLayerDormant(this);
@@ -2540,7 +2582,7 @@
 {
 //    cerr << "ViewPropertyContainer: " << this << " is owned by View " << v << endl;
     connect(m_v, SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
-	    this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
+            this, SIGNAL(propertyChanged(PropertyContainer::PropertyName)));
 }
 
 ViewPropertyContainer::~ViewPropertyContainer()