changeset 261:11021509c4eb

* some more work on measurement tool, and refactor Pane::paintEvent
author Chris Cannam
date Thu, 14 Jun 2007 16:28:27 +0000
parents 6d113226bb4c
children dae479593572
files layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h view/Pane.cpp view/Pane.h
diffstat 6 files changed, 508 insertions(+), 344 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Thu Jun 14 15:20:49 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Thu Jun 14 16:28:27 2007 +0000
@@ -2469,6 +2469,15 @@
 }
 
 bool
+SpectrogramLayer::getYScaleValue(View *v, int y,
+                                 float &value, QString &unit) const
+{
+    value = getFrequencyForY(v, y);
+    unit = "Hz";
+    return true;
+}
+
+bool
 SpectrogramLayer::snapToFeatureFrame(View *, int &frame,
 				     size_t &resolution,
 				     SnapType snap) const
--- a/layer/SpectrogramLayer.h	Thu Jun 14 15:20:49 2007 +0000
+++ b/layer/SpectrogramLayer.h	Thu Jun 14 16:28:27 2007 +0000
@@ -200,6 +200,8 @@
 
     virtual bool setDisplayExtents(float min, float max);
 
+    virtual bool getYScaleValue(View *, int, float &, QString &) const;
+
     virtual QString toXmlString(QString indent = "",
 				QString extraAttributes = "") const;
 
--- a/layer/WaveformLayer.cpp	Thu Jun 14 15:20:49 2007 +0000
+++ b/layer/WaveformLayer.cpp	Thu Jun 14 16:28:27 2007 +0000
@@ -388,7 +388,6 @@
 int
 WaveformLayer::dBscale(float sample, int m) const
 {
-//!!!    if (sample < 0.0) return -dBscale(-sample, m);
     if (sample < 0.0) return dBscale(-sample, m);
     float dB = AudioLevel::multiplier_to_dB(sample);
     if (dB < -50.0) return 0;
@@ -1033,6 +1032,75 @@
     return my - vy;
 }
 
+float
+WaveformLayer::getValueForY(View *v, Scale scale, int y,
+                            size_t minChannel, size_t maxChannel) const
+{
+    if (maxChannel < minChannel) return 0;
+
+    int h = v->height();
+
+    int channels = maxChannel - minChannel + 1;
+    int m = (h / channels) / 2;
+
+    if ((m_scale == dBScale || m_scale == MeterScale) &&
+        m_channelMode != MergeChannels) {
+        m = (h / channels);
+    }
+    
+    int channel = minChannel;
+    int mind = 0;
+
+    for (int c = minChannel; c <= maxChannel; ++c) {
+        int my = m + (((c - minChannel) * h) / channels);
+        int d = y - my;
+        if (d < 0) d = -d;
+        if (c == minChannel || d < mind) {
+            mind = d;
+            channel = c;
+        }
+    }
+	
+    int my = m + (((channel - minChannel) * h) / channels);
+
+    int vy = y - my;
+    float value = 0;
+
+    switch (scale) {
+
+    case LinearScale:
+        value = float(vy) / m;
+        break;
+
+    case MeterScale:
+        value = AudioLevel::preview_to_multiplier(vy, m);
+        break;
+
+    case dBScale:
+        value = AudioLevel::dB_to_multiplier((50 * float(vy)) / m - 50);
+        break;
+    }
+
+    return value;
+}
+
+bool
+WaveformLayer::getYScaleValue(View *v, int y,
+                              float &value, QString &unit) const
+{
+    size_t channels = 0, minChannel = 0, maxChannel = 0;
+    bool mergingChannels = false, mixingChannels = false;
+
+    channels = getChannelArrangement(minChannel, maxChannel,
+                                     mergingChannels, mixingChannels);
+
+    if (channels == 0) return false;
+
+    value = getValueForY(v, m_scale, y, minChannel, maxChannel);
+    unit = "V";
+    return true;
+}
+
 int
 WaveformLayer::getVerticalScaleWidth(View *, QPainter &paint) const
 {
--- a/layer/WaveformLayer.h	Thu Jun 14 15:20:49 2007 +0000
+++ b/layer/WaveformLayer.h	Thu Jun 14 16:28:27 2007 +0000
@@ -179,6 +179,9 @@
     virtual bool getValueExtents(float &min, float &max,
                                  bool &log, QString &unit) const;
 
+    virtual bool getYScaleValue(View *v, int y,
+                                float &value, QString &unit) const;
+
     virtual QString toXmlString(QString indent = "",
 				QString extraAttributes = "") const;
 
@@ -200,6 +203,9 @@
     int getYForValue(View *v, Scale scale, float value, size_t channel,
                      size_t minChannel, size_t maxChannel) const;
 
+    float getValueForY(View *v, Scale scale, int y,
+                       size_t minChannel, size_t maxChannel) const;
+
     float        m_gain;
     bool         m_autoNormalize;
     QColor       m_colour;
--- a/view/Pane.cpp	Thu Jun 14 15:20:49 2007 +0000
+++ b/view/Pane.cpp	Thu Jun 14 16:28:27 2007 +0000
@@ -360,35 +360,13 @@
     QPainter paint;
 
     QRect r(rect());
+    if (e) r = e->rect();
 
-    if (e) {
-	r = e->rect();
-    }
-/*
-    paint.begin(this);
-    paint.setClipRect(r);
-
-    if (hasLightBackground()) {
-	paint.setPen(Qt::white);
-	paint.setBrush(Qt::white);
-    } else {
-	paint.setPen(Qt::black);
-	paint.setBrush(Qt::black);
-    }
-    paint.drawRect(r);
-
-    paint.end();
-*/
     View::paintEvent(e);
 
     paint.begin(this);
 
-    if (e) {
-	paint.setClipRect(r);
-    }
-
-    int fontHeight = paint.fontMetrics().height();
-    int fontAscent = paint.fontMetrics().ascent();
+    if (e) paint.setClipRect(r);
 
     ViewManager::ToolMode toolMode = m_manager->getToolMode();
 
@@ -422,80 +400,138 @@
         }
     }
 
+    m_scaleWidth = 0;
+
+    if (m_manager && m_manager->shouldShowVerticalScale() && topLayer) {
+        drawVerticalScale(r, topLayer, paint);
+    }
+
+    if (m_identifyFeatures && topLayer) {
+        drawFeatureDescription(topLayer, paint);
+    }
+    
+    int sampleRate = getModelsSampleRate();
+    paint.setBrush(Qt::NoBrush);
+
+    if (m_centreLineVisible &&
+        m_manager &&
+        m_manager->shouldShowCentreLine()) {
+        drawCentreLine(sampleRate, paint);
+    }
+    
+    paint.setPen(QColor(50, 50, 50));
+
+    if (waveformModel &&
+        m_manager &&
+        m_manager->shouldShowDuration()) {
+        drawDurationAndRate(r, waveformModel, sampleRate, paint);
+    }
+
+    if (m_manager &&
+        m_manager->shouldShowLayerNames()) {
+        drawLayerNames(r, paint);
+    }
+
+    if (m_clickedInRange && m_manager) {
+
+        //!!! be nice if this looked a bit more in keeping with the
+        //selection block
+
+        if (m_shiftPressed && toolMode == ViewManager::NavigateMode) {
+
+	    paint.setPen(Qt::blue);
+            //!!! shouldn't use clickPos -- needs to use a clicked frame
+	    paint.drawRect(m_clickPos.x(), m_clickPos.y(),
+			   m_mousePos.x() - m_clickPos.x(),
+			   m_mousePos.y() - m_clickPos.y());
+
+        } else if (toolMode == ViewManager::MeasureMode && topLayer) {
+
+            drawMeasurementRect(topLayer, paint);
+	}
+    }
+    
+    if (selectionIsBeingEdited()) {
+        drawEditingSelection(paint);
+    }
+
+    paint.end();
+}
+
+void
+Pane::drawVerticalScale(QRect r, Layer *topLayer, QPainter &paint)
+{
     Layer *scaleLayer = 0;
 
-    if (m_manager && m_manager->shouldShowVerticalScale() && topLayer) {
+    float min, max;
+    bool log;
+    QString unit;
 
-        float min, max;
-        bool log;
-        QString unit;
+    // If the top layer has no scale and reports no display
+    // extents, but does report a unit, then the scale should be
+    // drawn from any underlying layer with a scale and that unit.
+    // If the top layer has no scale and no value extents at all,
+    // then the scale should be drawn from any underlying layer
+    // with a scale regardless of unit.
 
-        // If the top layer has no scale and reports no display
-        // extents, but does report a unit, then the scale should be
-        // drawn from any underlying layer with a scale and that unit.
-        // If the top layer has no scale and no value extents at all,
-        // then the scale should be drawn from any underlying layer
-        // with a scale regardless of unit.
+    int sw = topLayer->getVerticalScaleWidth(this, paint);
 
-        int sw = topLayer->getVerticalScaleWidth(this, paint);
+    if (sw > 0) {
+        scaleLayer = topLayer;
+        m_scaleWidth = sw;
 
-        if (sw > 0) {
-            scaleLayer = topLayer;
-            m_scaleWidth = sw;
+    } else {
 
-        } else {
+        bool hasDisplayExtents = topLayer->getDisplayExtents(min, max);
+        bool hasValueExtents = topLayer->getValueExtents(min, max, log, unit);
+            
+        if (!hasDisplayExtents) {
 
-            bool hasDisplayExtents = topLayer->getDisplayExtents(min, max);
-            bool hasValueExtents = topLayer->getValueExtents(min, max, log, unit);
-            
-            if (!hasDisplayExtents) {
+            if (!hasValueExtents) {
 
-                if (!hasValueExtents) {
+                for (LayerList::iterator vi = m_layers.end();
+                     vi != m_layers.begin(); ) {
+                        
+                    --vi;
+                        
+                    if ((*vi) == topLayer) continue;
+                        
+                    sw = (*vi)->getVerticalScaleWidth(this, paint);
+                        
+                    if (sw > 0) {
+                        scaleLayer = *vi;
+                        m_scaleWidth = sw;
+                        break;
+                    }
+                }
+            } else if (unit != "") { // && hasValueExtents && !hasDisplayExtents
 
-                    for (LayerList::iterator vi = m_layers.end();
-                         vi != m_layers.begin(); ) {
+                QString requireUnit = unit;
+
+                for (LayerList::iterator vi = m_layers.end();
+                     vi != m_layers.begin(); ) {
                         
-                        --vi;
+                    --vi;
                         
-                        if ((*vi) == topLayer) continue;
+                    if ((*vi) == topLayer) continue;
                         
-                        sw = (*vi)->getVerticalScaleWidth(this, paint);
-                        
-                        if (sw > 0) {
-                            scaleLayer = *vi;
-                            m_scaleWidth = sw;
-                            break;
+                    if ((*vi)->getDisplayExtents(min, max)) {
+                            
+                        // search no further than this: if the
+                        // scale from this layer isn't suitable,
+                        // we'll have to draw no scale (else we'd
+                        // risk ending up with the wrong scale)
+                            
+                        if ((*vi)->getValueExtents(min, max, log, unit) &&
+                            unit == requireUnit) {
+
+                            sw = (*vi)->getVerticalScaleWidth(this, paint);
+                            if (sw > 0) {
+                                scaleLayer = *vi;
+                                m_scaleWidth = sw;
+                            }
                         }
-                    }
-                } else if (unit != "") { // && hasValueExtents && !hasDisplayExtents
-
-                    QString requireUnit = unit;
-
-                    for (LayerList::iterator vi = m_layers.end();
-                         vi != m_layers.begin(); ) {
-                        
-                        --vi;
-                        
-                        if ((*vi) == topLayer) continue;
-                        
-                        if ((*vi)->getDisplayExtents(min, max)) {
-                            
-                            // search no further than this: if the
-                            // scale from this layer isn't suitable,
-                            // we'll have to draw no scale (else we'd
-                            // risk ending up with the wrong scale)
-                            
-                            if ((*vi)->getValueExtents(min, max, log, unit) &&
-                                unit == requireUnit) {
-
-                                sw = (*vi)->getVerticalScaleWidth(this, paint);
-                                if (sw > 0) {
-                                    scaleLayer = *vi;
-                                    m_scaleWidth = sw;
-                                }
-                            }
-                            break;
-                        }
+                        break;
                     }
                 }
             }
@@ -521,306 +557,341 @@
         
         paint.restore();
     }
+}
+            
+void
+Pane::drawFeatureDescription(Layer *topLayer, QPainter &paint)
+{
+    QPoint pos = m_identifyPoint;
+    QString desc = topLayer->getFeatureDescription(this, pos);
+	    
+    if (desc != "") {
+        
+        paint.save();
+        
+        int tabStop =
+            paint.fontMetrics().width(tr("Some lengthy prefix:"));
+        
+        QRect boundingRect = 
+            paint.fontMetrics().boundingRect
+            (rect(),
+             Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
+             desc, tabStop);
+        
+        if (hasLightBackground()) {
+            paint.setPen(Qt::NoPen);
+            paint.setBrush(QColor(250, 250, 250, 200));
+        } else {
+            paint.setPen(Qt::NoPen);
+            paint.setBrush(QColor(50, 50, 50, 200));
+        }
+        
+        int extra = paint.fontMetrics().descent();
+        paint.drawRect(width() - boundingRect.width() - 10 - extra,
+                       10 - extra,
+                       boundingRect.width() + 2 * extra,
+                       boundingRect.height() + extra);
+        
+        if (hasLightBackground()) {
+            paint.setPen(QColor(150, 20, 0));
+        } else {
+            paint.setPen(QColor(255, 150, 100));
+        }
+        
+        QTextOption option;
+        option.setWrapMode(QTextOption::NoWrap);
+        option.setAlignment(Qt::AlignRight | Qt::AlignTop);
+        option.setTabStop(tabStop);
+        paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
+                              boundingRect.width(),
+                              boundingRect.height()),
+                       desc,
+                       option);
+        
+        paint.restore();
+    }
+}
 
-    if (m_identifyFeatures && topLayer) {
+void
+Pane::drawCentreLine(int sampleRate, QPainter &paint)
+{
+    int fontHeight = paint.fontMetrics().height();
+    int fontAscent = paint.fontMetrics().ascent();
+
+    QColor c = QColor(0, 0, 0);
+    if (!hasLightBackground()) {
+        c = QColor(240, 240, 240);
+    }
+    paint.setPen(c);
+    int x = width() / 2 + 1;
+    paint.drawLine(x, 0, x, height() - 1);
+    paint.drawLine(x-1, 1, x+1, 1);
+    paint.drawLine(x-2, 0, x+2, 0);
+    paint.drawLine(x-1, height() - 2, x+1, height() - 2);
+    paint.drawLine(x-2, height() - 1, x+2, height() - 1);
+    
+    paint.setPen(QColor(50, 50, 50));
+    
+    int y = height() - fontHeight + fontAscent - 6;
+    
+    LayerList::iterator vi = m_layers.end();
+    
+    if (vi != m_layers.begin()) {
+	    
+        switch ((*--vi)->getPreferredFrameCountPosition()) {
             
-        QPoint pos = m_identifyPoint;
-        QString desc = topLayer->getFeatureDescription(this, pos);
-	    
-        if (desc != "") {
+        case Layer::PositionTop:
+            y = fontAscent + 6;
+            break;
             
-            paint.save();
+        case Layer::PositionMiddle:
+            y = (height() - fontHeight) / 2
+                + fontAscent;
+            break;
             
-            int tabStop =
-                paint.fontMetrics().width(tr("Some lengthy prefix:"));
-            
-            QRect boundingRect = 
-                paint.fontMetrics().boundingRect
-                (rect(),
-                 Qt::AlignRight | Qt::AlignTop | Qt::TextExpandTabs,
-                 desc, tabStop);
-            
-            if (hasLightBackground()) {
-                paint.setPen(Qt::NoPen);
-                paint.setBrush(QColor(250, 250, 250, 200));
-            } else {
-                paint.setPen(Qt::NoPen);
-                paint.setBrush(QColor(50, 50, 50, 200));
-            }
-            
-            int extra = paint.fontMetrics().descent();
-            paint.drawRect(width() - boundingRect.width() - 10 - extra,
-                           10 - extra,
-                           boundingRect.width() + 2 * extra,
-                           boundingRect.height() + extra);
-            
-            if (hasLightBackground()) {
-                paint.setPen(QColor(150, 20, 0));
-            } else {
-                paint.setPen(QColor(255, 150, 100));
-            }
-            
-            QTextOption option;
-            option.setWrapMode(QTextOption::NoWrap);
-            option.setAlignment(Qt::AlignRight | Qt::AlignTop);
-            option.setTabStop(tabStop);
-            paint.drawText(QRectF(width() - boundingRect.width() - 10, 10,
-                                  boundingRect.width(),
-                                  boundingRect.height()),
-                           desc,
-                           option);
-            
-            paint.restore();
+        case Layer::PositionBottom:
+            // y already set correctly
+            break;
         }
     }
     
-    int sampleRate = getModelsSampleRate();
-    paint.setBrush(Qt::NoBrush);
+    if (m_manager && m_manager->shouldShowFrameCount()) {
+        
+        if (sampleRate) {
 
-    if (m_centreLineVisible &&
-        m_manager &&
-        m_manager->shouldShowCentreLine()) {
-
-        QColor c = QColor(0, 0, 0);
-        if (!hasLightBackground()) {
-            c = QColor(240, 240, 240);
-        }
-        paint.setPen(c);
-        int x = width() / 2 + 1;
-	paint.drawLine(x, 0, x, height() - 1);
-        paint.drawLine(x-1, 1, x+1, 1);
-        paint.drawLine(x-2, 0, x+2, 0);
-        paint.drawLine(x-1, height() - 2, x+1, height() - 2);
-        paint.drawLine(x-2, height() - 1, x+2, height() - 1);
-
-	paint.setPen(QColor(50, 50, 50));
-
-	int y = height() - fontHeight
-	    + fontAscent - 6;
-	
-	LayerList::iterator vi = m_layers.end();
-	
-	if (vi != m_layers.begin()) {
-	    
-	    switch ((*--vi)->getPreferredFrameCountPosition()) {
-		
-	    case Layer::PositionTop:
-		y = fontAscent + 6;
-		break;
-		
-	    case Layer::PositionMiddle:
-		y = (height() - fontHeight) / 2
-		    + fontAscent;
-		break;
-
-	    case Layer::PositionBottom:
-		// y already set correctly
-		break;
-	    }
-	}
-
-        if (m_manager && m_manager->shouldShowFrameCount()) {
-
-            if (sampleRate) {
-
-                QString text(QString::fromStdString
-                             (RealTime::frame2RealTime
-                              (m_centreFrame, sampleRate).toText(true)));
-                
-                int tw = paint.fontMetrics().width(text);
-                int x = width()/2 - 4 - tw;
-                
-                drawVisibleText(paint, x, y, text, OutlinedText);
-            }
+            QString text(QString::fromStdString
+                         (RealTime::frame2RealTime
+                          (m_centreFrame, sampleRate).toText(true)));
             
-            QString text = QString("%1").arg(m_centreFrame);
-            
-            int x = width()/2 + 4;
+            int tw = paint.fontMetrics().width(text);
+            int x = width()/2 - 4 - tw;
             
             drawVisibleText(paint, x, y, text, OutlinedText);
         }
+        
+        QString text = QString("%1").arg(m_centreFrame);
+        
+        int x = width()/2 + 4;
+        
+        drawVisibleText(paint, x, y, text, OutlinedText);
+    }
+}
 
-    } else {
+void
+Pane::drawLayerNames(QRect r, QPainter &paint)
+{
+    int fontHeight = paint.fontMetrics().height();
+    int fontAscent = paint.fontMetrics().ascent();
 
-	paint.setPen(QColor(50, 50, 50));
+    if (r.y() + r.height() < height() - int(m_layers.size()) * fontHeight - 6) {
+        return;
     }
 
-    if (waveformModel &&
-        m_manager &&
-        m_manager->shouldShowDuration() &&
-	r.y() + r.height() >= height() - fontHeight - 6) {
+    std::vector<QString> texts;
+    int maxTextWidth = 0;
 
-        size_t modelRate = waveformModel->getSampleRate();
-	size_t playbackRate = m_manager->getPlaybackSampleRate();
-        size_t outputRate = m_manager->getOutputSampleRate();
+    for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
         
-	QString srNote = "";
+        QString text = (*i)->getLayerPresentationName();
+        int tw = paint.fontMetrics().width(text);
+        bool reduced = false;
+        while (tw > width() / 3 && text.length() > 4) {
+            if (!reduced && text.length() > 8) {
+                text = text.left(text.length() - 4);
+            } else {
+                text = text.left(text.length() - 2);
+            }
+            reduced = true;
+            tw = paint.fontMetrics().width(text + "...");
+        }
+        if (reduced) {
+            texts.push_back(text + "...");
+        } else {
+            texts.push_back(text);
+        }
+        if (tw > maxTextWidth) maxTextWidth = tw;
+    }
+    
+    int lly = height() - 6;
+    int llx = width() - maxTextWidth - 5;
+    
+    if (m_manager->getZoomWheelsEnabled()) {
+        lly -= 20;
+        llx -= 36;
+    }
+    
+    if (r.x() + r.width() >= llx) {
+	
+        for (size_t i = 0; i < texts.size(); ++i) {
+            
+            if (i + 1 == texts.size()) {
+                paint.setPen(Qt::black);
+            }
+            
+            drawVisibleText(paint, llx,
+                            lly - fontHeight + fontAscent,
+                            texts[i], OutlinedText);
+            
+            lly -= fontHeight;
+        }
+    }
+}
 
-	// Show (R) for waveform models that will be resampled on
-	// playback, and (X) for waveform models that will be played
-	// at the wrong rate because their rate differs from the
-	// current playback rate (which is not necessarily that of the
-	// main model).
+void
+Pane::drawMeasurementRect(Layer *topLayer, QPainter &paint)
+{
+    int fontHeight = paint.fontMetrics().height();
+    int fontAscent = paint.fontMetrics().ascent();
 
-        if (playbackRate != 0) {
-            if (modelRate == playbackRate) {
-                if (modelRate != outputRate) srNote = " " + tr("(R)");
-            } else {
-                srNote = " " + tr("(X)");
-            }
-        }
+    float v0, v1;
+    QString u0, u1;
+    bool b0, b1;
 
-	QString desc = tr("%1 / %2Hz%3")
-	    .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
-					  sampleRate)
-		 .toText(false).c_str())
-	    .arg(modelRate)
-	    .arg(srNote);
-
-	if (r.x() < m_scaleWidth + 5 + paint.fontMetrics().width(desc)) {
-	    drawVisibleText(paint, m_scaleWidth + 5,
-			    height() - fontHeight + fontAscent - 6,
-			    desc, OutlinedText);
-	}
+    QString axs, ays, bxs, bys, dxs, dys;
+    
+    if ((b0 = topLayer->getXScaleValue(this, m_clickPos.x(), v0, u0))) {
+        axs = QString("%1 %2").arg(v0).arg(u0);
+    }
+    
+    if ((b1 = topLayer->getXScaleValue(this, m_mousePos.x(), v1, u1))) {
+        bxs = QString("%1 %2").arg(v1).arg(u1);
+    }
+    
+    if (b0 && b1 && u0 == u1) {
+        dxs = QString("(%1 %2)").arg(v1 - v0).arg(u1);
+    }
+    
+    if ((b0 = topLayer->getYScaleValue(this, m_clickPos.y(), v0, u0))) {
+        ays = QString("%1 %2").arg(v0).arg(u0);
+    }
+    
+    if ((b1 = topLayer->getYScaleValue(this, m_mousePos.y(), v1, u1))) {
+        bys = QString("%1 %2").arg(v1).arg(u1);
+    }
+    
+    if (b0 && b1 && u0 == u1) {
+        dys = QString("(%1 %2)").arg(v1 - v0).arg(u1);
+    }
+    
+    int x = m_clickPos.x() + 2;
+    int y = m_clickPos.y() + fontAscent + 2;
+    
+    if (axs != "") {
+        drawVisibleText(paint, x, y, axs, OutlinedText);
+        y += fontHeight;
+    }
+    
+    if (ays != "") {
+        drawVisibleText(paint, x, y, ays, OutlinedText);
+        y += fontHeight;
     }
 
-    if (m_manager &&
-        m_manager->shouldShowLayerNames() &&
-        r.y() + r.height() >= height() - int(m_layers.size()) * fontHeight - 6) {
+    x = m_mousePos.x() - paint.fontMetrics().width(bxs) - 2;
+    y = m_mousePos.y() - 2;
 
-	std::vector<QString> texts;
-	int maxTextWidth = 0;
-
-	for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
-
-	    QString text = (*i)->getLayerPresentationName();
-	    int tw = paint.fontMetrics().width(text);
-            bool reduced = false;
-            while (tw > width() / 3 && text.length() > 4) {
-                if (!reduced && text.length() > 8) {
-                    text = text.left(text.length() - 4);
-                } else {
-                    text = text.left(text.length() - 2);
-                }
-                reduced = true;
-                tw = paint.fontMetrics().width(text + "...");
-            }
-            if (reduced) {
-                texts.push_back(text + "...");
-            } else {
-                texts.push_back(text);
-            }
-	    if (tw > maxTextWidth) maxTextWidth = tw;
-	}
+    if (bys != "" && bxs != "") y -= fontHeight;
     
-	int lly = height() - 6;
-        int llx = width() - maxTextWidth - 5;
-
-        if (m_manager->getZoomWheelsEnabled()) {
-            lly -= 20;
-            llx -= 36;
-        }
-
-	if (r.x() + r.width() >= llx) {
-	    
-	    for (size_t i = 0; i < texts.size(); ++i) {
-
-		if (i + 1 == texts.size()) {
-		    paint.setPen(Qt::black);
-		}
-		
-		drawVisibleText(paint, llx,
-				lly - fontHeight + fontAscent,
-				texts[i], OutlinedText);
-		
-		lly -= fontHeight;
-	    }
-	}
+    if (bxs != "") {
+        drawVisibleText(paint, x, y, bxs, OutlinedText);
+        y += fontHeight;
     }
 
-    if (m_clickedInRange && m_manager) {
+    x = m_mousePos.x() - paint.fontMetrics().width(bys) - 2;
 
-        //!!! be nice if this looked a bit more in keeping with the
-        //selection block
+    if (bys != "") {
+        drawVisibleText(paint, x, y, bys, OutlinedText);
+        y += fontHeight;
+    }
 
-        if (m_shiftPressed && toolMode == ViewManager::NavigateMode) {
+    paint.save();
+    
+    paint.setPen(Qt::green);
 
-	    paint.setPen(Qt::blue);
-            //!!! shouldn't use clickPos -- needs to use a clicked frame
-	    paint.drawRect(m_clickPos.x(), m_clickPos.y(),
-			   m_mousePos.x() - m_clickPos.x(),
-			   m_mousePos.y() - m_clickPos.y());
+    paint.drawRect(m_clickPos.x(), m_clickPos.y(),
+                   m_mousePos.x() - m_clickPos.x(),
+                   m_mousePos.y() - m_clickPos.y());
 
-        } else if (toolMode == ViewManager::MeasureMode && topLayer) {
+    paint.restore();
+}
 
-            float v0, v1;
-            QString u0, u1;
-            bool b0, b1;
-
-            if ((b0 = topLayer->getXScaleValue(this, m_clickPos.x(), v0, u0))) {
-                drawVisibleText(paint,
-                                m_clickPos.x() + 2,
-                                m_clickPos.y() + fontAscent + 2,
-                                QString("%1 %2").arg(v0).arg(u0),
-                                OutlinedText);
-
-                if ((b1 = topLayer->getXScaleValue(this, m_mousePos.x(), v1, u1))
-                    && u1 == u0) {
-                    QString t = QString("%1 %2").arg(v1 - v0).arg(u1);
-                    drawVisibleText(paint,
-                                    m_mousePos.x() - paint.fontMetrics().width(t) - 2,
-                                    m_mousePos.y() - 2,
-                                    t,
-                                    OutlinedText);
-                }
-            }
-
-	    paint.setPen(Qt::green);
-
-            //!!! shouldn't use clickPos -- needs to use a clicked frame
-	    paint.drawRect(m_clickPos.x(), m_clickPos.y(),
-			   m_mousePos.x() - m_clickPos.x(),
-			   m_mousePos.y() - m_clickPos.y());
-	}
+void
+Pane::drawEditingSelection(QPainter &paint)
+{
+    int offset = m_mousePos.x() - m_clickPos.x();
+    int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
+    int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
+    
+    if (m_editingSelectionEdge < 0) {
+        p1 = getXForFrame(m_editingSelection.getEndFrame());
+    } else if (m_editingSelectionEdge > 0) {
+        p0 = getXForFrame(m_editingSelection.getStartFrame());
     }
     
-    if (selectionIsBeingEdited()) {
+    paint.save();
+    if (hasLightBackground()) {
+        paint.setPen(QPen(Qt::black, 2));
+    } else {
+        paint.setPen(QPen(Qt::white, 2));
+    }
+    
+    //!!! duplicating display policy with View::drawSelections
+    
+    if (m_editingSelectionEdge < 0) {
+        paint.drawLine(p0, 1, p1, 1);
+        paint.drawLine(p0, 0, p0, height());
+        paint.drawLine(p0, height() - 1, p1, height() - 1);
+    } else if (m_editingSelectionEdge > 0) {
+        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();
+}
 
-	int offset = m_mousePos.x() - m_clickPos.x();
-	int p0 = getXForFrame(m_editingSelection.getStartFrame()) + offset;
-	int p1 = getXForFrame(m_editingSelection.getEndFrame()) + offset;
+void
+Pane::drawDurationAndRate(QRect r, const Model *waveformModel,
+                          int sampleRate, QPainter &paint)
+{
+    int fontHeight = paint.fontMetrics().height();
+    int fontAscent = paint.fontMetrics().ascent();
 
-	if (m_editingSelectionEdge < 0) {
-	    p1 = getXForFrame(m_editingSelection.getEndFrame());
-	} else if (m_editingSelectionEdge > 0) {
-	    p0 = getXForFrame(m_editingSelection.getStartFrame());
-	}
+    if (r.y() + r.height() < height() - fontHeight - 6) return;
 
-	paint.save();
-	if (hasLightBackground()) {
-	    paint.setPen(QPen(Qt::black, 2));
-	} else {
-	    paint.setPen(QPen(Qt::white, 2));
-	}
+    size_t modelRate = waveformModel->getSampleRate();
+    size_t playbackRate = m_manager->getPlaybackSampleRate();
+    size_t outputRate = m_manager->getOutputSampleRate();
+        
+    QString srNote = "";
 
-	//!!! duplicating display policy with View::drawSelections
+    // Show (R) for waveform models that will be resampled on
+    // playback, and (X) for waveform models that will be played
+    // at the wrong rate because their rate differs from the
+    // current playback rate (which is not necessarily that of the
+    // main model).
 
-	if (m_editingSelectionEdge < 0) {
-	    paint.drawLine(p0, 1, p1, 1);
-	    paint.drawLine(p0, 0, p0, height());
-	    paint.drawLine(p0, height() - 1, p1, height() - 1);
-	} else if (m_editingSelectionEdge > 0) {
-	    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 (playbackRate != 0) {
+        if (modelRate == playbackRate) {
+            if (modelRate != outputRate) srNote = " " + tr("(R)");
+        } else {
+            srNote = " " + tr("(X)");
+        }
     }
 
-    paint.end();
+    QString desc = tr("%1 / %2Hz%3")
+        .arg(RealTime::frame2RealTime(waveformModel->getEndFrame(),
+                                      sampleRate)
+             .toText(false).c_str())
+        .arg(modelRate)
+        .arg(srNote);
+
+    if (r.x() < m_scaleWidth + 5 + paint.fontMetrics().width(desc)) {
+        drawVisibleText(paint, m_scaleWidth + 5,
+                        height() - fontHeight + fontAscent - 6,
+                        desc, OutlinedText);
+    }
 }
 
 bool
--- a/view/Pane.h	Thu Jun 14 15:20:49 2007 +0000
+++ b/view/Pane.h	Thu Jun 14 16:28:27 2007 +0000
@@ -88,6 +88,14 @@
     virtual void wheelEvent(QWheelEvent *e);
     virtual void resizeEvent(QResizeEvent *e);
 
+    void drawVerticalScale(QRect r, Layer *, QPainter &);
+    void drawFeatureDescription(Layer *, QPainter &);
+    void drawCentreLine(int, QPainter &);
+    void drawDurationAndRate(QRect, const Model *, int, QPainter &);
+    void drawLayerNames(QRect, QPainter &);
+    void drawMeasurementRect(Layer *, QPainter &);
+    void drawEditingSelection(QPainter &);
+
     virtual bool render(QPainter &paint, int x0, size_t f0, size_t f1);
 
     Selection getSelectionAt(int x, bool &closeToLeft, bool &closeToRight) const;