changeset 24:bb9291d84810

* Add ffwd/rewind * Abstract out MultiSelection
author Chris Cannam
date Wed, 08 Feb 2006 17:59:16 +0000
parents 6ace4286ba06
children 7dad8a310963
files base/Layer.h base/Selection.cpp base/Selection.h base/View.cpp base/ViewManager.cpp base/ViewManager.h
diffstat 6 files changed, 180 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/base/Layer.h	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/Layer.h	Wed Feb 08 17:59:16 2006 +0000
@@ -194,6 +194,15 @@
      */
     virtual void setProperties(const QXmlAttributes &) = 0;
 
+    /**
+     * Indicate that a layer is not currently visible and is not
+     * expected to become visible in the near future (for example
+     * because the user has explicitly removed or hidden it).  The
+     * layer may respond by (for example) freeing any cache memory it
+     * is using, until next time its paint method is called.
+     */
+    virtual void setLayerDormant() { }
+
 signals:
     void modelChanged();
     void modelCompletionChanged();
--- a/base/Selection.cpp	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/Selection.cpp	Wed Feb 08 17:59:16 2006 +0000
@@ -91,3 +91,98 @@
 	    m_endFrame == s.m_endFrame);
 }
 
+
+MultiSelection::MultiSelection()
+{
+}
+
+MultiSelection::~MultiSelection()
+{
+}
+
+const MultiSelection::SelectionList &
+MultiSelection::getSelections() const
+{
+    return m_selections;
+}
+
+void
+MultiSelection::setSelection(const Selection &selection)
+{
+    clearSelections();
+    addSelection(selection);
+}
+
+void
+MultiSelection::addSelection(const Selection &selection)
+{
+    m_selections.insert(selection);
+
+    // Cope with a sitation where the new selection overlaps one or
+    // more existing ones.  This is a terribly inefficient way to do
+    // this, but that probably isn't significant in real life.
+
+    // It's essential for the correct operation of
+    // getContainingSelection that the selections do not overlap, so
+    // this is not just a frill.
+
+    for (SelectionList::iterator i = m_selections.begin();
+	 i != m_selections.end(); ) {
+	
+	SelectionList::iterator j = i;
+	if (++j == m_selections.end()) break;
+
+	if (i->getEndFrame() >= j->getStartFrame()) {
+	    Selection merged(i->getStartFrame(),
+			     std::max(i->getEndFrame(), j->getEndFrame()));
+	    m_selections.erase(i);
+	    m_selections.erase(j);
+	    m_selections.insert(merged);
+	    i = m_selections.begin();
+	} else {
+	    ++i;
+	}
+    }
+}
+
+void
+MultiSelection::removeSelection(const Selection &selection)
+{
+    //!!! Likewise this needs to cope correctly with the situation
+    //where selection is not one of the original selection set but
+    //simply overlaps one of them (cutting down the original selection
+    //appropriately)
+
+    if (m_selections.find(selection) != m_selections.end()) {
+	m_selections.erase(selection);
+    }
+}
+
+void
+MultiSelection::clearSelections()
+{
+    if (!m_selections.empty()) {
+	m_selections.clear();
+    }
+}
+
+Selection
+MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing)
+{
+    // This scales very badly with the number of selections, but it's
+    // more efficient for very small numbers of selections than a more
+    // scalable method, and I think that may be what we need
+
+    for (SelectionList::const_iterator i = m_selections.begin();
+	 i != m_selections.end(); ++i) {
+
+	if (i->contains(frame)) return *i;
+
+	if (i->getStartFrame() > frame) {
+	    if (defaultToFollowing) return *i;
+	    else return Selection();
+	}
+    }
+
+    return Selection();
+}
--- a/base/Selection.h	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/Selection.h	Wed Feb 08 17:59:16 2006 +0000
@@ -11,6 +11,7 @@
 #define _SELECTION_H_
 
 #include <cstddef>
+#include <set>
 
 class Selection
 {
@@ -34,4 +35,31 @@
     size_t m_endFrame;
 };
 
+class MultiSelection
+{
+public:
+    MultiSelection();
+    virtual ~MultiSelection();
+
+    typedef std::set<Selection> SelectionList;
+
+    const SelectionList &getSelections() const;
+    void setSelection(const Selection &selection);
+    void addSelection(const Selection &selection);
+    void removeSelection(const Selection &selection);
+    void clearSelections();
+
+    /**
+     * Return the selection that contains a given frame.
+     * If defaultToFollowing is true, and if the frame is not in a
+     * selected area, return the next selection after the given frame.
+     * Return the empty selection if no appropriate selection is found.
+     */
+    Selection getContainingSelection(size_t frame, bool defaultToFollowing);
+
+protected:
+    SelectionList m_selections;
+};
+    
+
 #endif
--- a/base/View.cpp	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/View.cpp	Wed Feb 08 17:59:16 2006 +0000
@@ -544,7 +544,7 @@
 	if (m_manager &&
 	    m_manager->isPlaying() &&
 	    m_manager->getPlaySelectionMode()) {
-	    ViewManager::SelectionList selections = m_manager->getSelections();
+	    MultiSelection::SelectionList selections = m_manager->getSelections();
 	    if (!selections.empty()) {
 		size_t selectionStart = selections.begin()->getStartFrame();
 		if (sf < long(selectionStart) - w / 10) {
@@ -1110,7 +1110,7 @@
 void
 View::drawSelections(QPainter &paint)
 {
-    ViewManager::SelectionList selections;
+    MultiSelection::SelectionList selections;
 
     if (m_manager) {
 	selections = m_manager->getSelections();
@@ -1131,7 +1131,7 @@
 
     const QFontMetrics &metrics = paint.fontMetrics();
 
-    for (ViewManager::SelectionList::iterator i = selections.begin();
+    for (MultiSelection::SelectionList::iterator i = selections.begin();
 	 i != selections.end(); ++i) {
 
 	int p0 = getXForFrame(i->getStartFrame());
--- a/base/ViewManager.cpp	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/ViewManager.cpp	Wed Feb 08 17:59:16 2006 +0000
@@ -20,6 +20,7 @@
     m_playSource(0),
     m_globalCentreFrame(0),
     m_globalZoom(1024),
+    m_playbackFrame(0),
     m_lastLeft(0), 
     m_lastRight(0),
     m_inProgressExclusive(true),
@@ -54,6 +55,27 @@
     return m_globalZoom;
 }
 
+unsigned long
+ViewManager::getPlaybackFrame() const
+{
+    if (m_playSource && m_playSource->isPlaying()) {
+	m_playbackFrame = m_playSource->getCurrentPlayingFrame();
+    }
+    return m_playbackFrame;
+}
+
+void
+ViewManager::setPlaybackFrame(unsigned long f)
+{
+    if (m_playbackFrame != f) {
+	m_playbackFrame = f;
+	if (m_playSource && m_playSource->isPlaying()) {
+	    m_playSource->play(f);
+	}
+	emit playbackFrameChanged(f);
+    }
+}
+
 bool
 ViewManager::haveInProgressSelection() const
 {
@@ -83,95 +105,44 @@
     emit inProgressSelectionChanged();
 }
 
-const ViewManager::SelectionList &
+const MultiSelection::SelectionList &
 ViewManager::getSelections() const
 {
-    return m_selections;
+    return m_selections.getSelections();
 }
 
 void
 ViewManager::setSelection(const Selection &selection)
 {
-    clearSelections();
-    addSelection(selection);
+    m_selections.setSelection(selection);
+    emit selectionChanged();
 }
 
 void
 ViewManager::addSelection(const Selection &selection)
 {
-    m_selections.insert(selection);
-
-    // Cope with a sitation where the new selection overlaps one or
-    // more existing ones.  This is a terribly inefficient way to do
-    // this, but that probably isn't significant in real life.
-
-    // It's essential for the correct operation of
-    // getContainingSelection that the selections do not overlap, so
-    // this is not just a frill.
-
-    for (SelectionList::iterator i = m_selections.begin();
-	 i != m_selections.end(); ) {
-	
-	SelectionList::iterator j = i;
-	if (++j == m_selections.end()) break;
-
-	if (i->getEndFrame() >= j->getStartFrame()) {
-	    Selection merged(i->getStartFrame(),
-			     std::max(i->getEndFrame(), j->getEndFrame()));
-	    m_selections.erase(i);
-	    m_selections.erase(j);
-	    m_selections.insert(merged);
-	    i = m_selections.begin();
-	} else {
-	    ++i;
-	}
-    }
-
+    m_selections.addSelection(selection);
     emit selectionChanged();
 }
 
 void
 ViewManager::removeSelection(const Selection &selection)
 {
-    //!!! Likewise this needs to cope correctly with the situation
-    //where selection is not one of the original selection set but
-    //simply overlaps one of them (cutting down the original selection
-    //appropriately)
-
-    if (m_selections.find(selection) != m_selections.end()) {
-	m_selections.erase(selection);
-	emit selectionChanged();
-    }
+    m_selections.removeSelection(selection);
+    emit selectionChanged();
 }
 
 void
 ViewManager::clearSelections()
 {
-    if (!m_selections.empty()) {
-	m_selections.clear();
-	emit selectionChanged();
-    }
+    m_selections.clearSelections();
+    emit selectionChanged();
 }
 
 Selection
 ViewManager::getContainingSelection(size_t frame, bool defaultToFollowing)
 {
-    // This scales very badly with the number of selections, but it's
-    // more efficient for very small numbers of selections than a more
-    // scalable method, and I think that may be what we need
-
-    for (SelectionList::const_iterator i = m_selections.begin();
-	 i != m_selections.end(); ++i) {
-
-	if (i->contains(frame)) return *i;
-
-	if (i->getStartFrame() > frame) {
-	    if (defaultToFollowing) return *i;
-	    else return Selection();
-	}
-    }
-
-    return Selection();
+    return m_selections.getContainingSelection(frame, defaultToFollowing);
 }
 
 void
@@ -247,13 +218,13 @@
 	    }
 	}
 
-	m_globalCentreFrame = m_playSource->getCurrentPlayingFrame();
+	m_playbackFrame = m_playSource->getCurrentPlayingFrame();
 
 #ifdef DEBUG_VIEW_MANAGER
-	std::cout << "ViewManager::checkPlayStatus: Playing, frame " << m_globalCentreFrame << ", levels " << m_lastLeft << "," << m_lastRight << std::endl;
+	std::cout << "ViewManager::checkPlayStatus: Playing, frame " << m_playbackFrame << ", levels " << m_lastLeft << "," << m_lastRight << std::endl;
 #endif
 
-	emit playbackFrameChanged(m_globalCentreFrame);
+	emit playbackFrameChanged(m_playbackFrame);
 
 	QTimer::singleShot(20, this, SLOT(checkPlayStatus()));
 
@@ -296,11 +267,14 @@
 	unsigned long playFrame = m_playSource->getCurrentPlayingFrame();
 	unsigned long diff = std::max(f, playFrame) - std::min(f, playFrame);
 	if (diff > 20000) {
+	    m_playbackFrame = f;
 	    m_playSource->play(f);
 #ifdef DEBUG_VIEW_MANAGER 
 	    std::cout << "ViewManager::considerSeek: reseeking from " << playFrame << " to " << f << std::endl;
 #endif
 	}
+    } else {
+	m_playbackFrame = f; //!!! only if that view is in scroll mode?
     }
 }
 
--- a/base/ViewManager.h	Mon Feb 06 17:24:52 2006 +0000
+++ b/base/ViewManager.h	Wed Feb 08 17:59:16 2006 +0000
@@ -14,7 +14,6 @@
 #include <QTimer>
 
 #include <map>
-#include <set>
 
 #include "Selection.h"
 
@@ -50,14 +49,17 @@
     unsigned long getGlobalCentreFrame() const;
     unsigned long getGlobalZoom() const;
 
-    typedef std::set<Selection> SelectionList;
+    unsigned long getPlaybackFrame() const;
+    void setPlaybackFrame(unsigned long frame);
 
     bool haveInProgressSelection() const;
     const Selection &getInProgressSelection(bool &exclusive) const;
     void setInProgressSelection(const Selection &selection, bool exclusive);
     void clearInProgressSelection();
 
-    const SelectionList &getSelections() const;
+    const MultiSelection &getSelection() const;
+
+    const MultiSelection::SelectionList &getSelections() const;
     void setSelection(const Selection &selection);
     void addSelection(const Selection &selection);
     void removeSelection(const Selection &selection);
@@ -125,11 +127,12 @@
     AudioPlaySource *m_playSource;
     unsigned long m_globalCentreFrame;
     unsigned long m_globalZoom;
+    mutable unsigned long m_playbackFrame;
 
     float m_lastLeft;
     float m_lastRight;
 
-    SelectionList m_selections;
+    MultiSelection m_selections;
     Selection m_inProgressSelection;
     bool m_inProgressExclusive;