changeset 13:01849cd277e6

* Hook up tool selection buttons to switch the cursor mode * Implement simple and multi-selection, snapping to the resolution of the current layer. You can't actually do anything with a selection yet
author Chris Cannam
date Mon, 23 Jan 2006 17:02:57 +0000
parents 484e7320f59f
children aa37f84ab70a
files layer/SpectrogramLayer.cpp layer/SpectrogramLayer.h layer/TimeInstantLayer.cpp layer/TimeInstantLayer.h layer/TimeValueLayer.cpp layer/TimeValueLayer.h layer/WaveformLayer.cpp widgets/Pane.cpp widgets/Pane.h
diffstat 9 files changed, 287 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/layer/SpectrogramLayer.cpp	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/SpectrogramLayer.cpp	Mon Jan 23 17:02:57 2006 +0000
@@ -1636,6 +1636,17 @@
 		   ybase + 9 + fontAscent + fontHeight * 2, dBMaxText);
 }
 
+int
+SpectrogramLayer::getNearestFeatureFrame(int frame, 
+					 size_t &resolution,
+					 bool snapRight) const
+{
+    resolution = getWindowIncrement();
+    int snapFrame = (frame / resolution) * resolution;
+    if (snapRight) snapFrame += resolution;
+    return snapFrame;
+}
+
 /*!!!
 
 bool
--- a/layer/SpectrogramLayer.h	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/SpectrogramLayer.h	Mon Jan 23 17:02:57 2006 +0000
@@ -54,6 +54,10 @@
     virtual QRect getFeatureDescriptionRect(QPainter &, QPoint) const;
     virtual void paintLocalFeatureDescription(QPainter &, QRect, QPoint) const;
 
+    virtual int getNearestFeatureFrame(int frame, 
+				       size_t &resolution,
+				       bool snapRight = true) const;
+
     void setModel(const DenseTimeValueModel *model);
 
     virtual PropertyList getProperties() const;
--- a/layer/TimeInstantLayer.cpp	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/TimeInstantLayer.cpp	Mon Jan 23 17:02:57 2006 +0000
@@ -224,6 +224,38 @@
 		   points.begin()->label);
 }
 
+int
+TimeInstantLayer::getNearestFeatureFrame(int frame,
+					 size_t &resolution,
+					 bool snapRight) const
+{
+    if (!m_model) {
+	return Layer::getNearestFeatureFrame(frame, resolution, snapRight);
+    }
+
+    resolution = m_model->getResolution();
+    SparseOneDimensionalModel::PointList points(m_model->getPoints(frame, frame));
+
+    int returnFrame = frame;
+
+    for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin();
+	 i != points.end(); ++i) {
+
+	if (snapRight) {
+	    if (i->frame > frame) {
+		returnFrame = i->frame;
+		break;
+	    }
+	} else {
+	    if (i->frame <= frame) {
+		returnFrame = i->frame;
+	    }
+	}
+    }
+
+    return returnFrame;
+}
+
 void
 TimeInstantLayer::paint(QPainter &paint, QRect rect) const
 {
--- a/layer/TimeInstantLayer.h	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/TimeInstantLayer.h	Mon Jan 23 17:02:57 2006 +0000
@@ -31,6 +31,10 @@
     virtual QRect getFeatureDescriptionRect(QPainter &, QPoint) const;
     virtual void paintLocalFeatureDescription(QPainter &, QRect, QPoint) const;
 
+    virtual int getNearestFeatureFrame(int frame, 
+				       size_t &resolution,
+				       bool snapRight = true) const;
+
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseOneDimensionalModel *model);
 
--- a/layer/TimeValueLayer.cpp	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/TimeValueLayer.cpp	Mon Jan 23 17:02:57 2006 +0000
@@ -268,6 +268,38 @@
 		   points.begin()->label);
 }
 
+int
+TimeValueLayer::getNearestFeatureFrame(int frame,
+				       size_t &resolution,
+				       bool snapRight) const
+{
+    if (!m_model) {
+	return Layer::getNearestFeatureFrame(frame, resolution, snapRight);
+    }
+
+    resolution = m_model->getResolution();
+    SparseTimeValueModel::PointList points(m_model->getPoints(frame, frame));
+
+    int returnFrame = frame;
+
+    for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
+	 i != points.end(); ++i) {
+
+	if (snapRight) {
+	    if (i->frame > frame) {
+		returnFrame = i->frame;
+		break;
+	    }
+	} else {
+	    if (i->frame <= frame) {
+		returnFrame = i->frame;
+	    }
+	}
+    }
+
+    return returnFrame;
+}
+
 void
 TimeValueLayer::paint(QPainter &paint, QRect rect) const
 {
--- a/layer/TimeValueLayer.h	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/TimeValueLayer.h	Mon Jan 23 17:02:57 2006 +0000
@@ -31,6 +31,10 @@
     virtual QRect getFeatureDescriptionRect(QPainter &, QPoint) const;
     virtual void paintLocalFeatureDescription(QPainter &, QRect, QPoint) const;
 
+    virtual int getNearestFeatureFrame(int frame, 
+				       size_t &resolution,
+				       bool snapRight = true) const;
+
     virtual const Model *getModel() const { return m_model; }
     void setModel(SparseTimeValueModel *model);
 
--- a/layer/WaveformLayer.cpp	Thu Jan 19 17:59:11 2006 +0000
+++ b/layer/WaveformLayer.cpp	Mon Jan 23 17:02:57 2006 +0000
@@ -385,6 +385,8 @@
 	paint->setPen(Qt::black);
 	paint->setBrush(Qt::NoBrush);
 
+	paint->setRenderHint(QPainter::Antialiasing, false);
+
     } else {
 	paint = &viewPainter;
     }
--- a/widgets/Pane.cpp	Thu Jan 19 17:59:11 2006 +0000
+++ b/widgets/Pane.cpp	Mon Jan 23 17:02:57 2006 +0000
@@ -13,6 +13,7 @@
 #include "base/ZoomConstraint.h"
 #include "base/RealTime.h"
 #include "base/Profiler.h"
+#include "base/ViewManager.h"
 
 #include <QPaintEvent>
 #include <QPainter>
@@ -27,6 +28,7 @@
     m_identifyFeatures(false),
     m_clickedInRange(false),
     m_shiftPressed(false),
+    m_ctrlPressed(false),
     m_centreLineVisible(true)
 {
     setObjectName("Pane");
@@ -223,6 +225,8 @@
     }
 
     if (m_clickedInRange && m_shiftPressed) {
+	//!!! be nice if this looked a bit more in keeping with the
+	//selection block
 	paint.setPen(Qt::blue);
 	paint.drawRect(m_clickPos.x(), m_clickPos.y(),
 		       m_mousePos.x() - m_clickPos.x(),
@@ -238,7 +242,36 @@
     m_clickPos = e->pos();
     m_clickedInRange = true;
     m_shiftPressed = (e->modifiers() & Qt::ShiftModifier);
-    m_dragCentreFrame = m_centreFrame;
+    m_ctrlPressed = (e->modifiers() & Qt::ControlModifier);
+
+    ViewManager::ToolMode mode = ViewManager::NavigateMode;
+    if (m_manager) mode = m_manager->getToolMode();
+
+    if (mode == ViewManager::NavigateMode) {
+
+	m_dragCentreFrame = m_centreFrame;
+
+    } else if (mode == ViewManager::SelectMode) {
+
+	int mouseFrame = e->x() * m_zoomLevel + getStartFrame();
+	size_t resolution = 1;
+	int snapFrame = mouseFrame;
+	
+	Layer *layer = getSelectedLayer();
+	if (layer) {
+	    snapFrame = layer->getNearestFeatureFrame(mouseFrame, resolution,
+						      false);
+	}
+	
+	if (snapFrame < 0) snapFrame = 0;
+	m_selectionStartFrame = snapFrame;
+	if (m_manager) {
+	    m_manager->setInProgressSelection(Selection(snapFrame,
+							snapFrame + resolution),
+					      !m_ctrlPressed);
+	}
+	update();
+    }
 
     emit paneInteractedWith();
 }
@@ -246,37 +279,67 @@
 void
 Pane::mouseReleaseEvent(QMouseEvent *e)
 {
+    ViewManager::ToolMode mode = ViewManager::NavigateMode;
+    if (m_manager) mode = m_manager->getToolMode();
+
     if (m_clickedInRange) {
 	mouseMoveEvent(e);
     }
-    if (m_shiftPressed) {
 
-	int x0 = std::min(m_clickPos.x(), m_mousePos.x());
-	int x1 = std::max(m_clickPos.x(), m_mousePos.x());
-	int w = x1 - x0;
+    if (mode == ViewManager::NavigateMode) {
 
-	long newStartFrame = getStartFrame() + m_zoomLevel * x0;
+	if (m_shiftPressed) {
 
-	if (newStartFrame <= -long(width() * m_zoomLevel)) {
-	    newStartFrame  = -long(width() * m_zoomLevel) + 1;
+	    int x0 = std::min(m_clickPos.x(), m_mousePos.x());
+	    int x1 = std::max(m_clickPos.x(), m_mousePos.x());
+	    int w = x1 - x0;
+	    
+	    long newStartFrame = getStartFrame() + m_zoomLevel * x0;
+	    
+	    if (newStartFrame <= -long(width() * m_zoomLevel)) {
+		newStartFrame  = -long(width() * m_zoomLevel) + 1;
+	    }
+	    
+	    if (newStartFrame >= long(getModelsEndFrame())) {
+		newStartFrame  = getModelsEndFrame() - 1;
+	    }
+	    
+	    float ratio = float(w) / float(width());
+//	std::cerr << "ratio: " << ratio << std::endl;
+	    size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
+	    if (newZoomLevel < 1) newZoomLevel = 1;
+
+//	std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
+	    setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
+	    setStartFrame(newStartFrame);
+
+	    //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
+//	update();
 	}
 
-	if (newStartFrame >= long(getModelsEndFrame())) {
-	    newStartFrame  = getModelsEndFrame() - 1;
+    } else if (mode == ViewManager::SelectMode) {
+
+	if (m_manager && m_manager->haveInProgressSelection()) {
+
+	    bool exclusive;
+	    Selection selection = m_manager->getInProgressSelection(exclusive);
+	    
+	    if (selection.getEndFrame() < selection.getStartFrame() + 2) {
+		selection = Selection();
+	    }
+	    
+	    m_manager->clearInProgressSelection();
+	    
+	    if (exclusive) {
+		m_manager->setSelection(selection);
+	    } else {
+		m_manager->addSelection(selection);
+	    }
 	}
+	
+	update();
+    } 
 
-	float ratio = float(w) / float(width());
-//	std::cerr << "ratio: " << ratio << std::endl;
-	size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio);
-	if (newZoomLevel < 1) newZoomLevel = 1;
-
-//	std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl;
-	setZoomLevel(getZoomConstraintBlockSize(newZoomLevel));
-	setStartFrame(newStartFrame);
-
-	//cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl;
-//	update();
-    }
     m_clickedInRange = false;
 
     emit paneInteractedWith();
@@ -285,6 +348,9 @@
 void
 Pane::mouseMoveEvent(QMouseEvent *e)
 {
+    ViewManager::ToolMode mode = ViewManager::NavigateMode;
+    if (m_manager) mode = m_manager->getToolMode();
+
     if (!m_clickedInRange) {
 	
 //	std::cerr << "Pane: calling identifyLocalFeatures" << std::endl;
@@ -302,35 +368,90 @@
 	    update();
 	}
 
-    } else if (m_shiftPressed) {
+	return;
+	
+    }
 
-	m_mousePos = e->pos();
-	update();
+    if (mode == ViewManager::NavigateMode) {
 
-    } else {
+	if (m_shiftPressed) {
 
-	long xoff = int(e->x()) - int(m_clickPos.x());
-	long frameOff = xoff * m_zoomLevel;
+	    m_mousePos = e->pos();
+	    update();
 
-	size_t newCentreFrame = m_dragCentreFrame;
-	
-	if (frameOff < 0) {
-	    newCentreFrame -= frameOff;
-	} else if (newCentreFrame >= size_t(frameOff)) {
-	    newCentreFrame -= frameOff;
 	} else {
-	    newCentreFrame = 0;
+
+	    long xoff = int(e->x()) - int(m_clickPos.x());
+	    long frameOff = xoff * m_zoomLevel;
+	    
+	    size_t newCentreFrame = m_dragCentreFrame;
+	    
+	    if (frameOff < 0) {
+		newCentreFrame -= frameOff;
+	    } else if (newCentreFrame >= size_t(frameOff)) {
+		newCentreFrame -= frameOff;
+	    } else {
+		newCentreFrame = 0;
+	    }
+	    
+	    if (newCentreFrame >= getModelsEndFrame()) {
+		newCentreFrame = getModelsEndFrame();
+		if (newCentreFrame > 0) --newCentreFrame;
+	    }
+	    
+	    if (std::max(m_centreFrame, newCentreFrame) -
+		std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
+		setCentreFrame(newCentreFrame);
+	    }
 	}
 
-	if (newCentreFrame >= getModelsEndFrame()) {
-	    newCentreFrame = getModelsEndFrame();
-	    if (newCentreFrame > 0) --newCentreFrame;
+    } else if (mode == ViewManager::SelectMode) {
+
+	int mouseFrame = e->x() * m_zoomLevel + getStartFrame();
+	size_t resolution = 1;
+	int snapFrameLeft = mouseFrame;
+	int snapFrameRight = mouseFrame;
+	
+	Layer *layer = getSelectedLayer();
+	if (layer) {
+	    snapFrameLeft = layer->getNearestFeatureFrame(mouseFrame, resolution,
+							  false);
+	    snapFrameRight = layer->getNearestFeatureFrame(mouseFrame, resolution,
+							   true);
+	}
+	
+	if (snapFrameLeft < 0) snapFrameLeft = 0;
+	if (snapFrameRight < 0) snapFrameRight = 0;
+	
+	size_t min, max;
+	
+	if (m_selectionStartFrame > snapFrameLeft) {
+	    min = snapFrameLeft;
+	    max = m_selectionStartFrame;
+	} else if (snapFrameRight > m_selectionStartFrame) {
+	    min = m_selectionStartFrame;
+	    max = snapFrameRight;
+	} else {
+	    min = snapFrameLeft;
+	    max = snapFrameRight;
 	}
 
-	if (std::max(m_centreFrame, newCentreFrame) -
-	    std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) {
-	    setCentreFrame(newCentreFrame);
+	if (m_manager) {
+	    m_manager->setInProgressSelection(Selection(min, max),
+					      !m_ctrlPressed);
 	}
+	
+	if (!m_manager || !m_manager->isPlaying()) {
+	    int offset = mouseFrame - getStartFrame();
+	    int available = getEndFrame() - getStartFrame();
+	    if (offset >= available * 0.9) {
+		setCentreFrame(m_centreFrame + int(offset - available * 0.9) + 1);
+	    } else if (offset <= available * 0.15) {
+		setCentreFrame(m_centreFrame - int(available * 0.15 - offset) - 1);
+	    }
+	}
+
+	update();
     }
 }
 
@@ -390,6 +511,36 @@
     emit paneInteractedWith();
 }
 
+void
+Pane::toolModeChanged()
+{
+    ViewManager::ToolMode mode = m_manager->getToolMode();
+    std::cerr << "Pane::toolModeChanged(" << mode << ")" << std::endl;
+
+    switch (mode) {
+
+    case ViewManager::NavigateMode:
+	setCursor(Qt::PointingHandCursor);
+	break;
+	
+    case ViewManager::SelectMode:
+	setCursor(Qt::ArrowCursor);
+	break;
+	
+    case ViewManager::EditMode:
+	setCursor(Qt::SizeAllCursor);
+	break;
+	
+    case ViewManager::DrawMode:
+	setCursor(Qt::CrossCursor);
+	break;
+	
+    case ViewManager::TextMode:
+	setCursor(Qt::IBeamCursor);
+	break;
+    }
+}
+
 QString
 Pane::toXmlString(QString indent, QString extraAttributes) const
 {
--- a/widgets/Pane.h	Thu Jan 19 17:59:11 2006 +0000
+++ b/widgets/Pane.h	Mon Jan 23 17:02:57 2006 +0000
@@ -16,6 +16,7 @@
 
 #include "base/ZoomConstraint.h"
 #include "base/View.h"
+#include "base/Selection.h"
 
 class QWidget;
 class QPaintEvent;
@@ -40,6 +41,9 @@
 signals:
     void paneInteractedWith();
 
+public slots:
+    virtual void toolModeChanged();
+
 protected:
     virtual void paintEvent(QPaintEvent *e);
     virtual void mousePressEvent(QMouseEvent *e);
@@ -55,8 +59,10 @@
     QPoint m_mousePos;
     bool m_clickedInRange;
     bool m_shiftPressed;
+    bool m_ctrlPressed;
     size_t m_dragCentreFrame;
     bool m_centreLineVisible;
+    size_t m_selectionStartFrame;
 };
 
 #endif