changeset 42:1bdf285c4eac

* Add "Export Audio File" option * Make note layer align in frequency with any spectrogram layer on the same view (if it's set to frequency mode) * Start to implement mouse editing for ranges of points by dragging the selection * First scrappy attempt at a vertical scale for time value layer
author Chris Cannam
date Mon, 27 Feb 2006 17:34:41 +0000
parents f2c416cbdaa9
children 78515b1e29eb
files layer/NoteLayer.cpp layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h widgets/Pane.cpp widgets/Pane.h
diffstat 7 files changed, 205 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/layer/NoteLayer.cpp	Fri Feb 24 17:26:11 2006 +0000
+++ b/layer/NoteLayer.cpp	Mon Feb 27 17:34:41 2006 +0000
@@ -17,6 +17,8 @@
 
 #include "model/NoteModel.h"
 
+#include "SpectrogramLayer.h" // for optional frequency alignment
+
 #include <QPainter>
 #include <QPainterPath>
 #include <QMouseEvent>
@@ -353,7 +355,7 @@
 NoteLayer::getYForValue(float value) const
 {
     float min, max, h = m_view->height();
-    
+
     switch (m_verticalScale) {
 
     case MIDIRangeScale:
@@ -367,12 +369,26 @@
 	break;
 
     case FrequencyScale:
+    
+	value = Pitch::getFrequencyForPitch(lrintf(value),
+					    value - lrintf(value));
+
+	// If we have a spectrogram layer on the same view as us, align
+	// ourselves with it...
+	for (int i = 0; i < m_view->getLayerCount(); ++i) {
+	    SpectrogramLayer *spectrogram = dynamic_cast<SpectrogramLayer *>
+		(m_view->getLayer(i));
+	    if (spectrogram) {
+		return spectrogram->getYForFrequency(value);
+	    }
+	}
+
+	// ...otherwise just interpolate
 	std::cerr << "FrequencyScale: value in = " << value << std::endl;
 	min = m_model->getValueMinimum();
 	min = Pitch::getFrequencyForPitch(lrintf(min), min - lrintf(min));
 	max = m_model->getValueMaximum();
 	max = Pitch::getFrequencyForPitch(lrintf(max), max - lrintf(max));
-	value = Pitch::getFrequencyForPitch(lrintf(value), value - lrintf(value));
 	std::cerr << "FrequencyScale: min = " << min << ", max = " << max << ", value = " << value << std::endl;
 	break;
     }
--- a/layer/SpectrogramLayer.cpp	Fri Feb 24 17:26:11 2006 +0000
+++ b/layer/SpectrogramLayer.cpp	Mon Feb 27 17:34:41 2006 +0000
@@ -2031,6 +2031,24 @@
 #endif
 }
 
+float
+SpectrogramLayer::getYForFrequency(float frequency) const
+{
+    return m_view->getYForFrequency(frequency,
+				    getEffectiveMinFrequency(),
+				    getEffectiveMaxFrequency(),
+				    m_frequencyScale == LogFrequencyScale);
+}
+
+float
+SpectrogramLayer::getFrequencyForY(int y) const
+{
+    return m_view->getFrequencyForY(y,
+				    getEffectiveMinFrequency(),
+				    getEffectiveMaxFrequency(),
+				    m_frequencyScale == LogFrequencyScale);
+}
+
 int
 SpectrogramLayer::getCompletion() const
 {
--- a/layer/SpectrogramLayer.h	Fri Feb 24 17:26:11 2006 +0000
+++ b/layer/SpectrogramLayer.h	Mon Feb 27 17:34:41 2006 +0000
@@ -169,6 +169,9 @@
 
     virtual bool isLayerOpaque() const { return true; }
 
+    float getYForFrequency(float frequency) const;
+    float getFrequencyForY(int y) const;
+
     virtual int getCompletion() const;
 
     virtual QString toXmlString(QString indent = "",
--- a/layer/TimeValueLayer.cpp	Fri Feb 24 17:26:11 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Mon Feb 27 17:34:41 2006 +0000
@@ -543,6 +543,32 @@
     paint.setRenderHint(QPainter::Antialiasing, false);
 }
 
+int
+TimeValueLayer::getVerticalScaleWidth(QPainter &paint) const
+{
+    return 100; //!!!
+}
+
+void
+TimeValueLayer::paintVerticalScale(QPainter &paint, QRect rect) const
+{
+    if (!m_model) return;
+
+    float v = m_model->getValueMinimum();
+    float inc = (m_model->getValueMaximum() - v) / 10;
+
+    while (v < m_model->getValueMaximum()) {
+	int y = getYForValue(v);
+	QString label = QString("%1").arg(v);
+	paint.drawLine(100 - 10, y, 100, y);
+	paint.drawText(100 - 15 - paint.fontMetrics().width(label),
+		       y - paint.fontMetrics().height() /2 + paint.fontMetrics().ascent(),
+		       label);
+	v += inc;
+    }
+
+}
+
 void
 TimeValueLayer::drawStart(QMouseEvent *e)
 {
--- a/layer/TimeValueLayer.h	Fri Feb 24 17:26:11 2006 +0000
+++ b/layer/TimeValueLayer.h	Mon Feb 27 17:34:41 2006 +0000
@@ -28,6 +28,9 @@
 
     virtual void paint(QPainter &paint, QRect rect) const;
 
+    virtual int getVerticalScaleWidth(QPainter &) const;
+    virtual void paintVerticalScale(QPainter &paint, QRect rect) const;
+
     virtual QString getFeatureDescription(QPoint &) const;
 
     virtual bool snapToFeatureFrame(int &frame,
--- a/widgets/Pane.cpp	Fri Feb 24 17:26:11 2006 +0000
+++ b/widgets/Pane.cpp	Mon Feb 27 17:34:41 2006 +0000
@@ -41,7 +41,12 @@
 bool
 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos)
 {
-    if (layer == getSelectedLayer()) {
+    QPoint discard;
+    bool b0, b1;
+
+    if (layer == getSelectedLayer() &&
+	!shouldIlluminateLocalSelection(discard, b0, b1)) {
+
 	pos = m_identifyPoint;
 	return m_identifyFeatures;
     }
@@ -49,6 +54,44 @@
     return false;
 }
 
+bool
+Pane::shouldIlluminateLocalSelection(QPoint &pos,
+				     bool &closeToLeft,
+				     bool &closeToRight)
+{
+    if (m_identifyFeatures &&
+	m_manager &&
+	m_manager->getToolMode() == ViewManager::EditMode &&
+	!m_manager->getSelections().empty() &&
+	!selectionIsBeingEdited()) {
+
+	Selection s(getSelectionAt(m_identifyPoint.x(),
+				   closeToLeft, closeToRight));
+
+	if (!s.isEmpty()) {
+	    if (getSelectedLayer() && getSelectedLayer()->isLayerEditable()) {
+		
+		pos = m_identifyPoint;
+		return true;
+	    }
+	}
+    }
+
+    return false;
+}
+
+bool
+Pane::selectionIsBeingEdited() const
+{
+    if (!m_editingSelection.isEmpty()) {
+	if (m_mousePos != m_clickPos &&
+	    getFrameForX(m_mousePos.x()) != getFrameForX(m_clickPos.x())) {
+	    return true;
+	}
+    }
+    return false;
+}
+
 void
 Pane::setCentreLineVisible(bool visible)
 {
@@ -281,6 +324,42 @@
 	}
     }
     
+    if (selectionIsBeingEdited()) {
+
+	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());
+	}
+
+	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();
+    }
+
     paint.end();
 }
 
@@ -322,6 +401,8 @@
 {
     m_clickPos = e->pos();
     m_clickedInRange = true;
+    m_editingSelection = Selection();
+    m_editingSelectionEdge = 0;
     m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
     m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
 
@@ -390,9 +471,11 @@
 
     } else if (mode == ViewManager::EditMode) {
 
-	Layer *layer = getSelectedLayer();
-	if (layer && layer->isLayerEditable()) {
-	    layer->editStart(e);
+	if (!editSelectionStart(e)) {
+	    Layer *layer = getSelectedLayer();
+	    if (layer && layer->isLayerEditable()) {
+		layer->editStart(e);
+	    }
 	}
     }
 
@@ -480,10 +563,12 @@
 
     } else if (mode == ViewManager::EditMode) {
 
-	Layer *layer = getSelectedLayer();
-	if (layer && layer->isLayerEditable()) {
-	    layer->editEnd(e);
-	    update();
+	if (!editSelectionEnd(e)) {
+	    Layer *layer = getSelectedLayer();
+	    if (layer && layer->isLayerEditable()) {
+		layer->editEnd(e);
+		update();
+	    }
 	}
     }
 
@@ -626,9 +711,11 @@
 
     } else if (mode == ViewManager::EditMode) {
 
-	Layer *layer = getSelectedLayer();
-	if (layer && layer->isLayerEditable()) {
-	    layer->editDrag(e);
+	if (!editSelectionDrag(e)) {
+	    Layer *layer = getSelectedLayer();
+	    if (layer && layer->isLayerEditable()) {
+		layer->editDrag(e);
+	    }
 	}
     }
 }
@@ -727,6 +814,35 @@
     emit paneInteractedWith();
 }
 
+bool
+Pane::editSelectionStart(QMouseEvent *e)
+{
+    bool closeToLeft, closeToRight;
+    Selection s(getSelectionAt(e->x(), closeToLeft, closeToRight));
+    if (s.isEmpty()) return false;
+    m_editingSelection = s;
+    m_editingSelectionEdge = (closeToLeft ? -1 : closeToRight ? 1 : 0);
+    m_mousePos = e->pos();
+    return true;
+}
+
+bool
+Pane::editSelectionDrag(QMouseEvent *e)
+{
+    if (m_editingSelection.isEmpty()) return false;
+    m_mousePos = e->pos();
+    update();
+    return true;
+}
+
+bool
+Pane::editSelectionEnd(QMouseEvent *e)
+{
+    if (m_editingSelection.isEmpty()) return false;
+    m_editingSelection = Selection();
+    return true;
+}
+
 void
 Pane::toolModeChanged()
 {
--- a/widgets/Pane.h	Fri Feb 24 17:26:11 2006 +0000
+++ b/widgets/Pane.h	Mon Feb 27 17:34:41 2006 +0000
@@ -31,6 +31,9 @@
     virtual QString getPropertyContainerIconName() const { return "pane"; }
 
     virtual bool shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos);
+    virtual bool shouldIlluminateLocalSelection(QPoint &pos,
+						bool &closeToLeft,
+						bool &closeToRight);
 
     void setCentreLineVisible(bool visible);
     bool getCentreLineVisible() const { return m_centreLineVisible; }
@@ -55,6 +58,11 @@
 
     Selection getSelectionAt(int x, bool &closeToLeft, bool &closeToRight);
 
+    bool editSelectionStart(QMouseEvent *e);
+    bool editSelectionDrag(QMouseEvent *e);
+    bool editSelectionEnd(QMouseEvent *e);
+    bool selectionIsBeingEdited() const;
+
     bool m_identifyFeatures;
     QPoint m_identifyPoint;
     QPoint m_clickPos;
@@ -67,6 +75,8 @@
     size_t m_dragCentreFrame;
     bool m_centreLineVisible;
     size_t m_selectionStartFrame;
+    Selection m_editingSelection;
+    int m_editingSelectionEdge;
 };
 
 #endif