changeset 267:4ed1446ad604

* more on measurement tool -- pull out some logic from pane to layer &c still more to do
author Chris Cannam
date Thu, 21 Jun 2007 16:12:00 +0000
parents aee39d8c0b83
children 70537b0434c4
files layer/Layer.cpp layer/Layer.h layer/SliceLayer.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/SpectrumLayer.cpp layer/SpectrumLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h view/Pane.cpp view/Pane.h view/View.cpp view/View.h
diffstat 13 files changed, 287 insertions(+), 286 deletions(-) [+]
line wrap: on
line diff
--- a/layer/Layer.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/Layer.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -20,11 +20,13 @@
 #include <iostream>
 
 #include <QMutexLocker>
+#include <QMouseEvent>
 
 #include "LayerFactory.h"
 #include "base/PlayParameterRepository.h"
 
-Layer::Layer()
+Layer::Layer() :
+    m_haveDraggingRect(false)
 {
 }
 
@@ -123,7 +125,7 @@
 }
 
 bool
-Layer::getXScaleValue(View *v, int x, float &value, QString &unit) const
+Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
 {
     if (!hasTimeXAxis()) return false;
 
@@ -135,3 +137,60 @@
     return true;
 }
 
+void
+Layer::measureStart(View *v, QMouseEvent *e)
+{
+    m_draggingRect.pixrect = QRect(e->x(), e->y(), 0, 0);
+    if (hasTimeXAxis()) {
+        m_draggingRect.startFrame = v->getFrameForX(e->x());
+        m_draggingRect.endFrame = m_draggingRect.startFrame;
+    }
+    m_haveDraggingRect = true;
+}
+
+void
+Layer::measureDrag(View *v, QMouseEvent *e)
+{
+    if (!m_haveDraggingRect) return;
+    m_draggingRect.pixrect = QRect(m_draggingRect.pixrect.x(),
+                                   m_draggingRect.pixrect.y(),
+                                   e->x() - m_draggingRect.pixrect.x(),
+                                   e->y() - m_draggingRect.pixrect.y());
+    if (hasTimeXAxis()) {
+        m_draggingRect.endFrame = v->getFrameForX(e->x());
+    }
+}
+
+void
+Layer::measureEnd(View *v, QMouseEvent *e)
+{
+    //!!! command
+    if (!m_haveDraggingRect) return;
+    measureDrag(v, e);
+    m_measureRectList.push_back(m_draggingRect);
+    m_haveDraggingRect = false;
+}
+
+void
+Layer::paintMeasurementRects(View *v, QPainter &paint) const
+{
+    if (m_haveDraggingRect) {
+        v->drawMeasurementRect(paint, this, m_draggingRect.pixrect);
+    }
+
+    bool timex = hasTimeXAxis();
+
+    for (MeasureRectList::const_iterator i = m_measureRectList.begin(); 
+         i != m_measureRectList.end(); ++i) {
+    
+        if (timex) {
+            int x0 = v->getXForFrame(i->startFrame);
+            int x1 = v->getXForFrame(i->endFrame);
+            QRect pr = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
+            i->pixrect = pr;
+        }
+
+        v->drawMeasurementRect(paint, this, i->pixrect);
+    }
+}
+
--- a/layer/Layer.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/Layer.h	Thu Jun 21 16:12:00 2007 +0000
@@ -105,6 +105,8 @@
     }
     virtual void paintCrosshairs(View *, QPainter &, QPoint) const { }
 
+    virtual void paintMeasurementRects(View *, QPainter &) const;
+
     virtual QString getFeatureDescription(View *, QPoint &) const {
 	return "";
     }
@@ -156,6 +158,14 @@
     virtual void editDrag(View *, QMouseEvent *) { }
     virtual void editEnd(View *, QMouseEvent *) { }
 
+    // Measurement rectangle (or equivalent).  Unlike draw and edit,
+    // the base Layer class can provide working implementations of
+    // these for most situations.
+    //
+    virtual void measureStart(View *, QMouseEvent *);
+    virtual void measureDrag(View *, QMouseEvent *);
+    virtual void measureEnd(View *, QMouseEvent *);
+
     /**
      * Open an editor on the item under the mouse (e.g. on
      * double-click).  If there is no item or editing is not
@@ -323,14 +333,14 @@
      * measurement tool.  The default implementation works correctly
      * if the layer hasTimeXAxis().
      */
-    virtual bool getXScaleValue(View *v, int x,
+    virtual bool getXScaleValue(const View *v, int x,
                                 float &value, QString &unit) const;
 
     /** 
      * Return the value and unit at the given y coordinate in the
      * given view.
      */
-    virtual bool getYScaleValue(View *, int /* y */,
+    virtual bool getYScaleValue(const View *, int /* y */,
                                 float &/* value */, QString &/* unit */) const {
         return false;
     }
@@ -390,6 +400,18 @@
 
     void verticalZoomChanged();
 
+protected:
+    struct MeasureRect {
+        mutable QRect pixrect;
+        long startFrame; // only valid for a layer that hasTimeXAxis
+        long endFrame;   // ditto
+    };
+
+    typedef std::vector<MeasureRect> MeasureRectList; // should be x-ordered
+    MeasureRectList m_measureRectList;
+    MeasureRect m_draggingRect;
+    bool m_haveDraggingRect;
+
 private:
     mutable QMutex m_dormancyMutex;
     mutable std::map<const void *, bool> m_dormancy;
--- a/layer/SliceLayer.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/SliceLayer.h	Thu Jun 21 16:12:00 2007 +0000
@@ -129,7 +129,7 @@
     bool                              m_normalize;
     float                             m_gain;
     mutable std::vector<int>          m_scalePoints;
-    mutable std::map<View *, int>     m_xorigins;
+    mutable std::map<const View *, int> m_xorigins;
     mutable size_t                    m_currentf0;
     mutable size_t                    m_currentf1;
     mutable std::vector<float>        m_values;
--- a/layer/SpectrogramLayer.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -2381,7 +2381,7 @@
 }
 
 float
-SpectrogramLayer::getYForFrequency(View *v, float frequency) const
+SpectrogramLayer::getYForFrequency(const View *v, float frequency) const
 {
     return v->getYForFrequency(frequency,
 			       getEffectiveMinFrequency(),
@@ -2390,7 +2390,7 @@
 }
 
 float
-SpectrogramLayer::getFrequencyForY(View *v, int y) const
+SpectrogramLayer::getFrequencyForY(const View *v, int y) const
 {
     return v->getFrequencyForY(y,
 			       getEffectiveMinFrequency(),
@@ -2469,7 +2469,7 @@
 }
 
 bool
-SpectrogramLayer::getYScaleValue(View *v, int y,
+SpectrogramLayer::getYScaleValue(const View *v, int y,
                                  float &value, QString &unit) const
 {
     value = getFrequencyForY(v, y);
--- a/layer/SpectrogramLayer.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/SpectrogramLayer.h	Thu Jun 21 16:12:00 2007 +0000
@@ -188,8 +188,8 @@
     virtual bool isLayerOpaque() const { return true; }
     virtual bool isLayerColourSignificant() const { return true; }
 
-    float getYForFrequency(View *v, float frequency) const;
-    float getFrequencyForY(View *v, int y) const;
+    float getYForFrequency(const View *v, float frequency) const;
+    float getFrequencyForY(const View *v, int y) const;
 
     virtual int getCompletion(View *v) const;
 
@@ -200,7 +200,7 @@
 
     virtual bool setDisplayExtents(float min, float max);
 
-    virtual bool getYScaleValue(View *, int, float &, QString &) const;
+    virtual bool getYScaleValue(const View *, int, float &, QString &) const;
 
     virtual QString toXmlString(QString indent = "",
 				QString extraAttributes = "") const;
--- a/layer/SpectrumLayer.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -332,10 +332,12 @@
 }
 
 bool
-SpectrumLayer::getXScaleValue(View *v, int x, 
+SpectrumLayer::getXScaleValue(const View *v, int x, 
                               float &value, QString &unit) const
 {
-    value = getFrequencyForX(x - m_xorigins[v], v->width() - m_xorigins[v] - 1);
+    if (m_xorigins.find(v) == m_xorigins.end()) return false;
+    int xorigin = m_xorigins.find(v)->second;
+    value = getFrequencyForX(x - xorigin, v->width() - xorigin - 1);
     unit = "Hz";
     return true;
 }
--- a/layer/SpectrumLayer.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/SpectrumLayer.h	Thu Jun 21 16:12:00 2007 +0000
@@ -59,7 +59,7 @@
     virtual bool getValueExtents(float &min, float &max,
                                  bool &logarithmic, QString &unit) const;
 
-    virtual bool getXScaleValue(View *v, int x,
+    virtual bool getXScaleValue(const View *v, int x,
                                 float &value, QString &unit) const;
 
     virtual bool isLayerScrollable(const View *) const { return false; }
--- a/layer/WaveformLayer.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/WaveformLayer.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -995,7 +995,7 @@
 }
 
 int
-WaveformLayer::getYForValue(View *v, Scale scale, float value, size_t channel,
+WaveformLayer::getYForValue(const View *v, Scale scale, float value, size_t channel,
                             size_t minChannel, size_t maxChannel) const
 {
     if (maxChannel < minChannel || channel < minChannel) return 0;
@@ -1033,7 +1033,7 @@
 }
 
 float
-WaveformLayer::getValueForY(View *v, Scale scale, int y,
+WaveformLayer::getValueForY(const View *v, Scale scale, int y,
                             size_t minChannel, size_t maxChannel) const
 {
     if (maxChannel < minChannel) return 0;
@@ -1085,7 +1085,7 @@
 }
 
 bool
-WaveformLayer::getYScaleValue(View *v, int y,
+WaveformLayer::getYScaleValue(const View *v, int y,
                               float &value, QString &unit) const
 {
     size_t channels = 0, minChannel = 0, maxChannel = 0;
--- a/layer/WaveformLayer.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/layer/WaveformLayer.h	Thu Jun 21 16:12:00 2007 +0000
@@ -179,7 +179,7 @@
     virtual bool getValueExtents(float &min, float &max,
                                  bool &log, QString &unit) const;
 
-    virtual bool getYScaleValue(View *v, int y,
+    virtual bool getYScaleValue(const View *v, int y,
                                 float &value, QString &unit) const;
 
     virtual QString toXmlString(QString indent = "",
@@ -200,10 +200,10 @@
     size_t getChannelArrangement(size_t &min, size_t &max,
                                  bool &merging, bool &mixing) const;
 
-    int getYForValue(View *v, Scale scale, float value, size_t channel,
+    int getYForValue(const View *v, Scale scale, float value, size_t channel,
                      size_t minChannel, size_t maxChannel) const;
 
-    float getValueForY(View *v, Scale scale, int y,
+    float getValueForY(const View *v, Scale scale, int y,
                        size_t minChannel, size_t maxChannel) const;
 
     float        m_gain;
--- a/view/Pane.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/view/Pane.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -42,9 +42,8 @@
 using std::cerr;
 using std::endl;
 
-QCursor Pane::m_measureCursor1;
-QCursor Pane::m_measureCursor2;
-bool Pane::m_measureCursorsCreated = false;
+QCursor *Pane::m_measureCursor1 = 0;
+QCursor *Pane::m_measureCursor2 = 0;
 
 Pane::Pane(QWidget *w) :
     View(w, true),
@@ -52,7 +51,6 @@
     m_clickedInRange(false),
     m_shiftPressed(false),
     m_ctrlPressed(false),
-    m_haveDraggingRect(false),
     m_navigating(false),
     m_resizing(false),
     m_centreLineVisible(true),
@@ -456,7 +454,7 @@
     }
 
     if (toolMode == ViewManager::MeasureMode && topLayer) {
-        drawMeasurementRects(topLayer, paint);
+        topLayer->paintMeasurementRects(this, paint);
     }
     
     if (selectionIsBeingEdited()) {
@@ -746,192 +744,6 @@
 }
 
 void
-Pane::drawMeasurementRects(Layer *topLayer, QPainter &paint)
-{
-    if (m_haveDraggingRect) {
-        drawMeasurementRect(topLayer, m_draggingRect, paint);
-    }
-
-    if (m_measureRects.find(topLayer) == m_measureRects.end() ||
-        m_measureRects[topLayer].empty()) return;
-
-    MeasureRectList &rects = m_measureRects[topLayer];
-
-    for (MeasureRectList::iterator i = rects.begin(); 
-         i != rects.end(); ++i) {
-        drawMeasurementRect(topLayer, *i, paint);
-    }
-}
-
-void
-Pane::drawMeasurementRect(Layer *topLayer, MeasureRect &r, QPainter &paint)
-{
-    if (topLayer->hasTimeXAxis()) {
-        r.start.rx() = getXForFrame(r.startFrame);
-        r.end.rx() = getXForFrame(r.endFrame);
-    }
-
-    int lx = std::min(r.start.x(), r.end.x());
-    int rx = std::max(r.start.x(), r.end.x());
-    if (rx < 0 || lx >= width()) return;
-
-    int fontHeight = paint.fontMetrics().height();
-    int fontAscent = paint.fontMetrics().ascent();
-
-    float v0, v1;
-    QString u0, u1;
-    bool b0 = false, b1 = false;
-
-    QString axs, ays, bxs, bys, dxs, dys;
-
-    int axx, axy, bxx, bxy, dxx, dxy;
-    int aw = 0, bw = 0, dw = 0;
-    
-    int labelCount = 0;
-
-    if ((b0 = topLayer->getXScaleValue(this, r.start.x(), v0, u0))) {
-        axs = QString("%1 %2").arg(v0).arg(u0);
-        aw = paint.fontMetrics().width(axs);
-        ++labelCount;
-    }
-        
-    if (r.start != r.end) {
-        if ((b1 = topLayer->getXScaleValue(this, r.end.x(), v1, u1))) {
-            bxs = QString("%1 %2").arg(v1).arg(u1);
-            bw = paint.fontMetrics().width(bxs);
-        }
-    }
-        
-    if (b0 && b1 && u0 == u1) {
-        dxs = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1);
-        dw = paint.fontMetrics().width(dxs);
-    }
-    
-    b0 = false;
-    b1 = false;
-
-    if ((b0 = topLayer->getYScaleValue(this, r.start.y(), v0, u0))) {
-        ays = QString("%1 %2").arg(v0).arg(u0);
-        aw = std::max(aw, paint.fontMetrics().width(ays));
-        ++labelCount;
-    }
-
-    if (r.start != r.end) {
-        if ((b1 = topLayer->getYScaleValue(this, r.end.y(), v1, u1))) {
-            bys = QString("%1 %2").arg(v1).arg(u1);
-            bw = std::max(bw, paint.fontMetrics().width(bys));
-        }
-    }
-    
-    if (b0 && b1 && u0 == u1) {
-        dys = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1);
-        dw = std::max(dw, paint.fontMetrics().width(dys));
-    }
-
-    int mw = abs(r.end.x() - r.start.x());
-    int mh = abs(r.end.y() - r.start.y());
-
-    bool edgeLabelsInside = false;
-    bool sizeLabelsInside = false;
-
-    if (mw < std::max(aw, std::max(bw, dw)) + 4) {
-        // defaults stand
-    } else if (mw < aw + bw + 4) {
-        if (mh > fontHeight * labelCount * 3 + 4) {
-            edgeLabelsInside = true;
-            sizeLabelsInside = true;
-        } else if (mh > fontHeight * labelCount * 2 + 4) {
-            edgeLabelsInside = true;
-        }
-    } else if (mw < aw + bw + dw + 4) {
-        if (mh > fontHeight * labelCount * 3 + 4) {
-            edgeLabelsInside = true;
-            sizeLabelsInside = true;
-        } else if (mh > fontHeight * labelCount + 4) {
-            edgeLabelsInside = true;
-        }
-    } else {
-        if (mh > fontHeight * labelCount + 4) {
-            edgeLabelsInside = true;
-            sizeLabelsInside = true;
-        }
-    }
-
-    if (edgeLabelsInside) {
-
-        axx = r.start.x() + 2;
-        axy = r.start.y() + fontAscent + 2;
-
-        bxx = r.end.x() - bw - 2;
-        bxy = r.end.y() - (labelCount-1) * fontHeight - 2;
-
-    } else {
-
-        axx = r.start.x() - aw - 2;
-        axy = r.start.y() + fontAscent;
-        
-        bxx = r.end.x() + 2;
-        bxy = r.end.y() - (labelCount-1) * fontHeight;
-    }
-
-    dxx = (r.end.x() - r.start.x())
-        / 2 + r.start.x() - dw/2;
-
-    if (sizeLabelsInside) {
-
-        dxy = (r.end.y() - r.start.y())
-            / 2 + r.start.y() - (labelCount * fontHeight)/2 + fontAscent;
-
-    } else {
-
-        dxy = std::max(r.end.y(), r.start.y()) + fontAscent + 2;
-    }
-    
-    if (axs != "") {
-        drawVisibleText(paint, axx, axy, axs, OutlinedText);
-        axy += fontHeight;
-    }
-    
-    if (ays != "") {
-        drawVisibleText(paint, axx, axy, ays, OutlinedText);
-        axy += fontHeight;
-    }
-
-    if (bxs != "") {
-        drawVisibleText(paint, bxx, bxy, bxs, OutlinedText);
-        bxy += fontHeight;
-    }
-
-    if (bys != "") {
-        drawVisibleText(paint, bxx, bxy, bys, OutlinedText);
-        bxy += fontHeight;
-    }
-
-    if (dxs != "") {
-        drawVisibleText(paint, dxx, dxy, dxs, OutlinedText);
-        dxy += fontHeight;
-    }
-
-    if (dys != "") {
-        drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
-        dxy += fontHeight;
-    }
-
-    if (r.start != r.end) {
-
-        paint.save();
-        
-        paint.setPen(Qt::green);
-        
-        paint.drawRect(r.start.x(), r.start.y(),
-                       r.end.x() - r.start.x(),
-                       r.end.y() - r.start.y());
-        
-        paint.restore();
-    }
-}
-
-void
 Pane::drawEditingSelection(QPainter &paint)
 {
     int offset = m_mousePos.x() - m_clickPos.x();
@@ -1277,29 +1089,8 @@
 
     } else if (mode == ViewManager::MeasureMode) {
 
-        //!!! command
-
-        MeasureRect rect;
-
-        rect.start = m_clickPos;
-        rect.end = rect.start;
-
-        rect.startFrame = getFrameForX(rect.start.x());
-        rect.endFrame = rect.startFrame;
-
-        m_draggingRect = rect;
-        m_haveDraggingRect = true;
-
-        
-/*!!!
-        m_measureStart = m_clickPos;
-        m_measureEnd = m_measureStart;
-
-        m_measureStartFrame = getFrameForX(m_clickPos.x());
-        m_measureEndFrame = m_measureStartFrame;
-
-        m_haveMeasureRect = true;
-*/
+        Layer *layer = getSelectedLayer();
+        if (layer) layer->measureStart(this, e);
         update();
     }
 
@@ -1384,18 +1175,10 @@
 
     } else if (mode == ViewManager::MeasureMode) {
 
-        if (m_haveDraggingRect) {
-
-            LayerList::iterator vi = m_layers.end();
-            if (vi != m_layers.begin()) {
-                Layer *topLayer = *(--vi);
-                m_measureRects[topLayer].push_back(m_draggingRect);
-            }
-
-            m_haveDraggingRect = false;
-        }
-
-        setCursor(m_measureCursor1);
+        Layer *layer = getSelectedLayer();
+        if (layer) layer->measureEnd(this, e);
+        if (m_measureCursor1) setCursor(*m_measureCursor1);
+        update();
     }
 
     m_clickedInRange = false;
@@ -1483,16 +1266,16 @@
 
     } else if (mode == ViewManager::MeasureMode) {
 
-        setCursor(m_measureCursor2);
+        if (m_measureCursor2) setCursor(*m_measureCursor2);
 
-        if (m_haveDraggingRect) {
-            m_draggingRect.end = e->pos();
-            if (hasTopLayerTimeXAxis()) {
-                m_draggingRect.endFrame = getFrameForX(m_draggingRect.end.x());
-                edgeScrollMaybe(e->x());
-            }
-            update();
+        Layer *layer = getSelectedLayer();
+        if (layer) layer->measureDrag(this, e);
+
+        if (hasTopLayerTimeXAxis()) {
+            edgeScrollMaybe(e->x());
         }
+
+        update();
     }
 }
 
@@ -2088,14 +1871,13 @@
     ViewManager::ToolMode mode = m_manager->getToolMode();
 //    std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl;
 
-    if (mode == ViewManager::MeasureMode && !m_measureCursorsCreated) {
-        m_measureCursor1 = QCursor(QBitmap(":/icons/measure1cursor.xbm"),
-                                   QBitmap(":/icons/measure1mask.xbm"),
-                                   15, 14);
-        m_measureCursor2 = QCursor(QBitmap(":/icons/measure2cursor.xbm"),
-                                   QBitmap(":/icons/measure2mask.xbm"),
-                                   16, 17);
-        m_measureCursorsCreated = true;
+    if (mode == ViewManager::MeasureMode && !m_measureCursor1) {
+        m_measureCursor1 = new QCursor(QBitmap(":/icons/measure1cursor.xbm"),
+                                       QBitmap(":/icons/measure1mask.xbm"),
+                                       15, 14);
+        m_measureCursor2 = new QCursor(QBitmap(":/icons/measure2cursor.xbm"),
+                                       QBitmap(":/icons/measure2mask.xbm"),
+                                       16, 17);
     }
 
     switch (mode) {
@@ -2117,7 +1899,7 @@
 	break;
 
     case ViewManager::MeasureMode:
-	setCursor(m_measureCursor1);
+        if (m_measureCursor1) setCursor(*m_measureCursor1);
 	break;
 
 /*	
--- a/view/Pane.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/view/Pane.h	Thu Jun 21 16:12:00 2007 +0000
@@ -88,25 +88,11 @@
     virtual void wheelEvent(QWheelEvent *e);
     virtual void resizeEvent(QResizeEvent *e);
 
-    // pull this out into another class at some point
-
-    struct MeasureRect {
-        QPoint start;
-        QPoint end;
-        long startFrame; // only valid for a layer that hasTimeXAxis
-        long endFrame;   // ditto
-    };
-
-    typedef std::vector<MeasureRect> MeasureRectList; // should be x-ordered
-    typedef std::map<Layer *, MeasureRectList> MeasureRectMap;
-
     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 drawMeasurementRects(Layer *, QPainter &);
-    void drawMeasurementRect(Layer *, MeasureRect &, QPainter &);
     void drawEditingSelection(QPainter &);
 
     virtual bool render(QPainter &paint, int x0, size_t f0, size_t f1);
@@ -141,10 +127,6 @@
     bool m_shiftPressed;
     bool m_ctrlPressed;
 
-    MeasureRectMap m_measureRects;
-    MeasureRect m_draggingRect;
-    bool m_haveDraggingRect;
-
     bool m_navigating;
     bool m_resizing;
     size_t m_dragCentreFrame;
@@ -169,9 +151,8 @@
     Thumbwheel *m_vthumb;
     NotifyingPushButton *m_reset;
 
-    static QCursor m_measureCursor1;
-    static QCursor m_measureCursor2;
-    static bool m_measureCursorsCreated;
+    static QCursor *m_measureCursor1;
+    static QCursor *m_measureCursor2;
 };
 
 #endif
--- a/view/View.cpp	Thu Jun 21 14:05:23 2007 +0000
+++ b/view/View.cpp	Thu Jun 21 16:12:00 2007 +0000
@@ -613,7 +613,7 @@
 }
 
 void
-View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style)
+View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style) const
 {
     if (style == OutlinedText) {
 
@@ -1628,6 +1628,159 @@
     paint.restore();
 }
 
+void
+View::drawMeasurementRect(QPainter &paint, const Layer *topLayer, QRect r) const
+{
+    if (r.x() + r.width() < 0 || r.x() >= width()) return;
+
+    int fontHeight = paint.fontMetrics().height();
+    int fontAscent = paint.fontMetrics().ascent();
+
+    float v0, v1;
+    QString u0, u1;
+    bool b0 = false, b1 = false;
+
+    QString axs, ays, bxs, bys, dxs, dys;
+
+    int axx, axy, bxx, bxy, dxx, dxy;
+    int aw = 0, bw = 0, dw = 0;
+    
+    int labelCount = 0;
+
+    if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) {
+        axs = QString("%1 %2").arg(v0).arg(u0);
+        aw = paint.fontMetrics().width(axs);
+        ++labelCount;
+    }
+        
+    if (r.width() > 0) {
+        if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) {
+            bxs = QString("%1 %2").arg(v1).arg(u1);
+            bw = paint.fontMetrics().width(bxs);
+        }
+    }
+        
+    if (b0 && b1 && u0 == u1) {
+        dxs = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1);
+        dw = paint.fontMetrics().width(dxs);
+    }
+    
+    b0 = false;
+    b1 = false;
+
+    if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) {
+        ays = QString("%1 %2").arg(v0).arg(u0);
+        aw = std::max(aw, paint.fontMetrics().width(ays));
+        ++labelCount;
+    }
+
+    if (r.height() > 0) {
+        if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) {
+            bys = QString("%1 %2").arg(v1).arg(u1);
+            bw = std::max(bw, paint.fontMetrics().width(bys));
+        }
+    }
+    
+    if (b0 && b1 && u0 == u1) {
+        dys = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1);
+        dw = std::max(dw, paint.fontMetrics().width(dys));
+    }
+
+    int mw = r.width();
+    int mh = r.height();
+
+    bool edgeLabelsInside = false;
+    bool sizeLabelsInside = false;
+
+    if (mw < std::max(aw, std::max(bw, dw)) + 4) {
+        // defaults stand
+    } else if (mw < aw + bw + 4) {
+        if (mh > fontHeight * labelCount * 3 + 4) {
+            edgeLabelsInside = true;
+            sizeLabelsInside = true;
+        } else if (mh > fontHeight * labelCount * 2 + 4) {
+            edgeLabelsInside = true;
+        }
+    } else if (mw < aw + bw + dw + 4) {
+        if (mh > fontHeight * labelCount * 3 + 4) {
+            edgeLabelsInside = true;
+            sizeLabelsInside = true;
+        } else if (mh > fontHeight * labelCount + 4) {
+            edgeLabelsInside = true;
+        }
+    } else {
+        if (mh > fontHeight * labelCount + 4) {
+            edgeLabelsInside = true;
+            sizeLabelsInside = true;
+        }
+    }
+
+    if (edgeLabelsInside) {
+
+        axx = r.x() + 2;
+        axy = r.y() + fontAscent + 2;
+
+        bxx = r.x() + r.width() - bw - 2;
+        bxy = r.y() + r.height() - (labelCount-1) * fontHeight - 2;
+
+    } else {
+
+        axx = r.x() - aw - 2;
+        axy = r.y() + fontAscent;
+        
+        bxx = r.x() + r.width() + 2;
+        bxy = r.y() + r.height() - (labelCount-1) * fontHeight;
+    }
+
+    dxx = r.width()/2 + r.x() - dw/2;
+
+    if (sizeLabelsInside) {
+
+        dxy = r.height()/2 + r.y() - (labelCount * fontHeight)/2 + fontAscent;
+
+    } else {
+
+        dxy = r.y() + r.height() + fontAscent + 2;
+    }
+    
+    if (axs != "") {
+        drawVisibleText(paint, axx, axy, axs, OutlinedText);
+        axy += fontHeight;
+    }
+    
+    if (ays != "") {
+        drawVisibleText(paint, axx, axy, ays, OutlinedText);
+        axy += fontHeight;
+    }
+
+    if (bxs != "") {
+        drawVisibleText(paint, bxx, bxy, bxs, OutlinedText);
+        bxy += fontHeight;
+    }
+
+    if (bys != "") {
+        drawVisibleText(paint, bxx, bxy, bys, OutlinedText);
+        bxy += fontHeight;
+    }
+
+    if (dxs != "") {
+        drawVisibleText(paint, dxx, dxy, dxs, OutlinedText);
+        dxy += fontHeight;
+    }
+
+    if (dys != "") {
+        drawVisibleText(paint, dxx, dxy, dys, OutlinedText);
+        dxy += fontHeight;
+    }
+
+    if (r.width() != 0 || r.height() != 0) {
+        paint.save();
+        paint.setPen(Qt::green);
+        paint.drawRect(r);
+        paint.restore();
+    }
+}
+
 bool
 View::render(QPainter &paint, int xorigin, size_t f0, size_t f1)
 {
--- a/view/View.h	Thu Jun 21 14:05:23 2007 +0000
+++ b/view/View.h	Thu Jun 21 16:12:00 2007 +0000
@@ -179,7 +179,9 @@
     };
 
     virtual void drawVisibleText(QPainter &p, int x, int y,
-				 QString text, TextStyle style);
+				 QString text, TextStyle style) const;
+
+    virtual void drawMeasurementRect(QPainter &p, const Layer *, QRect rect) const;
 
     virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const {
 	return false;