changeset 274:b9380f679f70

* Fix centre line position * Fix failure to update overview when generating peaks from wav file * Provide y-coordinate scale values and differences for spectrum measurement mode, and fix values for waveform (inc dB for both) * Add Printer colour scheme (may be futile)
author Chris Cannam
date Mon, 02 Jul 2007 13:04:17 +0000
parents e954c00cbe55
children bbe57afe9d7d
files layer/ColourMapper.cpp layer/ColourMapper.h layer/Layer.cpp layer/Layer.h layer/SliceLayer.cpp layer/SliceLayer.h layer/SpectrumLayer.cpp layer/SpectrumLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h layer/layer.pro view/Overview.cpp view/Overview.h view/Pane.cpp view/View.cpp
diffstat 15 files changed, 313 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ColourMapper.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/ColourMapper.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -39,7 +39,7 @@
 int
 ColourMapper::getColourMapCount()
 {
-    return 10;
+    return 11;
 }
 
 QString
@@ -59,6 +59,7 @@
     case FruitSalad:       return tr("Fruit Salad");
     case Banded:           return tr("Banded");
     case Highlight:        return tr("Highlight");
+    case Printer:          return tr("Printer");
     }
 
     return tr("<unknown>");
@@ -157,6 +158,28 @@
     case Highlight:
         if (norm > 0.99) return Qt::white;
         else return Qt::darkBlue;
+
+    case Printer:
+        if (norm > 0.8) {
+            r = 1.f;
+        } else if (norm > 0.7) {
+            r = 0.9f;
+        } else if (norm > 0.6) {
+            r = 0.8f;
+        } else if (norm > 0.5) {
+            r = 0.7f;
+        } else if (norm > 0.4) {
+            r = 0.6f;
+        } else if (norm > 0.3) {
+            r = 0.5f;
+        } else if (norm > 0.2) {
+            r = 0.4f;
+        } else {
+            r = 0.f;
+        }
+        r = g = b = 1.f - r;
+        hsv = false;
+        break;
     }
 
     if (hsv) {
@@ -203,6 +226,9 @@
 
     case Highlight:
         return Qt::red;
+
+    case Printer:
+        return Qt::red;
     }
 
     return Qt::white;
--- a/layer/ColourMapper.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/ColourMapper.h	Mon Jul 02 13:04:17 2007 +0000
@@ -42,7 +42,8 @@
         BlueOnBlack,
         FruitSalad,
         Banded,
-        Highlight
+        Highlight,
+        Printer
     };
 
     int getMap() const { return m_map; }
--- a/layer/Layer.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/Layer.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -123,6 +123,20 @@
 }
 
 bool
+Layer::getYScaleDifference(const View *v, int y0, int y1,
+                           float &diff, QString &unit) const
+{
+    float v0, v1;
+    if (!getYScaleValue(v, y0, v0, unit) ||
+        !getYScaleValue(v, y1, v1, unit)) {
+        diff = 0.f;
+        return false;
+    }
+    diff = fabsf(v1 - v0);
+    return true;
+}
+
+bool
 Layer::MeasureRect::operator<(const MeasureRect &mr) const
 {
     if (haveFrames) {
@@ -236,8 +250,7 @@
     m_draggingRect.pixrect = QRect(m_draggingRect.pixrect.x(),
                                    m_draggingRect.pixrect.y(),
                                    e->x() - m_draggingRect.pixrect.x(),
-                                   e->y() - m_draggingRect.pixrect.y())
-        .normalized();
+                                   e->y() - m_draggingRect.pixrect.y());
 
     setMeasureRectYCoord(v, m_draggingRect, false, e->y());
     
@@ -328,8 +341,6 @@
         i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
 
         updateMeasureRectYCoords(v, *i);
-        
-        i->pixrect = i->pixrect.normalized();
     }
 }
 
@@ -396,11 +407,10 @@
         }
         
         QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
-        
         r.pixrect = pr;
     }
-    
-    v->drawMeasurementRect(paint, this, r.pixrect, focus);
+
+    v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
 }
 
 QString
--- a/layer/Layer.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/Layer.h	Mon Jul 02 13:04:17 2007 +0000
@@ -367,6 +367,15 @@
     }
 
     /**
+     * Return the difference between the values at the given y
+     * coordinates in the given view, and the unit of the difference.
+     * The default implementation just calls getYScaleValue twice and
+     * returns the difference, with the same unit.
+     */
+    virtual bool getYScaleDifference(const View *v, int y0, int y1,
+                                     float &diff, QString &unit) const;
+        
+    /**
      * Get the number of vertical zoom steps available for this layer.
      * If vertical zooming is not available, return 0.  The meaning of
      * "zooming" is entirely up to the layer -- changing the zoom
--- a/layer/SliceLayer.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/SliceLayer.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -225,6 +225,85 @@
     return bin;
 }
 
+float
+SliceLayer::getYForValue(float value, const View *v, float &norm) const
+{
+    norm = 0.f;
+
+    if (m_yorigins.find(v) == m_yorigins.end()) return 0;
+
+    value *= m_gain;
+
+    int yorigin = m_yorigins[v];
+    int h = m_heights[v];
+    float thresh = -80.f;
+
+    float y = 0.f;
+
+    if (h <= 0) return y;
+
+    switch (m_energyScale) {
+
+    case dBScale:
+    {
+        float db = thresh;
+        if (value > 0.f) db = 10.f * log10f(value);
+        if (db < thresh) db = thresh;
+        norm = (db - thresh) / -thresh;
+        y = yorigin - (float(h) * norm);
+        break;
+    }
+    
+    case MeterScale:
+        y = AudioLevel::multiplier_to_preview(value, h);
+        norm = float(y) / float(h);
+        y = yorigin - y;
+        break;
+        
+    default:
+        norm = value;
+        y = yorigin - (float(h) * value);
+        break;
+    }
+    
+    return y;
+}
+
+float
+SliceLayer::getValueForY(float y, const View *v) const
+{
+    float value = 0.f;
+
+    if (m_yorigins.find(v) == m_yorigins.end()) return value;
+
+    int yorigin = m_yorigins[v];
+    int h = m_heights[v];
+    float thresh = -80.f;
+
+    if (h <= 0) return value;
+
+    y = yorigin - y;
+
+    switch (m_energyScale) {
+
+    case dBScale:
+    {
+        float db = ((y / h) * -thresh) + thresh;
+        value = powf(10.f, db/10.f);
+        break;
+    }
+
+    case MeterScale:
+        value = AudioLevel::preview_to_multiplier(lrintf(y), h);
+        break;
+
+    default:
+        value = y / h;
+    }
+
+    return value / m_gain;
+}
+
 void
 SliceLayer::paint(View *v, QPainter &paint, QRect rect) const
 {
@@ -245,21 +324,20 @@
 
     paint.setPen(m_colour);
 
-//    int w = (v->width() * 2) / 3;
-    int xorigin = getVerticalScaleWidth(v, paint) + 1; //!!! (v->width() / 2) - (w / 2);
+    int xorigin = getVerticalScaleWidth(v, paint) + 1;
     int w = v->width() - xorigin - 1;
 
     m_xorigins[v] = xorigin; // for use in getFeatureDescription
     
     int yorigin = v->height() - 20 - paint.fontMetrics().height() - 7;
     int h = yorigin - paint.fontMetrics().height() - 8;
-    if (h < 0) return;
 
-//    int h = (v->height() * 3) / 4;
-//    int yorigin = (v->height() / 2) + (h / 2);
-    
+    m_yorigins[v] = yorigin; // for getYForValue etc
+    m_heights[v] = h;
+
+    if (h <= 0) return;
+
     QPainterPath path;
-    float thresh = -80.f;
 
     size_t mh = m_sliceableModel->getHeight();
 
@@ -276,13 +354,16 @@
     size_t f1 = v->getFrameForX(f0x + 1);
     if (f1 > f0) --f1;
 
-    size_t col0 = f0 / m_sliceableModel->getResolution();
+    std::cerr << "centre frame " << v->getCentreFrame() << ", x " << f0x << ", f0 " << f0 << ", f1 " << f1 << std::endl;
+
+    size_t res = m_sliceableModel->getResolution();
+    size_t col0 = f0 / res;
     size_t col1 = col0;
-    if (m_samplingMode != NearestSample) {
-        col1 = f1 / m_sliceableModel->getResolution();
-    }
-    f0 = col0 * m_sliceableModel->getResolution();
-    f1 = (col1 + 1) * m_sliceableModel->getResolution() - 1;
+    if (m_samplingMode != NearestSample) col1 = f1 / res;
+    f0 = col0 * res;
+    f1 = (col1 + 1) * res - 1;
+
+    std::cerr << "resolution " << res << ", col0 " << col0 << ", col1 " << col1 << ", f0 " << f0 << ", f1 " << f1 << std::endl;
 
     m_currentf0 = f0;
     m_currentf1 = f1;
@@ -326,34 +407,8 @@
         nx = xorigin + getXForBin(bin + 1, mh, w);
 
         float value = m_values[bin];
-
-        value *= m_gain;
         float norm = 0.f;
-        float y = 0.f;
- 
-        switch (m_energyScale) {
-
-        case dBScale:
-        {
-            float db = thresh;
-            if (value > 0.f) db = 10.f * log10f(value);
-            if (db < thresh) db = thresh;
-            norm = (db - thresh) / -thresh;
-            y = yorigin - (float(h) * norm);
-            break;
-        }
-
-        case MeterScale:
-            y = AudioLevel::multiplier_to_preview(value, h);
-            norm = float(y) / float(h);
-            y = yorigin - y;
-            break;
-
-        default:
-            norm = value;
-            y = yorigin - (float(h) * value);
-            break;
-        }
+        float y = getYForValue(value, v, norm);
 
         if (m_plotStyle == PlotLines) {
 
--- a/layer/SliceLayer.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/SliceLayer.h	Mon Jul 02 13:04:17 2007 +0000
@@ -107,6 +107,9 @@
 protected:
     virtual float getXForBin(int bin, int totalBins, float w) const;
     virtual int getBinForX(float x, int totalBins, float w) const;
+
+    virtual float getYForValue(float value, const View *v, float &norm) const;
+    virtual float getValueForY(float y, const View *v) const;
     
     virtual QString getFeatureDescription(View *v, QPoint &,
                                           bool includeBinDescription,
@@ -130,6 +133,8 @@
     float                             m_gain;
     mutable std::vector<int>          m_scalePoints;
     mutable std::map<const View *, int> m_xorigins;
+    mutable std::map<const View *, int> m_yorigins;
+    mutable std::map<const View *, int> m_heights;
     mutable size_t                    m_currentf0;
     mutable size_t                    m_currentf1;
     mutable std::vector<float>        m_values;
--- a/layer/SpectrumLayer.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -324,7 +324,8 @@
         break;
 
     case InvertedLogBins:
-        x = (w - log10f(maxfreq - freq) * w) / log10f(maxfreq);
+        if (maxfreq == freq) x = w;
+        else x = w - (log10f(maxfreq - freq) * w) / log10f(maxfreq);
         break;
     }
 
@@ -343,6 +344,40 @@
 }
 
 bool
+SpectrumLayer::getYScaleValue(const View *v, int y,
+                              float &value, QString &unit) const
+{
+    value = getValueForY(y, v);
+
+    if (m_energyScale == dBScale || m_energyScale == MeterScale) {
+
+        float thresh = -80.f;
+
+        if (value > 0.f) {
+            value = 10.f * log10f(value);
+            if (value < thresh) value = thresh;
+        } else value = thresh;
+
+        unit = "dBV";
+
+    } else {
+        unit = "V";
+    }
+
+    return true;
+}
+
+bool
+SpectrumLayer::getYScaleDifference(const View *v, int y0, int y1,
+                                   float &diff, QString &unit) const
+{
+    bool rv = SliceLayer::getYScaleDifference(v, y0, y1, diff, unit);
+    if (rv && (unit == "dBV")) unit = "dB";
+    return rv;
+}
+
+
+bool
 SpectrumLayer::getCrosshairExtents(View *v, QPainter &paint,
                                    QPoint cursorPos,
                                    std::vector<QRect> &extents) const
--- a/layer/SpectrumLayer.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/SpectrumLayer.h	Mon Jul 02 13:04:17 2007 +0000
@@ -62,6 +62,12 @@
     virtual bool getXScaleValue(const View *v, int x,
                                 float &value, QString &unit) const;
 
+    virtual bool getYScaleValue(const View *, int y,
+                                float &value, QString &unit) const;
+
+    virtual bool getYScaleDifference(const View *, int y0, int y1,
+                                     float &diff, QString &unit) const;
+
     virtual bool isLayerScrollable(const View *) const { return false; }
 
     void setChannel(int);
--- a/layer/WaveformLayer.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/WaveformLayer.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -637,14 +637,14 @@
 
                 if (val < -1.0 || val > 1.0) continue;
 
-                int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
+                int y = getYForValue(v, val, ch);
 
                 if (py >= 0 && abs(y - py) < 10) continue;
                 else py = y;
 
                 int ny = y;
                 if (nval != 0.0) {
-                    ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
+                    ny = getYForValue(v, nval, ch);
                 }
 
                 paint->drawLine(x0, y, x1, y);
@@ -995,26 +995,29 @@
 }
 
 int
-WaveformLayer::getYForValue(const View *v, Scale scale, float value, size_t channel,
-                            size_t minChannel, size_t maxChannel) const
+WaveformLayer::getYForValue(const View *v, float value, size_t channel) const
 {
+    size_t channels = 0, minChannel = 0, maxChannel = 0;
+    bool mergingChannels = false, mixingChannels = false;
+
+    channels = getChannelArrangement(minChannel, maxChannel,
+                                     mergingChannels, mixingChannels);
+
     if (maxChannel < minChannel || channel < minChannel) return 0;
 
     int h = v->height();
-
-    int channels = maxChannel - minChannel + 1;
     int m = (h / channels) / 2;
-    int my = m + (((channel - minChannel) * h) / channels);
 	
     if ((m_scale == dBScale || m_scale == MeterScale) &&
         m_channelMode != MergeChannels) {
         m = (h / channels);
-        my = m + (((channel - minChannel) * h) / channels);
     }
 
+    int my = m + (((channel - minChannel) * h) / channels);
+
     int vy = 0;
 
-    switch (scale) {
+    switch (m_scale) {
 
     case LinearScale:
         vy = int(m * value);
@@ -1033,40 +1036,33 @@
 }
 
 float
-WaveformLayer::getValueForY(const View *v, Scale scale, int y,
-                            size_t minChannel, size_t maxChannel) const
+WaveformLayer::getValueForY(const View *v, int y, size_t &channel) const
 {
+    size_t channels = 0, minChannel = 0, maxChannel = 0;
+    bool mergingChannels = false, mixingChannels = false;
+
+    channels = getChannelArrangement(minChannel, maxChannel,
+                                     mergingChannels, mixingChannels);
+
     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;
+  
+    channel = (y * channels) / h + minChannel;
 
-    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 = my - y;
     float value = 0;
+    float thresh = -50.f;
 
-    switch (scale) {
+    switch (m_scale) {
 
     case LinearScale:
         value = float(vy) / m;
@@ -1077,27 +1073,75 @@
         break;
 
     case dBScale:
-        value = AudioLevel::dB_to_multiplier((50 * float(vy)) / m - 50);
+        value = (-thresh * float(vy)) / m + thresh;
+        value = AudioLevel::dB_to_multiplier(value);
         break;
     }
 
-    return value;
+    return value / m_gain;
 }
 
 bool
 WaveformLayer::getYScaleValue(const View *v, int y,
                               float &value, QString &unit) const
 {
-    size_t channels = 0, minChannel = 0, maxChannel = 0;
-    bool mergingChannels = false, mixingChannels = false;
+    size_t channel;
 
-    channels = getChannelArrangement(minChannel, maxChannel,
-                                     mergingChannels, mixingChannels);
+    value = getValueForY(v, y, channel);
 
-    if (channels == 0) return false;
+    if (m_scale == dBScale || m_scale == MeterScale) {
 
-    value = getValueForY(v, m_scale, y, minChannel, maxChannel);
-    unit = "V";
+        float thresh = -50.f;
+        
+        if (value > 0.f) {
+            value = 10.f * log10f(value);
+            if (value < thresh) value = thresh;
+        } else value = thresh;
+
+        unit = "dBV";
+
+    } else {
+        unit = "V";
+    }
+
+    return true;
+}
+
+bool
+WaveformLayer::getYScaleDifference(const View *v, int y0, int y1,
+                                   float &diff, QString &unit) const
+{
+    size_t c0, c1;
+    float v0 = getValueForY(v, y0, c0);
+    float v1 = getValueForY(v, y1, c1);
+
+    if (c0 != c1) {
+        // different channels, not comparable
+        diff = 0.f;
+        unit = "";
+        return false;
+    }
+
+    if (m_scale == dBScale || m_scale == MeterScale) {
+
+        float thresh = -50.f;
+
+        if (v1 == v0) diff = thresh;
+        else {
+            if (v1 > v0) diff = v0 / v1;
+            else diff = v1 / v0;
+
+            diff = 10.f * log10f(diff);
+            if (diff < thresh) diff = thresh;
+        }
+
+        unit = "dBV";
+
+    } else {
+        diff = fabsf(v1 - v0);
+        unit = "V";
+    }
+
     return true;
 }
 
@@ -1180,11 +1224,11 @@
 
             if (val < -1.0 || val > 1.0) continue;
 
-            int y = getYForValue(v, m_scale, val, ch, minChannel, maxChannel);
+            int y = getYForValue(v, val, ch);
 
             int ny = y;
             if (nval != 0.0) {
-                ny = getYForValue(v, m_scale, nval, ch, minChannel, maxChannel);
+                ny = getYForValue(v, nval, ch);
             }
 
             bool spaceForLabel = (i == 0 ||
--- a/layer/WaveformLayer.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/WaveformLayer.h	Mon Jul 02 13:04:17 2007 +0000
@@ -181,6 +181,9 @@
 
     virtual bool getYScaleValue(const View *v, int y,
                                 float &value, QString &unit) const;
+    
+    virtual bool getYScaleDifference(const View *v, int y0, int y1,
+                                     float &diff, QString &unit) const;
 
     virtual QString toXmlString(QString indent = "",
 				QString extraAttributes = "") const;
@@ -200,11 +203,9 @@
     size_t getChannelArrangement(size_t &min, size_t &max,
                                  bool &merging, bool &mixing) const;
 
-    int getYForValue(const View *v, Scale scale, float value, size_t channel,
-                     size_t minChannel, size_t maxChannel) const;
+    int getYForValue(const View *v, float value, size_t channel) const;
 
-    float getValueForY(const View *v, Scale scale, int y,
-                       size_t minChannel, size_t maxChannel) const;
+    float getValueForY(const View *v, int y, size_t &channel) const;
 
     float        m_gain;
     bool         m_autoNormalize;
--- a/layer/layer.pro	Fri Jun 29 16:50:59 2007 +0000
+++ b/layer/layer.pro	Mon Jul 02 13:04:17 2007 +0000
@@ -20,10 +20,10 @@
            LayerFactory.h \
            NoteLayer.h \
            PaintAssistant.h \
+           SliceableLayer.h \
+           SliceLayer.h \
            SpectrogramLayer.h \
            SpectrumLayer.h \
-           SliceLayer.h \
-           SliceableLayer.h \
            TextLayer.h \
            TimeInstantLayer.h \
            TimeRulerLayer.h \
@@ -35,9 +35,9 @@
            LayerFactory.cpp \
            NoteLayer.cpp \
            PaintAssistant.cpp \
+           SliceLayer.cpp \
            SpectrogramLayer.cpp \
            SpectrumLayer.cpp \
-           SliceLayer.cpp \
            TextLayer.cpp \
            TimeInstantLayer.cpp \
            TimeRulerLayer.cpp \
--- a/view/Overview.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/view/Overview.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -33,6 +33,7 @@
     m_followPan = false;
     m_followZoom = false;
     setPlaybackFollow(PlaybackIgnore);
+    m_modelTestTime.start();
 }
 
 void
@@ -50,13 +51,17 @@
     }
 
     if (!zoomChanged) {
-        for (LayerList::const_iterator i = m_layers.begin();
-             i != m_layers.end(); ++i) {
-            if ((*i)->getModel() &&
-                !(*i)->getModel()->isOK() ||
-                !(*i)->getModel()->isReady()) {
-                return;
+        if (m_modelTestTime.elapsed() < 1000) {
+            for (LayerList::const_iterator i = m_layers.begin();
+                 i != m_layers.end(); ++i) {
+                if ((*i)->getModel() &&
+                    !(*i)->getModel()->isOK() ||
+                    !(*i)->getModel()->isReady()) {
+                    return;
+                }
             }
+        } else {
+            m_modelTestTime.restart();
         }
     }
 
--- a/view/Overview.h	Fri Jun 29 16:50:59 2007 +0000
+++ b/view/Overview.h	Mon Jul 02 13:04:17 2007 +0000
@@ -19,6 +19,7 @@
 #include "View.h"
 
 #include <QPoint>
+#include <QTime>
 
 class QWidget;
 class QPaintEvent;
@@ -62,6 +63,7 @@
     QPoint m_mousePos;
     bool m_clickedInRange;
     size_t m_dragCentreFrame;
+    QTime m_modelTestTime;
     
     typedef std::set<View *> ViewSet;
     ViewSet m_views;
--- a/view/Pane.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/view/Pane.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -631,7 +631,7 @@
         c = QColor(240, 240, 240);
     }
     paint.setPen(c);
-    int x = width() / 2 + 1;
+    int x = width() / 2;
     paint.drawLine(x, 0, x, height() - 1);
     paint.drawLine(x-1, 1, x+1, 1);
     paint.drawLine(x-2, 0, x+2, 0);
--- a/view/View.cpp	Fri Jun 29 16:50:59 2007 +0000
+++ b/view/View.cpp	Mon Jul 02 13:04:17 2007 +0000
@@ -1726,9 +1726,18 @@
             bw = std::max(bw, paint.fontMetrics().width(bys));
         }
     }
-    
-    if (b0 && b1 && u0 == u1) {
-        dys = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1);
+
+    bool bd = false;
+    float dy = 0.f;
+    QString du;
+
+    if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(),
+                                            dy, du))) {
+        if (du != "") {
+            dys = QString("(%1 %2)").arg(dy).arg(du);
+        } else {
+            dys = QString("(%1)").arg(dy);
+        }
         dw = std::max(dw, paint.fontMetrics().width(dys));
     }