# HG changeset patch # User Chris Cannam # Date 1204108365 0 # Node ID 0895517bb2d15e7c4e12368a23dccdbf6d356b17 # Parent 813170c57b13fcc4871845a85e15aa561cc527ac * merge from trunk (1.2 ended up being tracked from trunk, but we may want this branch for fixes later) diff -r 813170c57b13 -r 0895517bb2d1 layer/Colour3DPlotLayer.cpp --- a/layer/Colour3DPlotLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/Colour3DPlotLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -39,7 +39,8 @@ m_colourScale(LinearScale), m_colourMap(0), m_normalizeColumns(false), - m_normalizeVisibleArea(false) + m_normalizeVisibleArea(false), + m_invertVertical(false) { } @@ -87,6 +88,7 @@ list.push_back("Colour Scale"); list.push_back("Normalize Columns"); list.push_back("Normalize Visible Area"); + list.push_back("Invert Vertical Scale"); return list; } @@ -97,6 +99,16 @@ if (name == "Colour Scale") return tr("Scale"); if (name == "Normalize Columns") return tr("Normalize Columns"); if (name == "Normalize Visible Area") return tr("Normalize Visible Area"); + if (name == "Invert Vertical Scale") return tr("Invert Vertical Scale"); + return ""; +} + +QString +Colour3DPlotLayer::getPropertyIconName(const PropertyName &name) const +{ + if (name == "Normalize Columns") return "normalise-columns"; + if (name == "Normalize Visible Area") return "normalise"; + if (name == "Invert Vertical Scale") return "invert-vertical"; return ""; } @@ -105,6 +117,7 @@ { if (name == "Normalize Columns") return ToggleProperty; if (name == "Normalize Visible Area") return ToggleProperty; + if (name == "Invert Vertical Scale") return ToggleProperty; return ValueProperty; } @@ -113,6 +126,7 @@ { if (name == "Normalize Columns" || name == "Normalize Visible Area" || + name == "Invert Vertical Scale" || name == "Colour Scale") return tr("Scale"); return QString(); } @@ -154,6 +168,11 @@ *deflt = 0; val = (m_normalizeVisibleArea ? 1 : 0); + } else if (name == "Invert Vertical Scale") { + + *deflt = 0; + val = (m_invertVertical ? 1 : 0); + } else { val = Layer::getPropertyRangeAndValue(name, min, max, deflt); } @@ -195,6 +214,8 @@ setNormalizeColumns(value ? true : false); } else if (name == "Normalize Visible Area") { setNormalizeVisibleArea(value ? true : false); + } else if (name == "Invert Vertical Scale") { + setInvertVertical(value ? true : false); } } @@ -246,6 +267,21 @@ return m_normalizeVisibleArea; } +void +Colour3DPlotLayer::setInvertVertical(bool n) +{ + if (m_invertVertical == n) return; + m_invertVertical = n; + cacheInvalid(); + emit layerParametersChanged(); +} + +bool +Colour3DPlotLayer::getInvertVertical() const +{ + return m_invertVertical; +} + bool Colour3DPlotLayer::isLayerScrollable(const View *v) const { @@ -278,6 +314,8 @@ float binHeight = float(v->height()) / m_model->getHeight(); int sy = int((v->height() - y) / binHeight); + if (m_invertVertical) sy = m_model->getHeight() - sy - 1; + float value = m_model->getValueAt(sx0, sy); // std::cerr << "bin value (" << sx0 << "," << sy << ") is " << value << std::endl; @@ -358,12 +396,15 @@ for (size_t i = 0; i < m_model->getHeight(); ++i) { - if ((i % step) != 0) continue; + size_t idx = i; + if (m_invertVertical) idx = m_model->getHeight() - idx - 1; + + if ((idx % step) != 0) continue; int y0 = int(v->height() - (i * binHeight) - 1); - QString text = m_model->getBinName(i); - if (text == "") text = QString("[%1]").arg(i + 1); + QString text = m_model->getBinName(idx); + if (text == "") text = QString("[%1]").arg(idx + 1); paint.drawLine(cw, y0, w, y0); @@ -518,7 +559,12 @@ if (pixel < 0) pixel = 0; if (pixel > 255) pixel = 255; - m_cache->setPixel(c - firstBin, y, pixel); + if (m_invertVertical) { + m_cache->setPixel(c - firstBin, m_model->getHeight() - y - 1, + pixel); + } else { + m_cache->setPixel(c - firstBin, y, pixel); + } } } } @@ -574,14 +620,21 @@ fillCache(sx0 < 0 ? 0 : sx0, sx1 < 0 ? 0 : sx1); +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT + std::cerr << "Colour3DPlotLayer::paint: height = "<< m_model->getHeight() << ", modelStart = " << modelStart << ", resolution = " << modelResolution << ", model rate = " << m_model->getSampleRate() << std::endl; +#endif + if (int(m_model->getHeight()) >= v->height() || - int(modelResolution) < v->getZoomLevel() / 2) { + int(modelResolution * m_model->getSampleRate()) < v->getZoomLevel() / 2) { +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT + std::cerr << "calling paintDense" << std::endl; +#endif paintDense(v, paint, rect); return; } #ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT - std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl; + std::cerr << "Colour3DPlotLayer::paint: w " << x1-x0 << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sx1-sx0 << ", sh " << sh << std::endl; std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", resolution " << m_model->getResolution() << std::endl; #endif @@ -596,7 +649,7 @@ int fx = sx * int(modelResolution); - if (fx + int(modelResolution) < int(modelStart) || + if (fx + int(modelResolution) <= int(modelStart) || fx > int(modelEnd)) continue; int rx0 = v->getXForFrame(int((fx + int(modelStart)) * srRatio)); @@ -687,7 +740,7 @@ for (int x = x0; x < x1; ++x) { - long xf = long(v->getFrameForX(x) / srRatio); + long xf = long(v->getFrameForX(x)); if (xf < 0) { for (int y = 0; y < h; ++y) { img.setPixel(x - x0, y, m_cache->color(0)); @@ -695,6 +748,8 @@ continue; } + xf /= srRatio; + float sx0 = (float(xf) - modelStart) / modelResolution; float sx1 = (float(v->getFrameForX(x+1) / srRatio) - modelStart) / modelResolution; diff -r 813170c57b13 -r 0895517bb2d1 layer/Colour3DPlotLayer.h --- a/layer/Colour3DPlotLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/Colour3DPlotLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -75,6 +75,7 @@ virtual PropertyList getProperties() const; virtual PropertyType getPropertyType(const PropertyName &) const; virtual QString getPropertyLabel(const PropertyName &) const; + virtual QString getPropertyIconName(const PropertyName &) const; virtual QString getPropertyGroupName(const PropertyName &) const; virtual int getPropertyRangeAndValue(const PropertyName &, int *min, int *max, int *deflt) const; @@ -97,6 +98,9 @@ void setNormalizeVisibleArea(bool n); bool getNormalizeVisibleArea() const; + void setInvertVertical(bool i); + bool getInvertVertical() const; + virtual const Model *getSliceableModel() const { return m_model; } virtual void toXml(QTextStream &stream, QString indent = "", @@ -116,6 +120,7 @@ int m_colourMap; bool m_normalizeColumns; bool m_normalizeVisibleArea; + bool m_invertVertical; void getColumn(size_t col, DenseThreeDimensionalModel::Column &) const; diff -r 813170c57b13 -r 0895517bb2d1 layer/ImageLayer.cpp --- a/layer/ImageLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/ImageLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -802,7 +803,7 @@ } void -ImageLayer::copy(Selection s, Clipboard &to) +ImageLayer::copy(View *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -812,21 +813,39 @@ for (ImageModel::PointList::iterator i = points.begin(); i != points.end(); ++i) { if (s.contains(i->frame)) { - //!!! inadequate Clipboard::Point point(i->frame, i->label); - point.setReferenceFrame(m_model->alignToReference(i->frame)); + point.setReferenceFrame(alignToReference(v, i->frame)); to.addPoint(point); } } } bool -ImageLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */) +ImageLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */) { if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); + bool realign = false; + + if (clipboardHasDifferentAlignment(v, from)) { + + QMessageBox::StandardButton button = + QMessageBox::question(v, tr("Re-align pasted items?"), + tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + + if (button == QMessageBox::Cancel) { + return false; + } + + if (button == QMessageBox::Yes) { + realign = true; + } + } + ImageModel::EditCommand *command = new ImageModel::EditCommand(m_model, tr("Paste")); @@ -834,10 +853,23 @@ i != points.end(); ++i) { if (!i->haveFrame()) continue; + size_t frame = 0; - if (frameOffset > 0 || -frameOffset < i->getFrame()) { - frame = i->getFrame() + frameOffset; + + if (!realign) { + + frame = i->getFrame(); + + } else { + + if (i->haveReferenceFrame()) { + frame = i->getReferenceFrame(); + frame = alignFromReference(v, frame); + } else { + frame = i->getFrame(); + } } + ImageModel::Point newPoint(frame); //!!! inadequate @@ -880,7 +912,7 @@ return; } - FileSource *rf = new FileSource(img, true); + FileSource *rf = new FileSource(img, FileSource::ProgressDialog); if (rf->isOK()) { std::cerr << "ok, adding it (local filename = " << rf->getLocalFilename().toStdString() << ")" << std::endl; m_remoteFiles[img] = rf; diff -r 813170c57b13 -r 0895517bb2d1 layer/ImageLayer.h --- a/layer/ImageLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/ImageLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -58,8 +58,8 @@ virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(Selection s, Clipboard &to); - virtual bool paste(const Clipboard &from, int frameOffset, + virtual void copy(View *v, Selection s, Clipboard &to); + virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive); virtual bool editOpen(View *, QMouseEvent *); // on double-click diff -r 813170c57b13 -r 0895517bb2d1 layer/Layer.cpp --- a/layer/Layer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/Layer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -68,10 +68,16 @@ (LayerFactory::getInstance()->getLayerType(this)); } +void +Layer::setPresentationName(QString name) +{ + m_presentationName = name; +} + QString Layer::getLayerPresentationName() const { -// QString layerName = objectName(); + if (m_presentationName != "") return m_presentationName; LayerFactory *factory = LayerFactory::getInstance(); QString layerName = factory->getLayerPresentationName @@ -159,6 +165,106 @@ return true; } +size_t +Layer::alignToReference(View *v, size_t frame) const +{ + const Model *m = getModel(); + std::cerr << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << std::endl; + if (m && m->getAlignmentReference()) { + return m->alignToReference(frame); + } else { + return v->alignToReference(frame); + } +} + +size_t +Layer::alignFromReference(View *v, size_t frame) const +{ + const Model *m = getModel(); + std::cerr << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << std::endl; + if (m && m->getAlignmentReference()) { + return m->alignFromReference(frame); + } else { + return v->alignFromReference(frame); + } +} + +bool +Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const +{ + // Notes on pasting to an aligned layer: + // + // Each point may have a reference frame that may differ from the + // point's given frame (in its source model). If it has no + // reference frame, we have to assume the source model was not + // aligned or was the reference model: when cutting or copying + // points from a layer, we must always set their reference frame + // correctly if we are aligned. + // + // When pasting: + // - if point's reference and aligned frames differ: + // - if this layer is aligned: + // - if point's aligned frame matches this layer's aligned version + // of point's reference frame: + // - we can paste at reference frame or our frame + // - else + // - we can paste at reference frame, result of aligning reference + // frame in our model, or literal source frame + // - else + // - we can paste at reference (our) frame, or literal source frame + // - else + // - if this layer is aligned: + // - we can paste at reference (point's only available) frame, + // or result of aligning reference frame in our model + // - else + // - we can only paste at reference frame + // + // Which of these alternatives are useful? + // + // Example: we paste between two tracks that are aligned to the + // same reference, and the points are at 10s and 20s in the source + // track, corresponding to 5s and 10s in the reference but 20s and + // 30s in the target track. + // + // The obvious default is to paste at 20s and 30s; if we aren't + // doing that, would it be better to paste at 5s and 10s or at 10s + // and 20s? We probably don't ever want to do the former, do we? + // We either want to be literal all the way through, or aligned + // all the way through. + + for (Clipboard::PointList::const_iterator i = clip.getPoints().begin(); + i != clip.getPoints().end(); ++i) { + + // In principle, we want to know whether the aligned version + // of the reference frame in our layer is the same as the + // source frame contained in the clipboard point. However, + // because of rounding during alignment, that won't + // necessarily be the case even if the clipboard point came + // from our layer! What we need to check is whether, if we + // aligned the clipboard point's frame back to the reference + // using this layer's alignment, we would obtain the same + // reference frame as that for the clipboard point. + + // What if the clipboard point has no reference frame? Then + // we have to treat it as having its own frame as the + // reference (i.e. having been copied from the reference + // model). + + long sourceFrame = i->getFrame(); + long referenceFrame = sourceFrame; + if (i->haveReferenceFrame()) { + referenceFrame = i->getReferenceFrame(); + } + long myMappedFrame = alignToReference(v, sourceFrame); + +// std::cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << std::endl; + + if (myMappedFrame != referenceFrame) return true; + } + + return false; +} + bool Layer::MeasureRect::operator<(const MeasureRect &mr) const { @@ -488,6 +594,11 @@ { stream << indent; + if (m_presentationName != "") { + extraAttributes = QString("%1 presentationName=\"%2\"") + .arg(extraAttributes).arg(encodeEntities(m_presentationName)); + } + stream << QString("getLayerTypeName (LayerFactory::getInstance()->getLayerType(this)))) @@ -517,6 +628,11 @@ { stream << indent; + if (m_presentationName != "") { + extraAttributes = QString("%1 presentationName=\"%2\"") + .arg(extraAttributes).arg(encodeEntities(m_presentationName)); + } + stream << QString("\n") .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName (LayerFactory::getInstance()->getLayerType(this)))) diff -r 813170c57b13 -r 0895517bb2d1 layer/Layer.h --- a/layer/Layer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/Layer.h Wed Feb 27 10:32:45 2008 +0000 @@ -92,9 +92,12 @@ virtual QString getPropertyContainerIconName() const; virtual QString getPropertyContainerName() const { - return objectName(); + if (m_presentationName != "") return m_presentationName; + else return objectName(); } + virtual void setPresentationName(QString name); + virtual QString getLayerPresentationName() const; virtual QPixmap getLayerPresentationPixmap(QSize) const { return QPixmap(); } @@ -193,7 +196,7 @@ virtual void resizeSelection(Selection, Selection /* newSize */) { } virtual void deleteSelection(Selection) { } - virtual void copy(Selection, Clipboard & /* to */) { } + virtual void copy(View *, Selection, Clipboard & /* to */) { } /** * Paste from the given clipboard onto the layer at the given @@ -202,7 +205,8 @@ * return false if the user cancelled the paste operation. This * function should return true if a paste actually occurred. */ - virtual bool paste(const Clipboard & /* from */, + virtual bool paste(View *, + const Clipboard & /* from */, int /* frameOffset */, bool /* interactive */) { return false; } @@ -465,6 +469,10 @@ protected: void connectSignals(const Model *); + virtual size_t alignToReference(View *v, size_t frame) const; + virtual size_t alignFromReference(View *v, size_t frame) const; + bool clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const; + struct MeasureRect { mutable QRect pixrect; @@ -540,6 +548,8 @@ void paintMeasurementRect(View *v, QPainter &paint, const MeasureRect &r, bool focus) const; + QString m_presentationName; + private: mutable QMutex m_dormancyMutex; mutable std::map m_dormancy; diff -r 813170c57b13 -r 0895517bb2d1 layer/LayerFactory.cpp --- a/layer/LayerFactory.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/LayerFactory.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -28,6 +28,8 @@ #include "SliceLayer.h" #include "SliceableLayer.h" +#include "base/Clipboard.h" + #include "data/model/RangeSummarisableTimeValueModel.h" #include "data/model/DenseTimeValueModel.h" #include "data/model/SparseOneDimensionalModel.h" @@ -350,6 +352,10 @@ dynamic_cast(layer)->setChannel(channel); return; } + if (dynamic_cast(layer)) { + dynamic_cast(layer)->setChannel(channel); + return; + } } Layer * @@ -478,3 +484,24 @@ settings.endGroup(); } +LayerFactory::LayerType +LayerFactory::getLayerTypeForClipboardContents(const Clipboard &clip) +{ + const Clipboard::PointList &contents = clip.getPoints(); + + bool haveFrame = false; + bool haveValue = false; + bool haveDuration = false; + + for (Clipboard::PointList::const_iterator i = contents.begin(); + i != contents.end(); ++i) { + if (i->haveFrame()) haveFrame = true; + if (i->haveValue()) haveValue = true; + if (i->haveDuration()) haveDuration = true; + } + + if (haveFrame && haveValue && haveDuration) return Notes; + if (haveFrame && haveValue) return TimeValues; + return TimeInstants; +} + diff -r 813170c57b13 -r 0895517bb2d1 layer/LayerFactory.h --- a/layer/LayerFactory.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/LayerFactory.h Wed Feb 27 10:32:45 2008 +0000 @@ -21,6 +21,7 @@ class Layer; class Model; +class Clipboard; class LayerFactory { @@ -76,6 +77,8 @@ QString getLayerTypeName(LayerType); LayerType getLayerTypeForName(QString); + LayerType getLayerTypeForClipboardContents(const Clipboard &); + protected: template bool trySetModel(Layer *layerBase, Model *modelBase) { diff -r 813170c57b13 -r 0895517bb2d1 layer/NoteLayer.cpp --- a/layer/NoteLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/NoteLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -916,7 +917,7 @@ } void -NoteLayer::copy(Selection s, Clipboard &to) +NoteLayer::copy(View *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -927,19 +928,38 @@ i != points.end(); ++i) { if (s.contains(i->frame)) { Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label); - point.setReferenceFrame(m_model->alignToReference(i->frame)); + point.setReferenceFrame(alignToReference(v, i->frame)); to.addPoint(point); } } } bool -NoteLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */) +NoteLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */) { if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); + bool realign = false; + + if (clipboardHasDifferentAlignment(v, from)) { + + QMessageBox::StandardButton button = + QMessageBox::question(v, tr("Re-align pasted items?"), + tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + + if (button == QMessageBox::Cancel) { + return false; + } + + if (button == QMessageBox::Yes) { + realign = true; + } + } + NoteModel::EditCommand *command = new NoteModel::EditCommand(m_model, tr("Paste")); @@ -948,9 +968,21 @@ if (!i->haveFrame()) continue; size_t frame = 0; - if (frameOffset > 0 || -frameOffset < i->getFrame()) { - frame = i->getFrame() + frameOffset; + + if (!realign) { + + frame = i->getFrame(); + + } else { + + if (i->haveReferenceFrame()) { + frame = i->getReferenceFrame(); + frame = alignFromReference(v, frame); + } else { + frame = i->getFrame(); + } } + NoteModel::Point newPoint(frame); if (i->haveLabel()) newPoint.label = i->getLabel(); diff -r 813170c57b13 -r 0895517bb2d1 layer/NoteLayer.h --- a/layer/NoteLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/NoteLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -58,8 +58,8 @@ virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(Selection s, Clipboard &to); - virtual bool paste(const Clipboard &from, int frameOffset, + virtual void copy(View *v, Selection s, Clipboard &to); + virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } diff -r 813170c57b13 -r 0895517bb2d1 layer/SingleColourLayer.cpp --- a/layer/SingleColourLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/SingleColourLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -22,12 +22,15 @@ #include #include +//#define DEBUG_COLOUR_SELECTION 1 + SingleColourLayer::ColourRefCount SingleColourLayer::m_colourRefCount; SingleColourLayer::SingleColourLayer() : m_colour(0), - m_colourExplicitlySet(false) + m_colourExplicitlySet(false), + m_defaultColourSet(false) { setDefaultColourFor(0); } @@ -125,7 +128,13 @@ void SingleColourLayer::setDefaultColourFor(View *v) { - if (m_colourExplicitlySet) return; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << "SingleColourLayer::setDefaultColourFor: m_colourExplicitlySet = " << m_colourExplicitlySet << ", m_defaultColourSet " << m_defaultColourSet << std::endl; +#endif + + if (m_colourExplicitlySet || m_defaultColourSet) return; + + if (v) m_defaultColourSet = true; // v==0 case doesn't really count bool dark = false; if (v) { @@ -148,9 +157,13 @@ // means we're being called from the constructor, and this is // a virtual function hint = getDefaultColourHint(dark, impose); -// std::cerr << "hint = " << hint << ", impose = " << impose << std::endl; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << "hint = " << hint << ", impose = " << impose << std::endl; +#endif } else { -// std::cerr << "(from ctor)" << std::endl; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << "(from ctor)" << std::endl; +#endif } if (hint >= 0 && impose) { @@ -171,15 +184,21 @@ count = m_colourRefCount[index]; } -// std::cerr << "index = " << index << ", count = " << count; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << "index = " << index << ", count = " << count; +#endif if (bestColour < 0 || count < bestCount) { bestColour = index; bestCount = count; -// std::cerr << " *"; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << " *"; +#endif } -// std::cerr << std::endl; +#ifdef DEBUG_COLOUR_SELECTION + std::cerr << std::endl; +#endif } if (bestColour < 0) m_colour = 0; @@ -289,7 +308,9 @@ if (m_colour != colour) { +#ifdef DEBUG_COLOUR_SELECTION std::cerr << "SingleColourLayer::setProperties: changing colour from " << m_colour << " to " << colour << std::endl; +#endif if (m_colourRefCount.find(m_colour) != m_colourRefCount.end() && m_colourRefCount[m_colour] > 0) { diff -r 813170c57b13 -r 0895517bb2d1 layer/SingleColourLayer.h --- a/layer/SingleColourLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/SingleColourLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -70,6 +70,7 @@ int m_colour; bool m_colourExplicitlySet; + bool m_defaultColourSet; }; #endif diff -r 813170c57b13 -r 0895517bb2d1 layer/SpectrumLayer.cpp --- a/layer/SpectrumLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/SpectrumLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -47,35 +47,64 @@ SpectrumLayer::~SpectrumLayer() { - //!!! delete parent's model -// for (size_t i = 0; i < m_fft.size(); ++i) delete m_fft[i]; + Model *m = const_cast + (static_cast(m_sliceableModel)); + m->aboutToDelete(); + m_sliceableModel = 0; + delete m; } void SpectrumLayer::setModel(DenseTimeValueModel *model) { + std::cerr << "SpectrumLayer::setModel(" << model << ") from " << m_originModel << std::endl; + if (m_originModel == model) return; + m_originModel = model; if (m_sliceableModel) { - const Model *oldModel = m_sliceableModel; + Model *m = const_cast + (static_cast(m_sliceableModel)); + m->aboutToDelete(); setSliceableModel(0); - // surprised I'm allowed to delete a const pointer -- may be a - // source of future compiler rejection? - delete oldModel; + delete m; } -//!!! setupFFT(); + + m_newFFTNeeded = true; + + emit layerParametersChanged(); +} + +void +SpectrumLayer::setChannel(int channel) +{ + std::cerr << "SpectrumLayer::setChannel(" << channel << ") from " << m_channel << std::endl; + + m_channelSet = true; + + if (m_channel == channel) return; + + m_channel = channel; + + m_newFFTNeeded = true; + + emit layerParametersChanged(); } void SpectrumLayer::setupFFT() { - FFTModel *oldFFT = dynamic_cast - (const_cast(m_sliceableModel)); - - if (oldFFT) { + if (m_sliceableModel) { + Model *m = const_cast + (static_cast(m_sliceableModel)); + m->aboutToDelete(); setSliceableModel(0); - delete oldFFT; + delete m; + } + + if (!m_originModel) { + return; } FFTModel *newFFT = new FFTModel(m_originModel, @@ -97,24 +126,8 @@ } newFFT->resume(); -} -void -SpectrumLayer::setChannel(int channel) -{ - m_channelSet = true; - - FFTModel *fft = dynamic_cast - (const_cast(m_sliceableModel)); - - if (m_channel == channel) { - if (fft) fft->resume(); - return; - } - - m_channel = channel; - - emit layerParametersChanged(); + m_newFFTNeeded = false; } Layer::PropertyList @@ -640,11 +653,14 @@ SpectrumLayer::paint(View *v, QPainter &paint, QRect rect) const { if (!m_originModel || !m_originModel->isOK() || - !m_originModel->isReady()) return; + !m_originModel->isReady()) { + std::cerr << "SpectrumLayer::paint: no origin model, or origin model not OK or not ready" << std::endl; + return; + } if (m_newFFTNeeded) { + std::cerr << "SpectrumLayer::paint: new FFT needed, calling setupFFT" << std::endl; const_cast(this)->setupFFT(); //ugh - m_newFFTNeeded = false; } FFTModel *fft = dynamic_cast @@ -660,6 +676,8 @@ pkh = 10; //!!! } + paint.save(); + if (fft && m_showPeaks) { // draw peak lines @@ -799,6 +817,8 @@ px = x; } // } + + paint.restore(); } void diff -r 813170c57b13 -r 0895517bb2d1 layer/SpectrumLayer.h --- a/layer/SpectrumLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/SpectrumLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -24,6 +24,7 @@ #include "data/model/DenseTimeValueModel.h" #include +#include class FFTModel; @@ -113,6 +114,8 @@ bool m_showPeaks; mutable bool m_newFFTNeeded; + mutable QMutex m_fftMutex; + void setupFFT(); virtual void getBiasCurve(BiasCurve &) const; diff -r 813170c57b13 -r 0895517bb2d1 layer/TextLayer.cpp --- a/layer/TextLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TextLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -671,7 +672,7 @@ } void -TextLayer::copy(Selection s, Clipboard &to) +TextLayer::copy(View *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -682,19 +683,38 @@ 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)); + point.setReferenceFrame(alignToReference(v, i->frame)); to.addPoint(point); } } } bool -TextLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */) +TextLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */) { if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); + bool realign = false; + + if (clipboardHasDifferentAlignment(v, from)) { + + QMessageBox::StandardButton button = + QMessageBox::question(v, tr("Re-align pasted items?"), + tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + + if (button == QMessageBox::Cancel) { + return false; + } + + if (button == QMessageBox::Yes) { + realign = true; + } + } + TextModel::EditCommand *command = new TextModel::EditCommand(m_model, tr("Paste")); @@ -713,9 +733,21 @@ if (!i->haveFrame()) continue; size_t frame = 0; - if (frameOffset > 0 || -frameOffset < i->getFrame()) { - frame = i->getFrame() + frameOffset; + + if (!realign) { + + frame = i->getFrame(); + + } else { + + if (i->haveReferenceFrame()) { + frame = i->getReferenceFrame(); + frame = alignFromReference(v, frame); + } else { + frame = i->getFrame(); + } } + TextModel::Point newPoint(frame); if (i->haveValue()) { diff -r 813170c57b13 -r 0895517bb2d1 layer/TextLayer.h --- a/layer/TextLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TextLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -56,8 +56,8 @@ virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(Selection s, Clipboard &to); - virtual bool paste(const Clipboard &from, int frameOffset, + virtual void copy(View *v, Selection s, Clipboard &to); + virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive); virtual bool editOpen(View *, QMouseEvent *); // on double-click diff -r 813170c57b13 -r 0895517bb2d1 layer/TimeInstantLayer.cpp --- a/layer/TimeInstantLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TimeInstantLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -25,10 +25,12 @@ #include "data/model/SparseOneDimensionalModel.h" #include "widgets/ItemEditDialog.h" +#include "widgets/ListInputDialog.h" #include #include #include +#include #include #include @@ -711,7 +713,7 @@ } void -TimeInstantLayer::copy(Selection s, Clipboard &to) +TimeInstantLayer::copy(View *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -722,43 +724,68 @@ i != points.end(); ++i) { if (s.contains(i->frame)) { Clipboard::Point point(i->frame, i->label); - point.setReferenceFrame(m_model->alignToReference(i->frame)); + point.setReferenceFrame(alignToReference(v, i->frame)); to.addPoint(point); } } } bool -TimeInstantLayer::paste(const Clipboard &from, int frameOffset, bool) +TimeInstantLayer::paste(View *v, const Clipboard &from, int frameOffset, bool) { if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); + bool realign = false; + + if (clipboardHasDifferentAlignment(v, from)) { + + QMessageBox::StandardButton button = + QMessageBox::question(v, tr("Re-align pasted instants?"), + tr("The instants you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + + if (button == QMessageBox::Cancel) { + return false; + } + + if (button == QMessageBox::Yes) { + realign = true; + } + } + 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) { if (!i->haveFrame()) continue; + size_t frame = 0; - if (frameOffset > 0 || -frameOffset < i->getFrame()) { - frame = i->getFrame() + frameOffset; + + if (!realign) { + + frame = i->getFrame(); + + } else { + + if (i->haveReferenceFrame()) { + frame = i->getReferenceFrame(); + frame = alignFromReference(v, frame); + } else { + frame = i->getFrame(); + } } + + if (frameOffset > 0) frame += frameOffset; + else if (frameOffset < 0) { + if (frame > -frameOffset) frame += frameOffset; + else frame = 0; + } + SparseOneDimensionalModel::Point newPoint(frame); if (i->haveLabel()) { newPoint.label = i->getLabel(); diff -r 813170c57b13 -r 0895517bb2d1 layer/TimeInstantLayer.h --- a/layer/TimeInstantLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TimeInstantLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -59,8 +59,8 @@ virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(Selection s, Clipboard &to); - virtual bool paste(const Clipboard &from, int frameOffset, + virtual void copy(View *v, Selection s, Clipboard &to); + virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } @@ -105,6 +105,8 @@ virtual int getDefaultColourHint(bool dark, bool &impose); + bool clipboardAlignmentDiffers(View *v, const Clipboard &) const; + SparseOneDimensionalModel *m_model; bool m_editing; SparseOneDimensionalModel::Point m_editingPoint; diff -r 813170c57b13 -r 0895517bb2d1 layer/TimeRulerLayer.cpp --- a/layer/TimeRulerLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TimeRulerLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -27,6 +27,8 @@ #include #include +//#define DEBUG_TIME_RULER_LAYER 1 + using std::cerr; using std::endl; @@ -192,104 +194,150 @@ void TimeRulerLayer::paint(View *v, QPainter &paint, QRect rect) const { -// std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() -// << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl; +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "TimeRulerLayer::paint (" << rect.x() << "," << rect.y() + << ") [" << rect.width() << "x" << rect.height() << "]" << std::endl; +#endif if (!m_model || !m_model->isOK()) return; int sampleRate = m_model->getSampleRate(); if (!sampleRate) return; - long startFrame = v->getStartFrame(); - long endFrame = v->getEndFrame(); + long startFrame = v->getFrameForX(rect.x() - 50); - int zoomLevel = v->getZoomLevel(); - - long rectStart = startFrame + (rect.x() - 100) * zoomLevel; - long rectEnd = startFrame + (rect.x() + rect.width() + 100) * zoomLevel; - -// std::cerr << "TimeRulerLayer::paint: calling paint.save()" << std::endl; - paint.save(); -//!!! paint.setClipRect(v->rect()); - - int minPixelSpacing = 50; +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "start frame = " << startFrame << std::endl; +#endif bool quarter = false; int incms = getMajorTickSpacing(v, quarter); - RealTime rt = RealTime::frame2RealTime(rectStart, sampleRate); - long ms = rt.sec * 1000 + rt.msec(); + int ms = lrint(1000.0 * (double(startFrame) / double(sampleRate))); ms = (ms / incms) * incms - incms; - RealTime incRt = RealTime::fromMilliseconds(incms); - long incFrame = RealTime::realTime2Frame(incRt, sampleRate); - int incX = incFrame / zoomLevel; +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "start ms = " << ms << " at step " << incms << std::endl; +#endif + + // Calculate the number of ticks per increment -- approximate + // values for x and frame counts here will do, no rounding issue. + // We always use the exact incms in our calculations for where to + // draw the actual ticks or lines. + + int minPixelSpacing = 50; + long incFrame = (incms * sampleRate) / 1000; + int incX = incFrame / v->getZoomLevel(); int ticks = 10; if (incX < minPixelSpacing * 2) { ticks = quarter ? 4 : 5; } - QRect oldClipRect = rect; - QRect newClipRect(oldClipRect.x() - 25, oldClipRect.y(), - oldClipRect.width() + 50, oldClipRect.height()); - paint.setClipRect(newClipRect); - paint.setClipRect(rect); + QColor greyColour = getPartialShades(v)[1]; - QColor greyColour = getPartialShades(v)[1]; + paint.save(); while (1) { - rt = RealTime::fromMilliseconds(ms); + // frame is used to determine where to draw the lines, so it + // needs to correspond to an exact pixel (so that we don't get + // a different pixel when scrolling a small amount and + // re-drawing with a different start frame). + + double dms = ms; + long frame = lrint((dms * sampleRate) / 1000.0); + frame /= v->getZoomLevel(); + frame *= v->getZoomLevel(); // so frame corresponds to an exact pixel + ms += incms; - long frame = RealTime::realTime2Frame(rt, sampleRate); - if (frame >= rectEnd) break; + int x = v->getXForFrame(frame); - int x = (frame - startFrame) / zoomLevel; - if (x < rect.x() || x >= rect.x() + rect.width()) continue; +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "Considering frame = " << frame << ", x = " << x << std::endl; +#endif - paint.setPen(greyColour); - paint.drawLine(x, 0, x, v->height()); + if (x >= rect.x() + rect.width() + 50) { +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "X well out of range, ending here" << std::endl; +#endif + break; + } - paint.setPen(getBaseQColor()); - paint.drawLine(x, 0, x, 5); - paint.drawLine(x, v->height() - 6, x, v->height() - 1); + if (x >= rect.x() - 50) { - QString text(QString::fromStdString(rt.toText())); +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "X in range, drawing line here" << std::endl; +#endif - int y; - QFontMetrics metrics = paint.fontMetrics(); - switch (m_labelHeight) { - default: - case LabelTop: - y = 6 + metrics.ascent(); - break; - case LabelMiddle: - y = v->height() / 2 - metrics.height() / 2 + metrics.ascent(); - break; - case LabelBottom: - y = v->height() - metrics.height() + metrics.ascent() - 6; - } + RealTime rt = RealTime::fromMilliseconds(ms); - int tw = metrics.width(text); + QString text(QString::fromStdString(rt.toText())); + QFontMetrics metrics = paint.fontMetrics(); + int tw = metrics.width(text); - if (v->getViewManager() && v->getViewManager()->getOverlayMode() != - ViewManager::NoOverlays) { + if (tw < 50 && + (x < rect.x() - tw/2 || + x >= rect.x() + rect.width() + tw/2)) { +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "hm, maybe X isn't in range after all (x = " << x << ", tw = " << tw << ", rect.x() = " << rect.x() << ", rect.width() = " << rect.width() << ")" << std::endl; +#endif + } - if (v->getLayer(0) == this) { - // backmost layer, don't worry about outlining the text - paint.drawText(x+2 - tw/2, y, text); - } else { - v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText); + paint.setPen(greyColour); + paint.drawLine(x, 0, x, v->height()); + + paint.setPen(getBaseQColor()); + paint.drawLine(x, 0, x, 5); + paint.drawLine(x, v->height() - 6, x, v->height() - 1); + + int y; + switch (m_labelHeight) { + default: + case LabelTop: + y = 6 + metrics.ascent(); + break; + case LabelMiddle: + y = v->height() / 2 - metrics.height() / 2 + metrics.ascent(); + break; + case LabelBottom: + y = v->height() - metrics.height() + metrics.ascent() - 6; + } + + if (v->getViewManager() && v->getViewManager()->getOverlayMode() != + ViewManager::NoOverlays) { + + if (v->getLayer(0) == this) { + // backmost layer, don't worry about outlining the text + paint.drawText(x+2 - tw/2, y, text); + } else { + v->drawVisibleText(paint, x+2 - tw/2, y, text, View::OutlinedText); + } } } paint.setPen(greyColour); for (int i = 1; i < ticks; ++i) { - rt = rt + (incRt / ticks); - frame = RealTime::realTime2Frame(rt, sampleRate); - x = (frame - startFrame) / zoomLevel; + + dms = ms - incms + (i * double(incms)) / ticks; + frame = lrint((dms * sampleRate) / 1000.0); + frame /= v->getZoomLevel(); + frame *= v->getZoomLevel(); // exact pixel as above + + x = v->getXForFrame(frame); + + if (x < rect.x() || x >= rect.x() + rect.width()) { +#ifdef DEBUG_TIME_RULER_LAYER +// std::cerr << "tick " << i << ": X out of range, going on to next tick" << std::endl; +#endif + continue; + } + +#ifdef DEBUG_TIME_RULER_LAYER + std::cerr << "tick " << i << " in range, drawing at " << x << std::endl; +#endif + int sz = 5; if (ticks == 10) { if ((i % 2) == 1) { diff -r 813170c57b13 -r 0895517bb2d1 layer/TimeValueLayer.cpp --- a/layer/TimeValueLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TimeValueLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -23,6 +23,7 @@ #include "view/View.h" #include "data/model/SparseTimeValueModel.h" +#include "data/model/Labeller.h" #include "widgets/ItemEditDialog.h" #include "widgets/ListInputDialog.h" @@ -35,6 +36,8 @@ #include #include #include +#include +#include #include #include @@ -538,6 +541,8 @@ int sampleRate = m_model->getSampleRate(); if (!sampleRate) return; + paint.setRenderHint(QPainter::Antialiasing, false); + // Profiler profiler("TimeValueLayer::paint", true); int x0 = rect.left(), x1 = rect.right(); @@ -599,6 +604,9 @@ if (m_plotStyle != PlotSegmentation) { textY = y - paint.fontMetrics().height() + paint.fontMetrics().ascent(); + if (textY < paint.fontMetrics().ascent() + 1) { + textY = paint.fontMetrics().ascent() + 1; + } } bool haveNext = false; @@ -1181,7 +1189,7 @@ } void -TimeValueLayer::copy(Selection s, Clipboard &to) +TimeValueLayer::copy(View *v, Selection s, Clipboard &to) { if (!m_model) return; @@ -1192,46 +1200,55 @@ 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)); + point.setReferenceFrame(alignToReference(v, i->frame)); to.addPoint(point); } } } bool -TimeValueLayer::paste(const Clipboard &from, int frameOffset, +TimeValueLayer::paste(View *v, const Clipboard &from, int frameOffset, bool interactive) { if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); + bool realign = false; + + if (clipboardHasDifferentAlignment(v, from)) { + + QMessageBox::StandardButton button = + QMessageBox::question(v, tr("Re-align pasted items?"), + tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"), + QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, + QMessageBox::Yes); + + if (button == QMessageBox::Cancel) { + return false; + } + + if (button == QMessageBox::Yes) { + realign = true; + } + } + SparseTimeValueModel::EditCommand *command = new SparseTimeValueModel::EditCommand(m_model, tr("Paste")); - //!!! Replace all this with a use of Labeller - enum ValueAvailability { UnknownAvailability, NoValues, SomeValues, AllValues }; - enum ValueGeneration { - GenerateNone, - GenerateFromCounter, - GenerateFromFrameNumber, - GenerateFromRealTime, - GenerateFromRealTimeDifference, - GenerateFromTempo, - GenerateFromExistingNeighbour, - GenerateFromLabels - }; - ValueGeneration generation = GenerateNone; + Labeller::ValueType generation = Labeller::ValueNone; bool haveUsableLabels = false; bool haveExistingItems = !(m_model->isEmpty()); + Labeller labeller; + labeller.setSampleRate(m_model->getSampleRate()); if (interactive) { @@ -1278,38 +1295,18 @@ text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?"); } + Labeller::TypeNameMap names = labeller.getTypeNames(); + QStringList options; - std::vector genopts; + std::vector genopts; - options << tr("Zero for all items"); - genopts.push_back(int(GenerateNone)); - - options << tr("Whole numbers counting from 1"); - genopts.push_back(int(GenerateFromCounter)); - - options << tr("Item's audio sample frame number"); - genopts.push_back(int(GenerateFromFrameNumber)); - - options << tr("Item's time in seconds"); - genopts.push_back(int(GenerateFromRealTime)); - - options << tr("Duration from the item to the following item"); - genopts.push_back(int(GenerateFromRealTimeDifference)); - - options << tr("Tempo in bpm derived from the duration"); - genopts.push_back(int(GenerateFromTempo)); - - if (haveExistingItems) { - options << tr("Value of the nearest existing item"); - genopts.push_back(int(GenerateFromExistingNeighbour)); + for (Labeller::TypeNameMap::const_iterator i = names.begin(); + i != names.end(); ++i) { + if (i->first == Labeller::ValueNone) options << tr("Zero for all items"); + else options << i->second; + genopts.push_back(i->first); } - if (haveUsableLabels) { - options << tr("Value extracted from the item's label (where possible)"); - genopts.push_back(int(GenerateFromLabels)); - } - - static int prevSelection = 0; bool ok = false; @@ -1319,32 +1316,54 @@ if (!ok) return false; int selection = 0; - generation = GenerateNone; + generation = Labeller::ValueNone; for (QStringList::const_iterator i = options.begin(); i != options.end(); ++i) { if (selected == *i) { - generation = ValueGeneration(genopts[selection]); + generation = genopts[selection]; break; } ++selection; } + + labeller.setType(generation); + + if (generation == Labeller::ValueFromCyclicalCounter || + generation == Labeller::ValueFromTwoLevelCounter) { + int cycleSize = QInputDialog::getInteger + (0, tr("Select cycle size"), + tr("Cycle size:"), 4, 2, 16, 1); + labeller.setCounterCycleSize(cycleSize); + } prevSelection = selection; } } - int counter = 1; - float prevBpm = 120.f; + SparseTimeValueModel::Point prevPoint(0); for (Clipboard::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { if (!i->haveFrame()) continue; + size_t frame = 0; - if (frameOffset > 0 || -frameOffset < i->getFrame()) { - frame = i->getFrame() + frameOffset; + + if (!realign) { + + frame = i->getFrame(); + + } else { + + if (i->haveReferenceFrame()) { + frame = i->getReferenceFrame(); + frame = alignFromReference(v, frame); + } else { + frame = i->getFrame(); + } } + SparseTimeValueModel::Point newPoint(frame); if (i->haveLabel()) { @@ -1353,81 +1372,33 @@ newPoint.label = QString("%1").arg(i->getValue()); } + bool usePrev = false; + SparseTimeValueModel::Point formerPrevPoint = prevPoint; + if (i->haveValue()) { newPoint.value = i->getValue(); } else { - - switch (generation) { - - case GenerateNone: - newPoint.value = 0; - break; - - case GenerateFromCounter: - newPoint.value = counter; - break; - - case GenerateFromFrameNumber: - newPoint.value = frame; - break; - - case GenerateFromRealTime: - newPoint.value = float(frame) / float(m_model->getSampleRate()); - break; - - case GenerateFromRealTimeDifference: - case GenerateFromTempo: - { - size_t nextFrame = frame; - Clipboard::PointList::const_iterator j = i; - for (; j != points.end(); ++j) { - if (!j->haveFrame()) continue; - if (j != i) break; - } - if (j != points.end()) { - nextFrame = j->getFrame(); - } - if (generation == GenerateFromRealTimeDifference) { - newPoint.value = float(nextFrame - frame) / - float(m_model->getSampleRate()); - } else { - float bpm = prevBpm; - if (nextFrame > frame) { - bpm = (60.f * m_model->getSampleRate()) / - (nextFrame - frame); - } - newPoint.value = bpm; - prevBpm = bpm; - } - break; - } - - case GenerateFromExistingNeighbour: - { - SparseTimeValueModel::PointList points = - m_model->getPoints(frame); - if (points.empty()) points = m_model->getPreviousPoints(frame); - if (points.empty()) points = m_model->getNextPoints(frame); - if (points.empty()) { - newPoint.value = 0.f; - } else { - newPoint.value = points.begin()->value; - } - } - - case GenerateFromLabels: - if (i->haveLabel()) { - // more forgiving than QString::toFloat() - newPoint.value = atof(i->getLabel().toLocal8Bit()); - } else { - newPoint.value = 0.f; - } +// std::cerr << "Setting value on point at " << newPoint.frame << " from labeller"; +// if (i == points.begin()) { +// std::cerr << ", no prev point" << std::endl; +// } else { +// std::cerr << ", prev point is at " << prevPoint.frame << std::endl; +// } + labeller.setValue + (newPoint, (i == points.begin()) ? 0 : &prevPoint); +// std::cerr << "New point value = " << newPoint.value << std::endl; + if (labeller.actingOnPrevPoint() && i != points.begin()) { + usePrev = true; } } - + + if (usePrev) { + command->deletePoint(formerPrevPoint); + command->addPoint(prevPoint); + } + + prevPoint = newPoint; command->addPoint(newPoint); - - ++counter; } command->finish(); diff -r 813170c57b13 -r 0895517bb2d1 layer/TimeValueLayer.h --- a/layer/TimeValueLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/TimeValueLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -61,8 +61,8 @@ virtual void resizeSelection(Selection s, Selection newSize); virtual void deleteSelection(Selection s); - virtual void copy(Selection s, Clipboard &to); - virtual bool paste(const Clipboard &from, int frameOffset, + virtual void copy(View *v, Selection s, Clipboard &to); + virtual bool paste(View *v, const Clipboard &from, int frameOffset, bool interactive); virtual const Model *getModel() const { return m_model; } diff -r 813170c57b13 -r 0895517bb2d1 layer/WaveformLayer.cpp --- a/layer/WaveformLayer.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/WaveformLayer.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -396,6 +396,73 @@ static float meterdbs[] = { -40, -30, -20, -15, -10, -5, -3, -2, -1, -0.5, 0 }; +bool +WaveformLayer::getSourceFramesForX(View *v, int x, size_t modelZoomLevel, + size_t &f0, size_t &f1) const +{ + long viewFrame = v->getFrameForX(x); + if (viewFrame < 0) { + f0 = 0; + f1 = 0; + return false; + } + + f0 = viewFrame; + + f0 = f0 / modelZoomLevel; + f0 = f0 * modelZoomLevel; + + viewFrame = v->getFrameForX(x + 1); + + f1 = viewFrame; + f1 = f1 / modelZoomLevel; + f1 = f1 * modelZoomLevel; + + return (f0 < m_model->getEndFrame()); +} + +float +WaveformLayer::getNormalizeGain(View *v, int channel) const +{ + long startFrame = v->getStartFrame(); + long endFrame = v->getEndFrame(); + + // Although a long for purposes of comparison against the view + // start and end frames, these are known to be non-negative + long modelStart = long(m_model->getStartFrame()); + long modelEnd = long(m_model->getEndFrame()); + + size_t rangeStart, rangeEnd; + + if (startFrame < modelStart) rangeStart = modelStart; + else rangeStart = startFrame; + + if (endFrame < 0) rangeEnd = 0; + else if (endFrame > modelEnd) rangeEnd = modelEnd; + else rangeEnd = endFrame; + + if (rangeEnd < rangeStart) rangeEnd = rangeStart; + + RangeSummarisableTimeValueModel::Range range = + m_model->getSummary(channel, rangeStart, rangeEnd - rangeStart); + + size_t minChannel = 0, maxChannel = 0; + bool mergingChannels = false, mixingChannels = false; + + getChannelArrangement(minChannel, maxChannel, + mergingChannels, mixingChannels); + + if (mergingChannels || mixingChannels) { + RangeSummarisableTimeValueModel::Range otherRange = + m_model->getSummary(1, rangeStart, rangeEnd - rangeStart); + range.max = std::max(range.max, otherRange.max); + range.min = std::min(range.min, otherRange.min); + range.absmean = std::min(range.absmean, otherRange.absmean); + } + + return 1.0 / std::max(fabsf(range.max), fabsf(range.min)); +} + void WaveformLayer::paint(View *v, QPainter &viewPainter, QRect rect) const { @@ -403,8 +470,6 @@ return; } - long startFrame = v->getStartFrame(); - long endFrame = v->getEndFrame(); int zoomLevel = v->getZoomLevel(); #ifdef DEBUG_WAVEFORM_PAINT @@ -478,11 +543,26 @@ if (x0 > 0) --x0; if (x1 < v->width()) ++x1; - long frame0 = v->getFrameForX(x0); - long frame1 = v->getFrameForX(x1 + 1); + // Our zoom level may differ from that at which the underlying + // model has its blocks. + // Each pixel within our visible range must always draw from + // exactly the same set of underlying audio frames, no matter what + // the range being drawn is. And that set of underlying frames + // must remain the same when we scroll one or more pixels left or + // right. + + size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel); + + size_t frame0; + size_t frame1; + size_t spare; + + getSourceFramesForX(v, x0, modelZoomLevel, frame0, spare); + getSourceFramesForX(v, x1, modelZoomLevel, spare, frame1); + #ifdef DEBUG_WAVEFORM_PAINT - std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << ")" << std::endl; + std::cerr << "Painting waveform from " << frame0 << " to " << frame1 << " (" << (x1-x0+1) << " pixels at zoom " << zoomLevel << " and model zoom " << modelZoomLevel << ")" << std::endl; #endif RangeSummarisableTimeValueModel::RangeBlock *ranges = @@ -507,45 +587,15 @@ m_effectiveGains.push_back(m_gain); } - // Although a long for purposes of comparison against the view - // start and end frames, these are known to be non-negative - long modelStart = long(m_model->getStartFrame()); - long modelEnd = long(m_model->getEndFrame()); - -#ifdef DEBUG_WAVEFORM_PAINT - std::cerr << "Model start = " << modelStart << ", end = " << modelEnd << std::endl; -#endif - for (size_t ch = minChannel; ch <= maxChannel; ++ch) { int prevRangeBottom = -1, prevRangeTop = -1; QColor prevRangeBottomColour = baseColour, prevRangeTopColour = baseColour; - size_t rangeStart, rangeEnd; m_effectiveGains[ch] = m_gain; if (m_autoNormalize) { - - if (startFrame < modelStart) rangeStart = modelStart; - else rangeStart = startFrame; - - if (endFrame < 0) rangeEnd = 0; - else if (endFrame > modelEnd) rangeEnd = modelEnd; - else rangeEnd = endFrame; - - if (rangeEnd < rangeStart) rangeEnd = rangeStart; - - RangeSummarisableTimeValueModel::Range range = - m_model->getSummary(ch, rangeStart, rangeEnd - rangeStart); - if (mergingChannels || mixingChannels) { - RangeSummarisableTimeValueModel::Range otherRange = - m_model->getSummary(1, rangeStart, rangeEnd - rangeStart); - range.max = std::max(range.max, otherRange.max); - range.min = std::min(range.min, otherRange.min); - range.absmean = std::min(range.absmean, otherRange.absmean); - } - m_effectiveGains[ch] = 1.0 / std::max(fabsf(range.max), - fabsf(range.min)); + m_effectiveGains[ch] = getNormalizeGain(v, ch); } float gain = m_effectiveGains[ch]; @@ -613,25 +663,14 @@ } } } + + m_model->getSummaries(ch, frame0, frame1 - frame0, + *ranges, modelZoomLevel); - if (frame1 < modelStart) continue; +#ifdef DEBUG_WAVEFORM_PAINT + std::cerr << ranges->size() << " ranges from " << frame0 << " to " << frame1 << std::endl; +#endif - size_t modelZoomLevel = zoomLevel; - - if (frame0 < modelStart) rangeStart = modelStart; - else rangeStart = frame0; - - if (frame1 < 0) rangeEnd = 0; - else if (frame1 > modelEnd) rangeEnd = modelEnd; - else rangeEnd = frame1; - - if (rangeEnd < rangeStart) rangeEnd = rangeStart; - - m_model->getSummaries - (ch, rangeStart, rangeEnd - rangeStart, *ranges, modelZoomLevel); - -// std::cerr << ranges->size() << " ranges" << std::endl; - if (mergingChannels || mixingChannels) { if (m_model->getChannelCount() > 1) { if (!otherChannelRanges) { @@ -639,7 +678,7 @@ new RangeSummarisableTimeValueModel::RangeBlock; } m_model->getSummaries - (1, rangeStart, rangeEnd - rangeStart, *otherChannelRanges, + (1, frame0, frame1 - frame0, *otherChannelRanges, modelZoomLevel); } else { if (otherChannelRanges != ranges) delete otherChannelRanges; @@ -650,42 +689,35 @@ for (int x = x0; x <= x1; ++x) { range = RangeSummarisableTimeValueModel::Range(); - size_t index = x - x0; - size_t maxIndex = index; - if (frame0 < modelStart) { - if (index < size_t((modelStart - frame0) / zoomLevel)) { - continue; - } else { - index -= ((modelStart - frame0) / zoomLevel); - maxIndex = index; - } + size_t f0, f1; + if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) continue; + f1 = f1 - 1; + + if (f0 < frame0) { + std::cerr << "ERROR: WaveformLayer::paint: pixel " << x << " has f0 = " << f0 << " which is less than range frame0 " << frame0 << " for x0 = " << x0 << std::endl; + continue; } - - if (int(modelZoomLevel) != zoomLevel) { - index = size_t((double(index) * zoomLevel) / modelZoomLevel); + size_t i0 = (f0 - frame0) / modelZoomLevel; + size_t i1 = (f1 - frame0) / modelZoomLevel; - if (int(modelZoomLevel) < zoomLevel) { - // Peaks may be missed! The model should avoid - // this by rounding zoom levels up rather than - // down, but we'd better cope in case it doesn't - maxIndex = index; - } else { - maxIndex = size_t((double(index + 1) * zoomLevel) - / modelZoomLevel) - 1; - } - } +#ifdef DEBUG_WAVEFORM_PAINT + std::cerr << "WaveformLayer::paint: pixel " << x << ": i0 " << i0 << " (f " << f0 << "), i1 " << i1 << " (f " << f1 << ")" << std::endl; +#endif - if (ranges && index < ranges->size()) { + if (i1 > i0 + 1) { + std::cerr << "WaveformLayer::paint: ERROR: i1 " << i1 << " > i0 " << i0 << " plus one (zoom = " << zoomLevel << ", model zoom = " << modelZoomLevel << ")" << std::endl; + } - range = (*ranges)[index]; + if (ranges && i0 < ranges->size()) { - if (maxIndex > index && maxIndex < ranges->size()) { - range.max = std::max(range.max, (*ranges)[maxIndex].max); - range.min = std::min(range.min, (*ranges)[maxIndex].min); - range.absmean = (range.absmean + - (*ranges)[maxIndex].absmean) / 2; + range = (*ranges)[i0]; + + if (i1 > i0 && i1 < ranges->size()) { + range.max = std::max(range.max, (*ranges)[i1].max); + range.min = std::min(range.min, (*ranges)[i1].min); + range.absmean = (range.absmean + (*ranges)[i1].absmean) / 2; } } else { @@ -696,28 +728,28 @@ if (mergingChannels) { - if (otherChannelRanges && index < otherChannelRanges->size()) { + if (otherChannelRanges && i0 < otherChannelRanges->size()) { range.max = fabsf(range.max); - range.min = -fabsf((*otherChannelRanges)[index].max); + range.min = -fabsf((*otherChannelRanges)[i0].max); range.absmean = (range.absmean + - (*otherChannelRanges)[index].absmean) / 2; + (*otherChannelRanges)[i0].absmean) / 2; - if (maxIndex > index && maxIndex < otherChannelRanges->size()) { + if (i1 > i0 && i1 < otherChannelRanges->size()) { // let's not concern ourselves about the mean range.min = std::min (range.min, - -fabsf((*otherChannelRanges)[maxIndex].max)); + -fabsf((*otherChannelRanges)[i1].max)); } } } else if (mixingChannels) { - if (otherChannelRanges && index < otherChannelRanges->size()) { + if (otherChannelRanges && i0 < otherChannelRanges->size()) { - range.max = (range.max + (*otherChannelRanges)[index].max) / 2; - range.min = (range.min + (*otherChannelRanges)[index].min) / 2; - range.absmean = (range.absmean + (*otherChannelRanges)[index].absmean) / 2; + range.max = (range.max + (*otherChannelRanges)[i0].max) / 2; + range.min = (range.min + (*otherChannelRanges)[i0].min) / 2; + range.absmean = (range.absmean + (*otherChannelRanges)[i0].absmean) / 2; } } @@ -890,11 +922,12 @@ if (!m_model || !m_model->isOK()) return ""; - long f0 = v->getFrameForX(x); - long f1 = v->getFrameForX(x + 1); + int zoomLevel = v->getZoomLevel(); - if (f0 < 0) f0 = 0; - if (f1 <= f0) return ""; + size_t modelZoomLevel = m_model->getSummaryBlockSize(zoomLevel); + + size_t f0, f1; + if (!getSourceFramesForX(v, x, modelZoomLevel, f0, f1)) return ""; QString text; diff -r 813170c57b13 -r 0895517bb2d1 layer/WaveformLayer.h --- a/layer/WaveformLayer.h Thu Nov 29 10:43:54 2007 +0000 +++ b/layer/WaveformLayer.h Wed Feb 27 10:32:45 2008 +0000 @@ -202,6 +202,11 @@ float getValueForY(const View *v, int y, size_t &channel) const; + bool getSourceFramesForX(View *v, int x, size_t modelZoomLevel, + size_t &f0, size_t &f1) const; + + float getNormalizeGain(View *v, int channel) const; + virtual void flagBaseColourChanged() { m_cacheValid = false; } float m_gain; diff -r 813170c57b13 -r 0895517bb2d1 view/Overview.cpp --- a/view/Overview.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/view/Overview.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -71,6 +71,7 @@ void Overview::modelReplaced() { + m_playPointerFrame = getAlignedPlaybackFrame(); View::modelReplaced(); } @@ -116,6 +117,8 @@ { bool changed = false; + f = getAlignedPlaybackFrame(); + if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true; m_playPointerFrame = f; @@ -179,6 +182,15 @@ long f0 = w->getFrameForX(0); long f1 = w->getFrameForX(w->width()); + if (f0 >= 0) { + size_t rf0 = w->alignToReference(f0); + f0 = alignFromReference(rf0); + } + if (f1 >= 0) { + size_t rf1 = w->alignToReference(f1); + f1 = alignFromReference(rf1); + } + int x0 = getXForFrame(f0); int x1 = getXForFrame(f1); @@ -200,12 +212,16 @@ Overview::mousePressEvent(QMouseEvent *e) { m_clickPos = e->pos(); + long clickFrame = getFrameForX(m_clickPos.x()); + if (clickFrame > 0) m_dragCentreFrame = clickFrame; + else m_dragCentreFrame = 0; + m_clickedInRange = true; + for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) { - if (*i) { - m_clickedInRange = true; - m_dragCentreFrame = ((View *)*i)->getCentreFrame(); - break; - } + if (*i && (*i)->getAligningModel() == getAligningModel()) { + m_dragCentreFrame = (*i)->getCentreFrame(); + break; + } } } @@ -242,7 +258,8 @@ if (std::max(m_centreFrame, newCentreFrame) - std::min(m_centreFrame, newCentreFrame) > size_t(m_zoomLevel)) { - emit centreFrameChanged(newCentreFrame, true, PlaybackScrollContinuous); + size_t rf = alignToReference(newCentreFrame); + emit centreFrameChanged(rf, true, PlaybackScrollContinuous); } } @@ -250,7 +267,9 @@ Overview::mouseDoubleClickEvent(QMouseEvent *e) { long frame = getFrameForX(e->x()); - emit centreFrameChanged(frame, true, PlaybackScrollContinuous); + size_t rf = 0; + if (frame > 0) rf = alignToReference(frame); + emit centreFrameChanged(rf, true, PlaybackScrollContinuous); } void diff -r 813170c57b13 -r 0895517bb2d1 view/Pane.cpp --- a/view/Pane.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/view/Pane.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -22,6 +22,7 @@ #include "ViewManager.h" #include "base/CommandHistory.h" #include "base/TextAbbrev.h" +#include "base/Preferences.h" #include "layer/WaveformLayer.h" //!!! ugh @@ -49,6 +50,8 @@ #include "widgets/KeyReference.h" //!!! should probably split KeyReference into a data class in base and another that shows the widget +//#define DEBUG_PANE + using std::cerr; using std::endl; @@ -63,6 +66,8 @@ m_ctrlPressed(false), m_navigating(false), m_resizing(false), + m_editing(false), + m_releasing(false), m_centreLineVisible(true), m_scaleWidth(0), m_headsUpDisplay(0), @@ -388,6 +393,7 @@ View::paintEvent(e); paint.begin(this); + setPaintFont(paint); if (e) paint.setClipRect(r); @@ -1209,6 +1215,8 @@ return; } +// std::cerr << "mousePressEvent" << std::endl; + m_clickPos = e->pos(); m_mousePos = m_clickPos; m_clickedInRange = true; @@ -1222,6 +1230,9 @@ if (m_manager) mode = m_manager->getToolMode(); m_navigating = false; + m_resizing = false; + m_editing = false; + m_releasing = false; if (mode == ViewManager::NavigateMode || (e->buttons() & Qt::MidButton) || @@ -1303,12 +1314,8 @@ } else if (mode == ViewManager::EditMode) { - if (!editSelectionStart(e)) { - Layer *layer = getSelectedLayer(); - if (layer && layer->isLayerEditable()) { - layer->editStart(this, e); - } - } + // Do nothing here -- we'll do it in mouseMoveEvent when the + // drag threshold has been passed } else if (mode == ViewManager::MeasureMode) { @@ -1327,9 +1334,13 @@ return; } +// std::cerr << "mouseReleaseEvent" << std::endl; + ViewManager::ToolMode mode = ViewManager::NavigateMode; if (m_manager) mode = m_manager->getToolMode(); + m_releasing = true; + if (m_clickedInRange) { mouseMoveEvent(e); } @@ -1356,7 +1367,10 @@ } else if (mode == ViewManager::SelectMode) { - if (!hasTopLayerTimeXAxis()) return; + if (!hasTopLayerTimeXAxis()) { + m_releasing = false; + return; + } if (m_manager && m_manager->haveInProgressSelection()) { @@ -1396,13 +1410,15 @@ } else if (mode == ViewManager::EditMode) { - if (!editSelectionEnd(e)) { - Layer *layer = getSelectedLayer(); - if (layer && layer->isLayerEditable()) { - layer->editEnd(this, e); - update(); - } - } + if (m_editing) { + if (!editSelectionEnd(e)) { + Layer *layer = getSelectedLayer(); + if (layer && layer->isLayerEditable()) { + layer->editEnd(this, e); + update(); + } + } + } } else if (mode == ViewManager::MeasureMode) { @@ -1413,6 +1429,7 @@ } m_clickedInRange = false; + m_releasing = false; emit paneInteractedWith(); } @@ -1424,8 +1441,24 @@ return; } +// std::cerr << "mouseMoveEvent" << std::endl; + updateContextHelp(&e->pos()); + if (m_navigating && m_clickedInRange && !m_releasing) { + + // if no buttons pressed, and not called from + // mouseReleaseEvent, we want to reset clicked-ness (to avoid + // annoying continual drags when we moved the mouse outside + // the window after pressing button first time). + + if (!(e->buttons() & Qt::LeftButton) && + !(e->buttons() & Qt::MidButton)) { + m_clickedInRange = false; + return; + } + } + ViewManager::ToolMode mode = ViewManager::NavigateMode; if (m_manager) mode = m_manager->getToolMode(); @@ -1509,12 +1542,44 @@ } else if (mode == ViewManager::EditMode) { - if (!editSelectionDrag(e)) { - Layer *layer = getSelectedLayer(); - if (layer && layer->isLayerEditable()) { - layer->editDrag(this, e); - } - } + if (m_editing) { + if (!editSelectionDrag(e)) { + Layer *layer = getSelectedLayer(); + if (layer && layer->isLayerEditable()) { + layer->editDrag(this, e); + } + } + } + + if (!m_editing) { + + DragMode newDragMode = updateDragMode + (m_dragMode, + m_clickPos, + e->pos(), + true, // can move horiz + true, // can move vert + true, // resist horiz + true); // resist vert + + if (newDragMode != UnresolvedDrag) { + + m_editing = true; + + QMouseEvent clickEvent(QEvent::MouseButtonPress, + m_clickPos, + Qt::NoButton, + e->buttons(), + e->modifiers()); + + if (!editSelectionStart(&clickEvent)) { + Layer *layer = getSelectedLayer(); + if (layer && layer->isLayerEditable()) { + layer->editStart(this, &clickEvent); + } + } + } + } } else if (mode == ViewManager::MeasureMode) { @@ -1615,51 +1680,17 @@ // If the top layer is incapable of being dragged // vertically, the logic is short circuited. - int xdiff = e->x() - m_clickPos.x(); - int ydiff = e->y() - m_clickPos.y(); - int smallThreshold = 10, bigThreshold = 50; + m_dragMode = updateDragMode + (m_dragMode, + m_clickPos, + e->pos(), + true, // can move horiz + canTopLayerMoveVertical(), // can move vert + canTopLayerMoveVertical() || (m_manager && m_manager->isPlaying()), // resist horiz + !(m_manager && m_manager->isPlaying())); // resist vert - bool canMoveVertical = canTopLayerMoveVertical(); - bool canMoveHorizontal = true; - - if (!canMoveHorizontal) { - m_dragMode = HorizontalDrag; - } - - if (m_dragMode == UnresolvedDrag) { - - if (abs(ydiff) > smallThreshold && - abs(ydiff) > abs(xdiff) * 2) { - m_dragMode = VerticalDrag; - } else if (abs(xdiff) > smallThreshold && - abs(xdiff) > abs(ydiff) * 2) { - m_dragMode = HorizontalDrag; - } else if (abs(xdiff) > smallThreshold && - abs(ydiff) > smallThreshold) { - m_dragMode = FreeDrag; - } else { - // When playing, we don't want to disturb the play - // position too easily; when not playing, we don't - // want to move up/down too easily - if (m_manager && m_manager->isPlaying()) { - canMoveHorizontal = false; - } else { - canMoveVertical = false; - } - } - } - - if (m_dragMode == VerticalDrag) { - if (abs(xdiff) > bigThreshold) m_dragMode = FreeDrag; - else canMoveHorizontal = false; - } - - if (m_dragMode == HorizontalDrag && canMoveVertical) { - if (abs(ydiff) > bigThreshold) m_dragMode = FreeDrag; - else canMoveVertical = false; - } - - if (canMoveHorizontal) { + if (m_dragMode == HorizontalDrag || + m_dragMode == FreeDrag) { long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x()); @@ -1672,7 +1703,12 @@ } else { newCentreFrame = 0; } - + +#ifdef DEBUG_PANE + std::cerr << "Pane::dragTopLayer: newCentreFrame = " << newCentreFrame << + ", models end frame = " << getModelsEndFrame() << std::endl; +#endif + if (newCentreFrame >= getModelsEndFrame()) { newCentreFrame = getModelsEndFrame(); if (newCentreFrame > 0) --newCentreFrame; @@ -1683,7 +1719,8 @@ } } - if (canMoveVertical) { + if (m_dragMode == VerticalDrag || + m_dragMode == FreeDrag) { float vmin = 0.f, vmax = 0.f; float dmin = 0.f, dmax = 0.f; @@ -1692,10 +1729,15 @@ // std::cerr << "ydiff = " << ydiff << std::endl; + int ydiff = e->y() - m_clickPos.y(); float perpix = (dmax - dmin) / height(); float valdiff = ydiff * perpix; // std::cerr << "valdiff = " << valdiff << std::endl; + if (m_dragMode == UnresolvedDrag && ydiff != 0) { + m_dragMode = VerticalDrag; + } + float newmin = m_dragStartMinValue + valdiff; float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff; if (newmin < vmin) { @@ -1715,6 +1757,65 @@ } } +Pane::DragMode +Pane::updateDragMode(DragMode dragMode, + QPoint origin, + QPoint point, + bool canMoveHorizontal, + bool canMoveVertical, + bool resistHorizontal, + bool resistVertical) +{ + int xdiff = point.x() - origin.x(); + int ydiff = point.y() - origin.y(); + + int smallThreshold = 10, bigThreshold = 80; + +// std::cerr << "Pane::updateDragMode: xdiff = " << xdiff << ", ydiff = " +// << ydiff << ", canMoveVertical = " << canMoveVertical << ", drag mode = " << m_dragMode << std::endl; + + if (dragMode == UnresolvedDrag) { + + if (abs(ydiff) > smallThreshold && + abs(ydiff) > abs(xdiff) * 2 && + canMoveVertical) { +// std::cerr << "Pane::updateDragMode: passed vertical threshold" << std::endl; + dragMode = VerticalDrag; + } else if (abs(xdiff) > smallThreshold && + abs(xdiff) > abs(ydiff) * 2 && + canMoveHorizontal) { +// std::cerr << "Pane::updateDragMode: passed horizontal threshold" << std::endl; + dragMode = HorizontalDrag; + } else if (abs(xdiff) > smallThreshold && + abs(ydiff) > smallThreshold && + canMoveVertical && + canMoveHorizontal) { +// std::cerr << "Pane::updateDragMode: passed both thresholds" << std::endl; + dragMode = FreeDrag; + } + } + + if (dragMode == VerticalDrag && canMoveHorizontal) { + if (abs(xdiff) > bigThreshold) dragMode = FreeDrag; + } + + if (dragMode == HorizontalDrag && canMoveVertical) { + if (abs(ydiff) > bigThreshold) dragMode = FreeDrag; + } + + if (dragMode == UnresolvedDrag) { + if (!resistHorizontal && xdiff != 0) { + dragMode = HorizontalDrag; + } + if (!resistVertical && ydiff != 0) { + if (dragMode == HorizontalDrag) dragMode = FreeDrag; + else dragMode = VerticalDrag; + } + } + + return dragMode; +} + void Pane::dragExtendSelection(QMouseEvent *e) { diff -r 813170c57b13 -r 0895517bb2d1 view/Pane.h --- a/view/Pane.h Thu Nov 29 10:43:54 2007 +0000 +++ b/view/Pane.h Wed Feb 27 10:32:45 2008 +0000 @@ -142,6 +142,8 @@ bool m_navigating; bool m_resizing; + bool m_editing; + bool m_releasing; size_t m_dragCentreFrame; float m_dragStartMinValue; bool m_centreLineVisible; @@ -158,6 +160,14 @@ }; DragMode m_dragMode; + DragMode updateDragMode(DragMode currentMode, + QPoint origin, + QPoint currentPoint, + bool canMoveHorizontal, + bool canMoveVertical, + bool resistHorizontal, + bool resistVertical); + QWidget *m_headsUpDisplay; Panner *m_vpan; Thumbwheel *m_hthumb; diff -r 813170c57b13 -r 0895517bb2d1 view/PaneStack.cpp --- a/view/PaneStack.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/view/PaneStack.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -495,14 +495,7 @@ std::cerr << "PaneStack::sizePropertyStacks: max min width " << maxMinWidth << std::endl; #endif -//#ifdef Q_WS_MAC - // This is necessary to compensate for cb->setMinimumSize(10, 10) - // in PropertyBox in the Mac version (to avoid a mysterious crash) - // ... no longer necessary with qt4.2 -// int setWidth = maxMinWidth * 3 / 2; -//#else int setWidth = maxMinWidth; -//#endif m_propertyStackStack->setMaximumWidth(setWidth + 10); @@ -511,6 +504,7 @@ m_panes[i].propertyStack->setMinimumWidth(setWidth); } + emit propertyStacksResized(setWidth); emit propertyStacksResized(); } diff -r 813170c57b13 -r 0895517bb2d1 view/PaneStack.h --- a/view/PaneStack.h Thu Nov 29 10:43:54 2007 +0000 +++ b/view/PaneStack.h Wed Feb 27 10:32:45 2008 +0000 @@ -74,6 +74,7 @@ void currentPaneChanged(Pane *pane); void currentLayerChanged(Pane *pane, Layer *layer); void rightButtonMenuRequested(Pane *pane, QPoint position); + void propertyStacksResized(int width); void propertyStacksResized(); void contextHelpChanged(const QString &); diff -r 813170c57b13 -r 0895517bb2d1 view/View.cpp --- a/view/View.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/view/View.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -19,6 +19,7 @@ #include "base/ZoomConstraint.h" #include "base/Profiler.h" #include "base/Pitch.h" +#include "base/Preferences.h" #include "layer/TimeRulerLayer.h" #include "layer/SingleColourLayer.h" @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -328,9 +330,11 @@ if (e) { size_t rf = alignToReference(f); +#ifdef DEBUG_VIEW_WIDGET_PAINT std::cerr << "View[" << this << "]::setCentreFrame(" << f << "): emitting centreFrameChanged(" << rf << ")" << std::endl; +#endif emit centreFrameChanged(rf, m_followPan, m_followPlay); } } @@ -349,6 +353,11 @@ { long z = (long)m_zoomLevel; long frame = m_centreFrame - (width()/2) * z; + +#ifdef DEBUG_VIEW_WIDGET_PAINT + std::cerr << "View::getFrameForX(" << x << "): z = " << z << ", m_centreFrame = " << m_centreFrame << ", width() = " << width() << ", frame = " << frame << std::endl; +#endif + frame = (frame / z) * z; // this is start frame return frame + x * z; } @@ -503,9 +512,6 @@ View::LayerProgressBar::LayerProgressBar(QWidget *parent) : QProgressBar(parent) { - QFont f(font()); - f.setPointSize(f.pointSize() * 8 / 10); - setFont(f); } void @@ -523,6 +529,12 @@ m_progressBars[layer]->setMinimum(0); m_progressBars[layer]->setMaximum(100); m_progressBars[layer]->setMinimumWidth(80); + + QFont f(m_progressBars[layer]->font()); + int fs = Preferences::getInstance()->getViewFontSize(); + f.setPointSize(std::min(fs, int(ceil(fs * 0.85)))); + + m_progressBars[layer]->setFont(f); m_progressBars[layer]->hide(); connect(layer, SIGNAL(layerParametersChanged()), @@ -655,7 +667,10 @@ connect(this, SIGNAL(zoomLevelChanged(unsigned long, bool)), m_manager, SLOT(viewZoomLevelChanged(unsigned long, bool))); - if (m_followPlay != PlaybackIgnore) { + if (m_followPlay == PlaybackScrollPage) { +// std::cerr << "View::setViewManager: setting centre frame to global centre frame: " << m_manager->getGlobalCentreFrame() << std::endl; + setCentreFrame(m_manager->getGlobalCentreFrame(), false); + } else if (m_followPlay == PlaybackScrollContinuous) { // std::cerr << "View::setViewManager: setting centre frame to playback frame: " << m_manager->getPlaybackFrame() << std::endl; setCentreFrame(m_manager->getPlaybackFrame(), false); } else if (m_followPan) { @@ -880,8 +895,10 @@ { if (m_followPan) { size_t f = alignFromReference(rf); +#ifdef DEBUG_VIEW_WIDGET_PAINT std::cerr << "View[" << this << "]::globalCentreFrameChanged(" << rf << "): setting centre frame to " << f << std::endl; +#endif setCentreFrame(f, false); } } @@ -1108,6 +1125,7 @@ } Model *anyModel = 0; + Model *alignedModel = 0; Model *goodModel = 0; for (LayerList::const_iterator i = m_layers.begin(); @@ -1121,8 +1139,10 @@ Model *model = (*i)->getModel(); if (!model) continue; + anyModel = model; + if (model->getAlignmentReference()) { - anyModel = model; + alignedModel = model; if (layer->isLayerOpaque() || dynamic_cast(model)) { goodModel = model; @@ -1131,6 +1151,7 @@ } if (goodModel) return goodModel; + else if (alignedModel) return alignedModel; else return anyModel; } @@ -1399,6 +1420,14 @@ } void +View::setPaintFont(QPainter &paint) +{ + QFont font(paint.font()); + font.setPointSize(Preferences::getInstance()->getViewFontSize()); + paint.setFont(font); +} + +void View::paintEvent(QPaintEvent *e) { // Profiler prof("View::paintEvent", false); @@ -1583,7 +1612,7 @@ if (repaintCache) paint.begin(m_cache); else paint.begin(this); - + setPaintFont(paint); paint.setClipRect(cacheRect); paint.setPen(getBackground()); @@ -1624,7 +1653,7 @@ paint.begin(this); paint.setClipRect(nonCacheRect); - + setPaintFont(paint); if (scrollables.empty()) { paint.setPen(getBackground()); paint.setBrush(getBackground()); @@ -1642,6 +1671,7 @@ paint.end(); paint.begin(this); + setPaintFont(paint); if (e) paint.setClipRect(e->rect()); if (!m_selectionCached) { drawSelections(paint); @@ -1885,6 +1915,8 @@ int labelCount = 0; + // top-left point, x-coord + if ((b0 = topLayer->getXScaleValue(this, r.x(), v0, u0))) { axs = QString("%1 %2").arg(v0).arg(u0); if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) { @@ -1894,6 +1926,8 @@ aw = paint.fontMetrics().width(axs); ++labelCount; } + + // bottom-right point, x-coord if (r.width() > 0) { if ((b1 = topLayer->getXScaleValue(this, r.x() + r.width(), v1, u1))) { @@ -1905,15 +1939,19 @@ bw = paint.fontMetrics().width(bxs); } } + + // dimension, width if (b0 && b1 && v1 != v0 && u0 == u1) { - dxs = QString("(%1 %2)").arg(fabs(v1 - v0)).arg(u1); + dxs = QString("[%1 %2]").arg(fabs(v1 - v0)).arg(u1); dw = paint.fontMetrics().width(dxs); } b0 = false; b1 = false; + // top-left point, y-coord + if ((b0 = topLayer->getYScaleValue(this, r.y(), v0, u0))) { ays = QString("%1 %2").arg(v0).arg(u0); if (u0 == "Hz" && Pitch::isFrequencyInMidiRange(v0)) { @@ -1924,6 +1962,8 @@ ++labelCount; } + // bottom-right point, y-coord + if (r.height() > 0) { if ((b1 = topLayer->getYScaleValue(this, r.y() + r.height(), v1, u1))) { bys = QString("%1 %2").arg(v1).arg(u1); @@ -1939,13 +1979,24 @@ float dy = 0.f; QString du; + // dimension, height + if ((bd = topLayer->getYScaleDifference(this, r.y(), r.y() + r.height(), dy, du)) && dy != 0) { if (du != "") { - dys = QString("(%1 %2)").arg(dy).arg(du); + if (du == "Hz") { + int semis; + float cents; + semis = Pitch::getPitchForFrequencyDifference(v0, v1, ¢s); + dys = QString("[%1 %2 (%3)]") + .arg(dy).arg(du) + .arg(Pitch::getLabelForPitchRange(semis, cents)); + } else { + dys = QString("[%1 %2]").arg(dy).arg(du); + } } else { - dys = QString("(%1)").arg(dy); + dys = QString("[%1]").arg(dy); } dw = std::max(dw, paint.fontMetrics().width(dys)); } diff -r 813170c57b13 -r 0895517bb2d1 view/View.h --- a/view/View.h Thu Nov 29 10:43:54 2007 +0000 +++ b/view/View.h Wed Feb 27 10:32:45 2008 +0000 @@ -310,7 +310,8 @@ virtual void drawSelections(QPainter &); virtual bool shouldLabelSelections() const { return true; } virtual bool render(QPainter &paint, int x0, size_t f0, size_t f1); - + virtual void setPaintFont(QPainter &paint); + typedef std::vector LayerList; int getModelsSampleRate() const; diff -r 813170c57b13 -r 0895517bb2d1 view/ViewManager.cpp --- a/view/ViewManager.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/view/ViewManager.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -57,7 +57,7 @@ settings.endGroup(); if (getGlobalDarkBackground()) { - +/* std::cerr << "dark palette:" << std::endl; std::cerr << "window = " << QApplication::palette().color(QPalette::Window).name().toStdString() << std::endl; std::cerr << "windowtext = " << QApplication::palette().color(QPalette::WindowText).name().toStdString() << std::endl; @@ -70,7 +70,7 @@ std::cerr << "light = " << QApplication::palette().color(QPalette::Light).name().toStdString() << std::endl; std::cerr << "dark = " << QApplication::palette().color(QPalette::Dark).name().toStdString() << std::endl; std::cerr << "mid = " << QApplication::palette().color(QPalette::Mid).name().toStdString() << std::endl; - +*/ m_lightPalette = QPalette(QColor("#000000"), // WindowText QColor("#dddfe4"), // Button QColor("#ffffff"), // Light @@ -83,6 +83,7 @@ } else { +/* std::cerr << "light palette:" << std::endl; std::cerr << "window = " << QApplication::palette().color(QPalette::Window).name().toStdString() << std::endl; std::cerr << "windowtext = " << QApplication::palette().color(QPalette::WindowText).name().toStdString() << std::endl; @@ -95,7 +96,7 @@ std::cerr << "light = " << QApplication::palette().color(QPalette::Light).name().toStdString() << std::endl; std::cerr << "dark = " << QApplication::palette().color(QPalette::Dark).name().toStdString() << std::endl; std::cerr << "mid = " << QApplication::palette().color(QPalette::Mid).name().toStdString() << std::endl; - +*/ m_darkPalette = QPalette(QColor("#ffffff"), // WindowText QColor("#3e3e3e"), // Button QColor("#808080"), // Light @@ -274,18 +275,19 @@ MultiSelection::SelectionList sl = getSelections(); if (sl.empty()) return frame; - size_t selectionStartFrame = sl.begin()->getStartFrame(); - if (frame < selectionStartFrame) { - frame = selectionStartFrame; - return frame; + for (MultiSelection::SelectionList::const_iterator i = sl.begin(); + i != sl.end(); ++i) { + + if (frame < i->getEndFrame()) { + if (frame < i->getStartFrame()) { + return i->getStartFrame(); + } else { + return frame; + } + } } - MultiSelection::SelectionList::iterator i = sl.end(); - --i; - size_t selectionEndFrame = i->getEndFrame(); - if (frame > selectionEndFrame) frame = selectionEndFrame; - - return frame; + return sl.begin()->getStartFrame(); } void diff -r 813170c57b13 -r 0895517bb2d1 widgets/AudioDial.cpp --- a/widgets/AudioDial.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/AudioDial.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -75,6 +75,7 @@ m_knobColor(Qt::black), m_meterColor(Qt::white), m_defaultValue(0), + m_defaultMappedValue(0), m_mappedValue(0), m_noMappedUpdate(false), m_showTooltip(true), @@ -334,15 +335,24 @@ void AudioDial::setDefaultValue(int defaultValue) { m_defaultValue = defaultValue; + if (m_rangeMapper) { + m_defaultMappedValue = m_rangeMapper->getValueForPosition(defaultValue); + } } - void AudioDial::setValue(int value) { QDial::setValue(value); updateMappedValue(value); } +void AudioDial::setDefaultMappedValue(float value) +{ + m_defaultMappedValue = value; + if (m_rangeMapper) { + m_defaultValue = m_rangeMapper->getPositionForValue(value); + } +} void AudioDial::setMappedValue(float mappedValue) { @@ -407,6 +417,18 @@ } } +void +AudioDial::setToDefault() +{ + if (m_rangeMapper) { + setMappedValue(m_defaultMappedValue); + return; + } + int dv = m_defaultValue; + if (dv < minimum()) dv = minimum(); + if (dv > maximum()) dv = maximum(); + setValue(m_defaultValue); +} // Alternate mouse behavior event handlers. void AudioDial::mousePressEvent(QMouseEvent *mouseEvent) @@ -416,10 +438,7 @@ } else if (mouseEvent->button() == Qt::MidButton || ((mouseEvent->button() == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier))) { - int dv = m_defaultValue; - if (dv < minimum()) dv = minimum(); - if (dv > maximum()) dv = maximum(); - setValue(m_defaultValue); + setToDefault(); } else if (mouseEvent->button() == Qt::LeftButton) { m_mousePressed = true; m_posMouse = mouseEvent->pos(); diff -r 813170c57b13 -r 0895517bb2d1 widgets/AudioDial.h --- a/widgets/AudioDial.h Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/AudioDial.h Wed Feb 27 10:32:45 2008 +0000 @@ -107,8 +107,12 @@ void setValue(int value); + void setDefaultMappedValue(float mappedValue); + void setMappedValue(float mappedValue); + void setToDefault(); + protected: void drawTick(QPainter &paint, float angle, int size, bool internal); virtual void paintEvent(QPaintEvent *); @@ -129,6 +133,7 @@ QColor m_meterColor; int m_defaultValue; + float m_defaultMappedValue; float m_mappedValue; bool m_noMappedUpdate; diff -r 813170c57b13 -r 0895517bb2d1 widgets/ImageDialog.cpp --- a/widgets/ImageDialog.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/ImageDialog.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -186,7 +186,7 @@ tr("The URL scheme \"%1\" is not supported") .arg(url.scheme())); } else { - m_remoteFile = new FileSource(url, true); + m_remoteFile = new FileSource(url, FileSource::ProgressDialog); m_remoteFile->waitForData(); if (!m_remoteFile->isOK()) { QMessageBox::critical(this, tr("File download failed"), diff -r 813170c57b13 -r 0895517bb2d1 widgets/LabelCounterInputDialog.cpp --- a/widgets/LabelCounterInputDialog.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/LabelCounterInputDialog.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -37,7 +37,7 @@ layout->addWidget(label, 0, 0); QSpinBox *counter = new QSpinBox; - counter->setMinimum(1); + counter->setMinimum(-10); counter->setMaximum(10000); counter->setSingleStep(1); m_origSecondCounter = m_labeller->getSecondLevelCounterValue(); @@ -47,7 +47,7 @@ layout->addWidget(counter, 0, 1); counter = new QSpinBox; - counter->setMinimum(1); + counter->setMinimum(-10); counter->setMaximum(10000); counter->setSingleStep(1); m_origCounter = m_labeller->getCounterValue(); diff -r 813170c57b13 -r 0895517bb2d1 widgets/PluginParameterBox.cpp --- a/widgets/PluginParameterBox.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/PluginParameterBox.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -18,6 +18,7 @@ #include "AudioDial.h" #include "plugin/PluginXml.h" +#include "plugin/RealTimePluginInstance.h" // for PortHint stuff #include "base/RangeMapper.h" @@ -98,19 +99,31 @@ float deft = params[i].defaultValue; float value = m_plugin->getParameter(params[i].identifier); + int hint = PortHint::NoHint; + RealTimePluginInstance *rtpi = dynamic_cast + (m_plugin); + if (rtpi) { + hint = rtpi->getParameterDisplayHint(i); + } + float qtz = 0.0; if (params[i].isQuantized) qtz = params[i].quantizeStep; + std::cerr << "PluginParameterBox: hint = " << hint << ", min = " << min << ", max = " + << max << ", qtz = " << qtz << std::endl; + std::vector valueNames = params[i].valueNames; // construct an integer range int imin = 0, imax = 100; - if (qtz > 0.0) { - imax = int((max - min) / qtz); - } else { - qtz = (max - min) / 100.0; + if (!(hint & PortHint::Logarithmic)) { + if (qtz > 0.0) { + imax = int((max - min) / qtz); + } else { + qtz = (max - min) / 100.0; + } } //!!! would be nice to ensure the default value corresponds to @@ -162,12 +175,19 @@ dial->setMaximum(imax); dial->setPageStep(1); dial->setNotchesVisible((imax - imin) <= 12); - dial->setDefaultValue(lrintf((deft - min) / qtz)); - dial->setValue(lrintf((value - min) / qtz)); +//!!! dial->setDefaultValue(lrintf((deft - min) / qtz)); +// dial->setValue(lrintf((value - min) / qtz)); dial->setFixedWidth(32); dial->setFixedHeight(32); - dial->setRangeMapper(new LinearRangeMapper - (imin, imax, min, max, unit)); + RangeMapper *rm = 0; + if (hint & PortHint::Logarithmic) { + rm = new LogRangeMapper(imin, imax, min, max, unit); + } else { + rm = new LinearRangeMapper(imin, imax, min, max, unit); + } + dial->setRangeMapper(rm); + dial->setDefaultValue(rm->getPositionForValue(deft)); + dial->setValue(rm->getPositionForValue(value)); dial->setShowToolTip(true); connect(dial, SIGNAL(valueChanged(int)), this, SLOT(dialChanged(int))); @@ -178,7 +198,7 @@ spinbox->setMinimum(min); spinbox->setMaximum(max); spinbox->setSuffix(QString(" %1").arg(unit)); - spinbox->setSingleStep(qtz); + if (qtz != 0) spinbox->setSingleStep(qtz); spinbox->setValue(value); spinbox->setDecimals(4); connect(spinbox, SIGNAL(valueChanged(double)), @@ -238,6 +258,8 @@ newValue = min + ival * qtz; } + std::cerr << "PluginParameterBox::dialChanged: newValue = " << newValue << std::endl; + QDoubleSpinBox *spin = m_params[identifier].spin; if (spin) { spin->blockSignals(true); @@ -320,7 +342,11 @@ AudioDial *dial = m_params[identifier].dial; if (dial) { dial->blockSignals(true); - dial->setValue(ival); + if (dial->rangeMapper()) { + dial->setMappedValue(value); + } else { + dial->setValue(ival); + } dial->blockSignals(false); } diff -r 813170c57b13 -r 0895517bb2d1 widgets/PropertyBox.cpp --- a/widgets/PropertyBox.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/PropertyBox.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -642,8 +642,8 @@ if (!newColour.isValid()) return; ColourNameDialog dialog(tr("Name New Colour"), - tr("Enter name for the new colour:"), - newColour, "", this); + tr("Enter a name for the new colour:"), + newColour, newColour.name(), this); dialog.showDarkBackgroundCheckbox(tr("Prefer black background for this colour")); if (dialog.exec() == QDialog::Accepted) { //!!! command diff -r 813170c57b13 -r 0895517bb2d1 widgets/PropertyStack.cpp --- a/widgets/PropertyStack.cpp Thu Nov 29 10:43:54 2007 +0000 +++ b/widgets/PropertyStack.cpp Wed Feb 27 10:32:45 2008 +0000 @@ -114,17 +114,6 @@ shortName = QString("&%1 %2").arg(i + 1).arg(shortName); -#ifdef Q_WS_MAC - - // Qt 4.2 on OS/X doesn't show the icons in the tab bar, and - // I'm not sure why -- use labels instead - - addTab(box, shortName); - -#else - - // Icons on other platforms - QString iconName = container->getPropertyContainerIconName(); QIcon icon(IconLoader().load(iconName)); @@ -135,8 +124,6 @@ setTabToolTip(i, name); } -#endif - m_boxes.push_back(box); }