changeset 46:5364a9d338a2

* Add Insert Instant function in main window * Ensure selections and window geometry are saved in session file * Add wait cursor on session file save * Various improvements to display of texts in pane (clearer readability) * Use commands for setting properties on layers and panes (still need to batch up multiple sets on the same property) * Fix failure of spectrogram to refresh when initial part became visible * Some fixes & paint optimisations in View &c * Make curve mode for time value layers work properly when resolution == 1 * Some vague improvements for time value layer vertical scale
author Chris Cannam
date Thu, 16 Mar 2006 18:46:00 +0000
parents b11edc8b8ea0
children bac8b14ab355
files base/CommandHistory.cpp base/CommandHistory.h base/PropertyContainer.cpp base/PropertyContainer.h base/Selection.cpp base/Selection.h base/View.cpp base/View.h
diffstat 8 files changed, 169 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/base/CommandHistory.cpp	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/CommandHistory.cpp	Thu Mar 16 18:46:00 2006 +0000
@@ -33,6 +33,7 @@
 CommandHistory::CommandHistory() :
     m_undoLimit(50),
     m_redoLimit(50),
+    m_menuLimit(15),
     m_savedAt(0),
     m_currentMacro(0),
     m_executeMacro(false)
@@ -112,7 +113,7 @@
 	return;
     }
 
-    std::cerr << "MVCH::addCommand: " << command->getName().toLocal8Bit().data() << std::endl;
+    std::cerr << "MVCH::addCommand: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl;
 
     // We can't redo after adding a command
     clearStack(m_redoStack);
@@ -241,6 +242,13 @@
 }
 
 void
+CommandHistory::setMenuLimit(int limit)
+{
+    m_menuLimit = limit;
+    updateActions();
+}
+
+void
 CommandHistory::documentSaved()
 {
     m_savedAt = m_undoStack.size();
@@ -287,7 +295,8 @@
 {
     while (!stack.empty()) {
 	Command *command = stack.top();
-	std::cerr << "MVCH::clearStack: About to delete command: " << command->getName().toLocal8Bit().data() << " at " << command << std::endl;
+	// Not safe to call getName() on a command about to be deleted
+	std::cerr << "MVCH::clearStack: About to delete command " << command << std::endl;
 	delete command;
 	stack.pop();
     }
@@ -353,7 +362,7 @@
 	CommandStack tempStack;
 	int j = 0;
 
-	while (j < 10 && !stack.empty()) {
+	while (j < m_menuLimit && !stack.empty()) {
 
 	    Command *command = stack.top();
 	    tempStack.push(command);
--- a/base/CommandHistory.h	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/CommandHistory.h	Thu Mar 16 18:46:00 2006 +0000
@@ -60,17 +60,23 @@
     void addCommand(Command *command, bool execute = true);
     
     /// Return the maximum number of items in the undo history.
-    int undoLimit() { return m_undoLimit; }
+    int getUndoLimit() const { return m_undoLimit; }
 
     /// Set the maximum number of items in the undo history.
     void setUndoLimit(int limit);
 
     /// Return the maximum number of items in the redo history.
-    int redoLimit() { return m_redoLimit; }
+    int getRedoLimit() const { return m_redoLimit; }
 
     /// Set the maximum number of items in the redo history.
     void setRedoLimit(int limit);
     
+    /// Return the maximum number of items visible in undo and redo menus.
+    int getMenuLimit() const { return m_menuLimit; }
+
+    /// Set the maximum number of items in the menus.
+    void setMenuLimit(int limit);
+
     /// Start recording commands to batch up into a single compound command.
     void startCompoundOperation(QString name, bool execute);
 
@@ -148,6 +154,7 @@
 
     int m_undoLimit;
     int m_redoLimit;
+    int m_menuLimit;
     int m_savedAt;
 
     MacroCommand *m_currentMacro;
--- a/base/PropertyContainer.cpp	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/PropertyContainer.cpp	Thu Mar 16 18:46:00 2006 +0000
@@ -8,6 +8,9 @@
 */
 
 #include "PropertyContainer.h"
+#include "CommandHistory.h"
+
+#include <iostream>
 
 PropertyContainer::PropertyList
 PropertyContainer::getProperties() const
@@ -42,7 +45,47 @@
 }
 
 void
-PropertyContainer::setProperty(const PropertyName &, int) 
+PropertyContainer::setProperty(const PropertyName &name, int) 
+{
+    std::cerr << "WARNING: PropertyContainer[" << getPropertyContainerName().toStdString() << "]::setProperty(" << name.toStdString() << "): no implementation in subclass!" << std::endl;
+}
+
+void
+PropertyContainer::setPropertyWithCommand(const PropertyName &name, int value)
+{
+    int currentValue = getPropertyRangeAndValue(name, 0, 0);
+    if (value == currentValue) return;
+
+    CommandHistory::getInstance()->addCommand
+	(new SetPropertyCommand(this, name, value));
+}
+
+PropertyContainer::SetPropertyCommand::SetPropertyCommand(PropertyContainer *pc,
+							  const PropertyName &pn,
+							  int value) :
+    m_pc(pc),
+    m_pn(pn),
+    m_value(value),
+    m_oldValue(0)
 {
 }
 
+void
+PropertyContainer::SetPropertyCommand::execute()
+{
+    m_oldValue = m_pc->getPropertyRangeAndValue(m_pn, 0, 0);
+    m_pc->setProperty(m_pn, m_value);
+}
+
+void
+PropertyContainer::SetPropertyCommand::unexecute() 
+{
+    m_pc->setProperty(m_pn, m_oldValue);
+}
+
+QString
+PropertyContainer::SetPropertyCommand::getName() const
+{
+    return m_pc->tr("Set %1 Property").arg(m_pn);
+}
+
--- a/base/PropertyContainer.h	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/PropertyContainer.h	Thu Mar 16 18:46:00 2006 +0000
@@ -10,6 +10,8 @@
 #ifndef _PROPERTY_CONTAINER_H_
 #define _PROPERTY_CONTAINER_H_
 
+#include "Command.h"
+
 #include <QString>
 #include <QObject>
 #include <vector>
@@ -89,6 +91,30 @@
      * colours, the integer value should be treated as a qRgb.
      */
     virtual void setProperty(const PropertyName &, int value);
+
+    /**
+     * Set a property using a command, supporting undo and redo.
+     */
+    virtual void setPropertyWithCommand(const PropertyName &, int value);
+
+protected:
+
+    class SetPropertyCommand : public Command
+    {
+    public:
+	SetPropertyCommand(PropertyContainer *pc, const PropertyName &pn, int);
+	virtual ~SetPropertyCommand() { }
+
+	virtual void execute();
+	virtual void unexecute();
+	virtual QString getName() const;
+
+    protected:
+	PropertyContainer *m_pc;
+	PropertyName m_pn;
+	int m_value;
+	int m_oldValue;
+    };
 };
 
 #endif
--- a/base/Selection.cpp	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/Selection.cpp	Thu Mar 16 18:46:00 2006 +0000
@@ -186,3 +186,19 @@
 
     return Selection();
 }
+
+QString
+MultiSelection::toXmlString(QString indent,
+			    QString extraAttributes) const
+{
+    QString s;
+    s += indent + QString("<selections %1>\n").arg(extraAttributes);
+    for (SelectionList::iterator i = m_selections.begin();
+	 i != m_selections.end(); ++i) {
+	s += indent + QString("  <selection start=\"%1\" end=\"%2\"/>\n")
+	    .arg(i->getStartFrame()).arg(i->getEndFrame());
+    }
+    s += indent + "</selections>\n";
+    return s;
+}
+
--- a/base/Selection.h	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/Selection.h	Thu Mar 16 18:46:00 2006 +0000
@@ -13,6 +13,8 @@
 #include <cstddef>
 #include <set>
 
+#include "XmlExportable.h"
+
 class Selection
 {
 public:
@@ -35,7 +37,7 @@
     size_t m_endFrame;
 };
 
-class MultiSelection
+class MultiSelection : public XmlExportable
 {
 public:
     MultiSelection();
@@ -57,6 +59,9 @@
      */
     Selection getContainingSelection(size_t frame, bool defaultToFollowing) const;
 
+    virtual QString toXmlString(QString indent = "",
+				QString extraAttributes = "") const;
+
 protected:
     SelectionList m_selections;
 };
--- a/base/View.cpp	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/View.cpp	Thu Mar 16 18:46:00 2006 +0000
@@ -470,9 +470,40 @@
 }
 
 void
-View::drawVisibleText(int x, int y, QString text, TextStyle style)
+View::drawVisibleText(QPainter &paint, int x, int y, QString text, TextStyle style)
 {
-    //!!! blah.
+    if (style == OutlinedText) {
+
+	QColor origPenColour = paint.pen().color();
+	QColor penColour = origPenColour;
+	QColor surroundColour = Qt::white;  //palette().background().color();
+
+	if (!hasLightBackground()) {
+	    int h, s, v;
+	    penColour.getHsv(&h, &s, &v);
+	    penColour = QColor::fromHsv(h, s, 255 - v);
+	    surroundColour = Qt::black;
+	}
+
+	paint.setPen(surroundColour);
+
+	for (int dx = -1; dx <= 1; ++dx) {
+	    for (int dy = -1; dy <= 1; ++dy) {
+		if (!(dx || dy)) continue;
+		paint.drawText(x + dx, y + dy, text);
+	    }
+	}
+
+	paint.setPen(penColour);
+
+	paint.drawText(x, y, text);
+
+	paint.setPen(origPenColour);
+
+    } else {
+
+	std::cerr << "ERROR: View::drawVisibleText: Boxed style not yet implemented!" << std::endl;
+    }
 }
 
 void
@@ -811,26 +842,18 @@
 {
     changed = false;
 
+    // We want a list of all the scrollable layers that are behind the
+    // backmost non-scrollable layer.
+
     LayerList scrollables;
     for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
 	if ((*i)->isLayerDormant(this)) continue;
+	if ((*i)->isLayerOpaque()) {
+	    // You can't see anything behind an opaque layer!
+	    scrollables.clear();
+	}
 	if ((*i)->isLayerScrollable(this)) scrollables.push_back(*i);
-	else {
-	    if (testChanged && scrollables != m_lastScrollableBackLayers) {
-		m_lastScrollableBackLayers = scrollables;
-		changed = true;
-	    }
-	    return scrollables;
-	}
-    }
-
-    if (scrollables.size() == 1 &&
-	dynamic_cast<TimeRulerLayer *>(*scrollables.begin())) {
-
-	// If only the ruler is scrollable, it's not worth the bother
-	// -- it probably redraws as quickly as it refreshes from
-	// cache
-	scrollables.clear();
+	else break;
     }
 
     if (testChanged && scrollables != m_lastScrollableBackLayers) {
@@ -850,13 +873,18 @@
     // Everything in front of the first non-scrollable from the back
     // should also be considered non-scrollable
 
-    size_t count = 0;
+    bool started = false;
+
     for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) {
 	if ((*i)->isLayerDormant(this)) continue;
-	if (count < scrollables.size()) {
-	    ++count;
+	if (!started && (*i)->isLayerScrollable(this)) {
 	    continue;
 	}
+	started = true;
+	if ((*i)->isLayerOpaque()) {
+	    // You can't see anything behind an opaque layer!
+	    nonScrollables.clear();
+	}
 	nonScrollables.push_back(*i);
     }
 
@@ -1006,7 +1034,7 @@
     QRect nonCacheRect(cacheRect);
 
     // If not all layers are scrollable, but some of the back layers
-    // are, we should store only those in the cache
+    // are, we should store only those in the cache.
 
     bool layersChanged = false;
     LayerList scrollables = getScrollableBackLayers(true, layersChanged);
@@ -1015,6 +1043,10 @@
     bool haveSelections = m_manager && !m_manager->getSelections().empty();
     bool selectionDrawn = false;
 
+    // If all the non-scrollable layers are non-opaque, then we draw
+    // the selection rectangle behind them and cache it.  If any are
+    // opaque, however, we can't cache.
+    //
     if (!selectionCacheable) {
 	selectionCacheable = true;
 	for (LayerList::const_iterator i = nonScrollables.begin();
--- a/base/View.h	Wed Mar 15 18:11:23 2006 +0000
+++ b/base/View.h	Thu Mar 16 18:46:00 2006 +0000
@@ -170,7 +170,8 @@
 	OutlinedText
     };
 
-    virtual void drawVisibleText(int x, int y, QString text, TextStyle style);
+    virtual void drawVisibleText(QPainter &p, int x, int y,
+				 QString text, TextStyle style);
 
     virtual bool shouldIlluminateLocalFeatures(const Layer *, QPoint &) const {
 	return false;