changeset 335:2f83b6e3b8ca

* Add Erase tool and mode * Add icons for Normalize buttons in property boxes, and for Show Peaks * Add support for velocity in notes -- not yet reflected in display or editable in the note edit dialog, but they are imported from MIDI, played, and exported * Begin work on making pastes align pasted times (subtler than I thought)
author Chris Cannam
date Fri, 23 Nov 2007 16:48:23 +0000
parents 0a74248af622
children 4a542ba875c2
files layer/ImageLayer.cpp layer/Layer.h layer/NoteLayer.cpp layer/NoteLayer.h layer/SliceLayer.cpp layer/SliceLayer.h layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/SpectrumLayer.cpp layer/SpectrumLayer.h layer/TextLayer.cpp layer/TextLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeRulerLayer.cpp layer/TimeRulerLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h layer/WaveformLayer.cpp layer/WaveformLayer.h view/Pane.cpp view/ViewManager.h widgets/PropertyBox.cpp widgets/PropertyBox.h
diffstat 24 files changed, 339 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/layer/ImageLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/ImageLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -814,6 +814,7 @@
 	if (s.contains(i->frame)) {
             //!!! inadequate
             Clipboard::Point point(i->frame, i->label);
+            point.setReferenceFrame(m_model->alignToReference(i->frame));
             to.addPoint(point);
         }
     }
--- a/layer/Layer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/Layer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -151,7 +151,7 @@
 	return false;
     }
 
-    // Draw and edit modes:
+    // Draw, erase, and edit modes:
     //
     // Layer needs to get actual mouse events, I guess.  Draw mode is
     // probably the easier.
@@ -160,6 +160,10 @@
     virtual void drawDrag(View *, QMouseEvent *) { }
     virtual void drawEnd(View *, QMouseEvent *) { }
 
+    virtual void eraseStart(View *, QMouseEvent *) { }
+    virtual void eraseDrag(View *, QMouseEvent *) { }
+    virtual void eraseEnd(View *, QMouseEvent *) { }
+
     virtual void editStart(View *, QMouseEvent *) { }
     virtual void editDrag(View *, QMouseEvent *) { }
     virtual void editEnd(View *, QMouseEvent *) { }
--- a/layer/NoteLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/NoteLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -41,8 +41,8 @@
     SingleColourLayer(),
     m_model(0),
     m_editing(false),
-    m_originalPoint(0, 0.0, 0, tr("New Point")),
-    m_editingPoint(0, 0.0, 0, tr("New Point")),
+    m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
+    m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
     m_editingCommand(0),
     m_verticalScale(AutoAlignScale)
 {
@@ -619,7 +619,7 @@
 
     float value = getValueForY(v, e->y());
 
-    m_editingPoint = NoteModel::Point(frame, value, 0, tr("New Point"));
+    m_editingPoint = NoteModel::Point(frame, value, 0, 0.8, tr("New Point"));
     m_originalPoint = m_editingPoint;
 
     if (m_editingCommand) m_editingCommand->finish();
@@ -670,6 +670,51 @@
 }
 
 void
+NoteLayer::eraseStart(View *v, QMouseEvent *e)
+{
+    if (!m_model) return;
+
+    NoteModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+
+    m_editingPoint = *points.begin();
+
+    if (m_editingCommand) {
+	m_editingCommand->finish();
+	m_editingCommand = 0;
+    }
+
+    m_editing = true;
+}
+
+void
+NoteLayer::eraseDrag(View *v, QMouseEvent *e)
+{
+}
+
+void
+NoteLayer::eraseEnd(View *v, QMouseEvent *e)
+{
+    if (!m_model || !m_editing) return;
+
+    m_editing = false;
+
+    NoteModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+    if (points.begin()->frame != m_editingPoint.frame ||
+        points.begin()->value != m_editingPoint.value) return;
+
+    m_editingCommand = new NoteModel::EditCommand
+        (m_model, tr("Erase Point"));
+
+    m_editingCommand->deletePoint(m_editingPoint);
+
+    m_editingCommand->finish();
+    m_editingCommand = 0;
+    m_editing = false;
+}
+
+void
 NoteLayer::editStart(View *v, QMouseEvent *e)
 {
 //    std::cerr << "NoteLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
@@ -881,7 +926,8 @@
     for (NoteModel::PointList::iterator i = points.begin();
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
-            Clipboard::Point point(i->frame, i->value, i->duration, i->label);
+            Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label);
+            point.setReferenceFrame(m_model->alignToReference(i->frame));
             to.addPoint(point);
         }
     }
@@ -911,6 +957,7 @@
         if (i->haveValue()) newPoint.value = i->getValue();
         else newPoint.value = (m_model->getValueMinimum() +
                                m_model->getValueMaximum()) / 2;
+        if (i->haveLevel()) newPoint.level = i->getLevel();
         if (i->haveDuration()) newPoint.duration = i->getDuration();
         else {
             size_t nextFrame = frame;
--- a/layer/NoteLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/NoteLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -44,6 +44,10 @@
     virtual void drawDrag(View *v, QMouseEvent *);
     virtual void drawEnd(View *v, QMouseEvent *);
 
+    virtual void eraseStart(View *v, QMouseEvent *);
+    virtual void eraseDrag(View *v, QMouseEvent *);
+    virtual void eraseEnd(View *v, QMouseEvent *);
+
     virtual void editStart(View *v, QMouseEvent *);
     virtual void editDrag(View *v, QMouseEvent *);
     virtual void editEnd(View *v, QMouseEvent *);
--- a/layer/SliceLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SliceLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -569,6 +569,13 @@
     return SingleColourLayer::getPropertyLabel(name);
 }
 
+QString
+SliceLayer::getPropertyIconName(const PropertyName &name) const
+{
+    if (name == "Normalize") return "normalise";
+    return "";
+}
+
 Layer::PropertyType
 SliceLayer::getPropertyType(const PropertyName &name) const
 {
--- a/layer/SliceLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SliceLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -52,6 +52,7 @@
 
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
+    virtual QString getPropertyIconName(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
     virtual QString getPropertyGroupName(const PropertyName &) const;
     virtual int getPropertyRangeAndValue(const PropertyName &,
--- a/layer/SpectrogramLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SpectrogramLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -177,6 +177,14 @@
     return "";
 }
 
+QString
+SpectrogramLayer::getPropertyIconName(const PropertyName &name) const
+{
+    if (name == "Normalize Columns") return "normalise-columns";
+    if (name == "Normalize Visible Area") return "normalise";
+    return "";
+}
+
 Layer::PropertyType
 SpectrogramLayer::getPropertyType(const PropertyName &name) const
 {
--- a/layer/SpectrogramLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SpectrogramLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -79,6 +79,7 @@
 
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
+    virtual QString getPropertyIconName(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
     virtual QString getPropertyGroupName(const PropertyName &) const;
     virtual int getPropertyRangeAndValue(const PropertyName &,
--- a/layer/SpectrumLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SpectrumLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -136,6 +136,13 @@
     return SliceLayer::getPropertyLabel(name);
 }
 
+QString
+SpectrumLayer::getPropertyIconName(const PropertyName &name) const
+{
+    if (name == "Show Peak Frequencies") return "show-peaks";
+    return SliceLayer::getPropertyIconName(name);
+}
+
 Layer::PropertyType
 SpectrumLayer::getPropertyType(const PropertyName &name) const
 {
--- a/layer/SpectrumLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/SpectrumLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -52,6 +52,7 @@
 
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
+    virtual QString getPropertyIconName(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
     virtual QString getPropertyGroupName(const PropertyName &) const;
     virtual int getPropertyRangeAndValue(const PropertyName &,
--- a/layer/TextLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TextLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -448,6 +448,51 @@
 }
 
 void
+TextLayer::eraseStart(View *v, QMouseEvent *e)
+{
+    if (!m_model) return;
+
+    TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
+    if (points.empty()) return;
+
+    m_editingPoint = *points.begin();
+
+    if (m_editingCommand) {
+	m_editingCommand->finish();
+	m_editingCommand = 0;
+    }
+
+    m_editing = true;
+}
+
+void
+TextLayer::eraseDrag(View *v, QMouseEvent *e)
+{
+}
+
+void
+TextLayer::eraseEnd(View *v, QMouseEvent *e)
+{
+    if (!m_model || !m_editing) return;
+
+    m_editing = false;
+
+    TextModel::PointList points = getLocalPoints(v, e->x(), e->y());
+    if (points.empty()) return;
+    if (points.begin()->frame != m_editingPoint.frame ||
+        points.begin()->height != m_editingPoint.height) return;
+
+    m_editingCommand = new TextModel::EditCommand
+        (m_model, tr("Erase Point"));
+
+    m_editingCommand->deletePoint(m_editingPoint);
+
+    m_editingCommand->finish();
+    m_editingCommand = 0;
+    m_editing = false;
+}
+
+void
 TextLayer::editStart(View *v, QMouseEvent *e)
 {
 //    std::cerr << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
@@ -637,6 +682,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->height, i->label);
+            point.setReferenceFrame(m_model->alignToReference(i->frame));
             to.addPoint(point);
         }
     }
--- a/layer/TextLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TextLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -44,6 +44,10 @@
     virtual void drawDrag(View *v, QMouseEvent *);
     virtual void drawEnd(View *v, QMouseEvent *);
 
+    virtual void eraseStart(View *v, QMouseEvent *);
+    virtual void eraseDrag(View *v, QMouseEvent *);
+    virtual void eraseEnd(View *v, QMouseEvent *);
+
     virtual void editStart(View *v, QMouseEvent *);
     virtual void editDrag(View *v, QMouseEvent *);
     virtual void editEnd(View *v, QMouseEvent *);
--- a/layer/TimeInstantLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeInstantLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -493,6 +493,50 @@
 }
 
 void
+TimeInstantLayer::eraseStart(View *v, QMouseEvent *e)
+{
+    if (!m_model) return;
+
+    SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+
+    m_editingPoint = *points.begin();
+
+    if (m_editingCommand) {
+	m_editingCommand->finish();
+	m_editingCommand = 0;
+    }
+
+    m_editing = true;
+}
+
+void
+TimeInstantLayer::eraseDrag(View *v, QMouseEvent *e)
+{
+}
+
+void
+TimeInstantLayer::eraseEnd(View *v, QMouseEvent *e)
+{
+    if (!m_model || !m_editing) return;
+
+    m_editing = false;
+
+    SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+    if (points.begin()->frame != m_editingPoint.frame) return;
+
+    m_editingCommand = new SparseOneDimensionalModel::EditCommand
+        (m_model, tr("Erase Point"));
+
+    m_editingCommand->deletePoint(m_editingPoint);
+
+    m_editingCommand->finish();
+    m_editingCommand = 0;
+    m_editing = false;
+}
+
+void
 TimeInstantLayer::editStart(View *v, QMouseEvent *e)
 {
     std::cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << std::endl;
@@ -678,6 +722,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->label);
+            point.setReferenceFrame(m_model->alignToReference(i->frame));
             to.addPoint(point);
         }
     }
@@ -693,6 +738,19 @@
     SparseOneDimensionalModel::EditCommand *command =
 	new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste"));
 
+    //!!!
+    
+    // Clipboard::haveReferenceFrames() will return true if any of the
+    // items in the clipboard came from an aligned, non-reference model.
+    
+    // We need to know whether these points came from our model or not
+    // -- if they did, we don't want to align them.
+
+    // If they didn't come from our model, and if reference frames are
+    // available, then we want to offer to align them.  If reference
+    // frames are unavailable but they came from the reference model,
+    // we want to offer to align them too.
+
     for (Clipboard::PointList::const_iterator i = points.begin();
          i != points.end(); ++i) {
         
--- a/layer/TimeInstantLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeInstantLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -45,6 +45,10 @@
     virtual void drawDrag(View *v, QMouseEvent *);
     virtual void drawEnd(View *v, QMouseEvent *);
 
+    virtual void eraseStart(View *v, QMouseEvent *);
+    virtual void eraseDrag(View *v, QMouseEvent *);
+    virtual void eraseEnd(View *v, QMouseEvent *);
+
     virtual void editStart(View *v, QMouseEvent *);
     virtual void editDrag(View *v, QMouseEvent *);
     virtual void editEnd(View *v, QMouseEvent *);
--- a/layer/TimeRulerLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeRulerLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -15,6 +15,8 @@
 
 #include "TimeRulerLayer.h"
 
+#include "LayerFactory.h"
+
 #include "data/model/Model.h"
 #include "base/RealTime.h"
 #include "base/ColourDatabase.h"
@@ -314,6 +316,14 @@
         (QString(darkbg ? "White" : "Black"));
 }
 
+QString TimeRulerLayer::getLayerPresentationName() const
+{
+    LayerFactory *factory = LayerFactory::getInstance();
+    QString layerName = factory->getLayerPresentationName
+        (factory->getLayerType(this));
+    return layerName;
+}
+
 void
 TimeRulerLayer::toXml(QTextStream &stream,
                       QString indent, QString extraAttributes) const
--- a/layer/TimeRulerLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeRulerLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -51,6 +51,8 @@
         return false;
     }
 
+    virtual QString getLayerPresentationName() const;
+
     virtual void toXml(QTextStream &stream, QString indent = "",
                        QString extraAttributes = "") const;
 
--- a/layer/TimeValueLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeValueLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -940,6 +940,51 @@
 }
 
 void
+TimeValueLayer::eraseStart(View *v, QMouseEvent *e)
+{
+    if (!m_model) return;
+
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+
+    m_editingPoint = *points.begin();
+
+    if (m_editingCommand) {
+	m_editingCommand->finish();
+	m_editingCommand = 0;
+    }
+
+    m_editing = true;
+}
+
+void
+TimeValueLayer::eraseDrag(View *v, QMouseEvent *e)
+{
+}
+
+void
+TimeValueLayer::eraseEnd(View *v, QMouseEvent *e)
+{
+    if (!m_model || !m_editing) return;
+
+    m_editing = false;
+
+    SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
+    if (points.empty()) return;
+    if (points.begin()->frame != m_editingPoint.frame ||
+        points.begin()->value != m_editingPoint.value) return;
+
+    m_editingCommand = new SparseTimeValueModel::EditCommand
+        (m_model, tr("Erase Point"));
+
+    m_editingCommand->deletePoint(m_editingPoint);
+
+    m_editingCommand->finish();
+    m_editingCommand = 0;
+    m_editing = false;
+}
+
+void
 TimeValueLayer::editStart(View *v, QMouseEvent *e)
 {
 //    std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
@@ -1147,6 +1192,7 @@
 	 i != points.end(); ++i) {
 	if (s.contains(i->frame)) {
             Clipboard::Point point(i->frame, i->value, i->label);
+            point.setReferenceFrame(m_model->alignToReference(i->frame));
             to.addPoint(point);
         }
     }
--- a/layer/TimeValueLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/TimeValueLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -47,6 +47,10 @@
     virtual void drawDrag(View *v, QMouseEvent *);
     virtual void drawEnd(View *v, QMouseEvent *);
 
+    virtual void eraseStart(View *v, QMouseEvent *);
+    virtual void eraseDrag(View *v, QMouseEvent *);
+    virtual void eraseEnd(View *v, QMouseEvent *);
+
     virtual void editStart(View *v, QMouseEvent *);
     virtual void editDrag(View *v, QMouseEvent *);
     virtual void editEnd(View *v, QMouseEvent *);
--- a/layer/WaveformLayer.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/WaveformLayer.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -108,6 +108,13 @@
     return SingleColourLayer::getPropertyLabel(name);
 }
 
+QString
+WaveformLayer::getPropertyIconName(const PropertyName &name) const
+{
+    if (name == "Normalize Visible Area") return "normalise";
+    return "";
+}
+
 Layer::PropertyType
 WaveformLayer::getPropertyType(const PropertyName &name) const
 {
--- a/layer/WaveformLayer.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/layer/WaveformLayer.h	Fri Nov 23 16:48:23 2007 +0000
@@ -53,6 +53,7 @@
 
     virtual PropertyList getProperties() const;
     virtual QString getPropertyLabel(const PropertyName &) const;
+    virtual QString getPropertyIconName(const PropertyName &) const;
     virtual PropertyType getPropertyType(const PropertyName &) const;
     virtual QString getPropertyGroupName(const PropertyName &) const;
     virtual int getPropertyRangeAndValue(const PropertyName &,
--- a/view/Pane.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/view/Pane.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -1294,6 +1294,13 @@
 	    layer->drawStart(this, e);
 	}
 
+    } else if (mode == ViewManager::EraseMode) {
+
+	Layer *layer = getSelectedLayer();
+	if (layer && layer->isLayerEditable()) {
+	    layer->eraseStart(this, e);
+	}
+
     } else if (mode == ViewManager::EditMode) {
 
 	if (!editSelectionStart(e)) {
@@ -1379,6 +1386,14 @@
 	    update();
 	}
 
+    } else if (mode == ViewManager::EraseMode) {
+
+	Layer *layer = getSelectedLayer();
+	if (layer && layer->isLayerEditable()) {
+	    layer->eraseEnd(this, e);
+	    update();
+	}
+
     } else if (mode == ViewManager::EditMode) {
 
 	if (!editSelectionEnd(e)) {
@@ -1485,6 +1500,13 @@
 	    layer->drawDrag(this, e);
 	}
 
+    } else if (mode == ViewManager::EraseMode) {
+
+	Layer *layer = getSelectedLayer();
+	if (layer && layer->isLayerEditable()) {
+	    layer->eraseDrag(this, e);
+	}
+
     } else if (mode == ViewManager::EditMode) {
 
 	if (!editSelectionDrag(e)) {
@@ -2189,6 +2211,10 @@
     case ViewManager::DrawMode:
 	setCursor(Qt::CrossCursor);
 	break;
+	
+    case ViewManager::EraseMode:
+	setCursor(Qt::CrossCursor);
+	break;
 
     case ViewManager::MeasureMode:
         if (m_measureCursor1) setCursor(*m_measureCursor1);
@@ -2328,6 +2354,13 @@
 	if (editable) {
             help = tr("Click to add a new item in the active layer");
         }
+
+    } else if (mode == ViewManager::EraseMode) {
+        
+        //!!! could call through to a layer function to find out exact meaning
+	if (editable) {
+            help = tr("Click to erase an item from the active layer");
+        }
         
     } else if (mode == ViewManager::EditMode) {
         
--- a/view/ViewManager.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/view/ViewManager.h	Fri Nov 23 16:48:23 2007 +0000
@@ -66,18 +66,6 @@
     void setPlaybackFrame(unsigned long frame);
 
     // Only meaningful in solo mode, and used for optional alignment feature
-
-    //!!! We probably don't want to do this.  It's probably better to
-    // always have playback frame aligned against the reference model,
-    // and have the ViewManager know which is the reference model.
-    // That way the ViewManager can assume that all Views report in
-    // reference model timeline, and it can convert the playback frame
-    // received from the play source (which always operates in literal
-    // audio sample frames, i.e. playback model timeline) to the 
-    // reference timeline itself so the view never has to worry about
-    // the difference between playback and reference model.  Of course
-    // that does mean the ViewManager needs to know about both.
-
     Model *getPlaybackModel() const;
     void setPlaybackModel(Model *);
 
@@ -113,6 +101,7 @@
 	SelectMode,
         EditMode,
 	DrawMode,
+	EraseMode,
 	MeasureMode
     };
     ToolMode getToolMode() const { return m_toolMode; }
--- a/widgets/PropertyBox.cpp	Thu Nov 22 14:27:41 2007 +0000
+++ b/widgets/PropertyBox.cpp	Fri Nov 23 16:48:23 2007 +0000
@@ -29,9 +29,11 @@
 
 #include "AudioDial.h"
 #include "LEDButton.h"
+#include "IconLoader.h"
 
 #include "NotifyingCheckBox.h"
 #include "NotifyingComboBox.h"
+#include "NotifyingPushButton.h"
 #include "ColourNameDialog.h"
 
 #include <QGridLayout>
@@ -270,6 +272,7 @@
 
     QString groupName = m_container->getPropertyGroupName(name);
     QString propertyLabel = m_container->getPropertyLabel(name);
+    QString iconName = m_container->getPropertyIconName(name);
 
 #ifdef DEBUG_PROPERTY_BOX
     std::cerr << "PropertyBox[" << this
@@ -307,36 +310,45 @@
 
     case PropertyContainer::ToggleProperty:
     {
-        NotifyingCheckBox *cb;
+        QAbstractButton *button = 0;
 
 	if (have) {
-	    cb = dynamic_cast<NotifyingCheckBox *>(m_propertyControllers[name]);
-	    assert(cb);
+            button = dynamic_cast<QAbstractButton *>(m_propertyControllers[name]);
+            assert(button);
 	} else {
 #ifdef DEBUG_PROPERTY_BOX 
 	    std::cerr << "PropertyBox: creating new checkbox" << std::endl;
 #endif
-	    cb = new NotifyingCheckBox();
-	    cb->setObjectName(name);
-	    connect(cb, SIGNAL(stateChanged(int)),
-		    this, SLOT(propertyControllerChanged(int)));
-            connect(cb, SIGNAL(mouseEntered()),
+            if (iconName != "") {
+                button = new NotifyingPushButton();
+                button->setCheckable(true);
+                QIcon icon(IconLoader().load(iconName));
+                button->setIcon(icon);
+                button->setObjectName(name);
+                button->setFixedSize(QSize(18, 18));
+            } else {
+                button = new NotifyingCheckBox();
+                button->setObjectName(name);
+            }
+	    connect(button, SIGNAL(toggled(bool)),
+		    this, SLOT(propertyControllerChanged(bool)));
+            connect(button, SIGNAL(mouseEntered()),
                     this, SLOT(mouseEnteredWidget()));
-            connect(cb, SIGNAL(mouseLeft()),
+            connect(button, SIGNAL(mouseLeft()),
                     this, SLOT(mouseLeftWidget()));
 	    if (inGroup) {
-		cb->setToolTip(propertyLabel);
-		m_groupLayouts[groupName]->addWidget(cb);
+		button->setToolTip(propertyLabel);
+		m_groupLayouts[groupName]->addWidget(button);
 	    } else {
-		m_layout->addWidget(cb, row, 1, 1, 2);
+		m_layout->addWidget(button, row, 1, 1, 2);
 	    }
-	    m_propertyControllers[name] = cb;
+	    m_propertyControllers[name] = button;
 	}
 
-	if (cb->isChecked() != (value > 0)) {
-	    cb->blockSignals(true);
-	    cb->setChecked(value > 0);
-	    cb->blockSignals(false);
+        if (button->isChecked() != (value > 0)) {
+	    button->blockSignals(true);
+	    button->setChecked(value > 0);
+	    button->blockSignals(false);
 	}
 	break;
     }
@@ -577,6 +589,12 @@
 }    
 
 void
+PropertyBox::propertyControllerChanged(bool on)
+{
+    propertyControllerChanged(on ? 1 : 0);
+}
+
+void
 PropertyBox::propertyControllerChanged(int value)
 {
     QObject *obj = sender();
@@ -762,7 +780,7 @@
         emit contextHelpChanged(tr("Toggle Playback of %1").arg(cname));
     } else if (wname == "") {
         return;
-    } else if (dynamic_cast<NotifyingCheckBox *>(w)) {
+    } else if (dynamic_cast<QAbstractButton *>(w)) {
         emit contextHelpChanged(tr("Toggle %1 property of %2")
                                 .arg(wname).arg(cname));
     } else {
--- a/widgets/PropertyBox.h	Thu Nov 22 14:27:41 2007 +0000
+++ b/widgets/PropertyBox.h	Fri Nov 23 16:48:23 2007 +0000
@@ -54,6 +54,7 @@
 
 protected slots:
     void propertyControllerChanged(int);
+    void propertyControllerChanged(bool);
 
     void playGainChanged(float);
     void playGainDialChanged(int);