Chris@127: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@127: Chris@127: /* Chris@127: Sonic Visualiser Chris@127: An audio file viewer and annotation editor. Chris@127: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@127: Chris@127: This program is free software; you can redistribute it and/or Chris@127: modify it under the terms of the GNU General Public License as Chris@127: published by the Free Software Foundation; either version 2 of the Chris@127: License, or (at your option) any later version. See the file Chris@127: COPYING included with this distribution for more information. Chris@127: */ Chris@127: Chris@127: #include "Layer.h" Chris@128: #include "view/View.h" Chris@128: #include "data/model/Model.h" Chris@268: #include "base/CommandHistory.h" Chris@127: Chris@127: #include Chris@127: Chris@131: #include Chris@267: #include Chris@131: Chris@131: #include "LayerFactory.h" Chris@128: #include "base/PlayParameterRepository.h" Chris@127: Chris@272: #include Chris@272: Chris@267: Layer::Layer() : Chris@267: m_haveDraggingRect(false) Chris@127: { Chris@127: } Chris@127: Chris@127: Layer::~Layer() Chris@127: { Chris@127: // std::cerr << "Layer::~Layer(" << this << ")" << std::endl; Chris@127: } Chris@127: Chris@127: QString Chris@127: Layer::getPropertyContainerIconName() const Chris@127: { Chris@127: return LayerFactory::getInstance()->getLayerIconName Chris@127: (LayerFactory::getInstance()->getLayerType(this)); Chris@127: } Chris@127: Chris@127: QString Chris@127: Layer::getLayerPresentationName() const Chris@127: { Chris@203: // QString layerName = objectName(); Chris@203: Chris@203: LayerFactory *factory = LayerFactory::getInstance(); Chris@203: QString layerName = factory->getLayerPresentationName Chris@203: (factory->getLayerType(this)); Chris@203: Chris@127: QString modelName; Chris@127: if (getModel()) modelName = getModel()->objectName(); Chris@127: Chris@127: QString text; Chris@127: if (modelName != "") { Chris@127: text = QString("%1: %2").arg(modelName).arg(layerName); Chris@127: } else { Chris@127: text = layerName; Chris@127: } Chris@127: Chris@127: return text; Chris@127: } Chris@127: Chris@127: void Chris@127: Layer::setObjectName(const QString &name) Chris@127: { Chris@127: QObject::setObjectName(name); Chris@127: emit layerNameChanged(); Chris@127: } Chris@127: Chris@127: PlayParameters * Chris@127: Layer::getPlayParameters() Chris@127: { Chris@127: // std::cerr << "Layer (" << this << ", " << objectName().toStdString() << ")::getPlayParameters: model is "<< getModel() << std::endl; Chris@127: const Model *model = getModel(); Chris@127: if (model) { Chris@127: return PlayParameterRepository::getInstance()->getPlayParameters(model); Chris@127: } Chris@127: return 0; Chris@127: } Chris@127: Chris@127: void Chris@131: Layer::setLayerDormant(const View *v, bool dormant) Chris@131: { Chris@131: const void *vv = (const void *)v; Chris@131: QMutexLocker locker(&m_dormancyMutex); Chris@131: m_dormancy[vv] = dormant; Chris@131: } Chris@131: Chris@131: bool Chris@131: Layer::isLayerDormant(const View *v) const Chris@131: { Chris@131: const void *vv = (const void *)v; Chris@131: QMutexLocker locker(&m_dormancyMutex); Chris@131: if (m_dormancy.find(vv) == m_dormancy.end()) return false; Chris@131: return m_dormancy.find(vv)->second; Chris@131: } Chris@131: Chris@131: void Chris@127: Layer::showLayer(View *view, bool show) Chris@127: { Chris@127: setLayerDormant(view, !show); Chris@127: emit layerParametersChanged(); Chris@127: } Chris@127: Chris@260: bool Chris@267: Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const Chris@260: { Chris@260: if (!hasTimeXAxis()) return false; Chris@260: Chris@260: const Model *m = getModel(); Chris@260: if (!m) return false; Chris@260: Chris@260: value = float(v->getFrameForX(x)) / m->getSampleRate(); Chris@260: unit = "s"; Chris@260: return true; Chris@260: } Chris@260: Chris@268: bool Chris@274: Layer::getYScaleDifference(const View *v, int y0, int y1, Chris@274: float &diff, QString &unit) const Chris@274: { Chris@274: float v0, v1; Chris@274: if (!getYScaleValue(v, y0, v0, unit) || Chris@274: !getYScaleValue(v, y1, v1, unit)) { Chris@274: diff = 0.f; Chris@274: return false; Chris@274: } Chris@274: diff = fabsf(v1 - v0); Chris@274: return true; Chris@274: } Chris@274: Chris@274: bool Chris@268: Layer::MeasureRect::operator<(const MeasureRect &mr) const Chris@268: { Chris@268: if (haveFrames) { Chris@268: if (startFrame == mr.startFrame) { Chris@268: if (endFrame != mr.endFrame) { Chris@268: return endFrame < mr.endFrame; Chris@268: } Chris@268: } else { Chris@268: return startFrame < mr.startFrame; Chris@268: } Chris@268: } else { Chris@268: if (pixrect.x() == mr.pixrect.x()) { Chris@268: if (pixrect.width() != mr.pixrect.width()) { Chris@268: return pixrect.width() < mr.pixrect.width(); Chris@268: } Chris@268: } else { Chris@268: return pixrect.x() < mr.pixrect.x(); Chris@268: } Chris@268: } Chris@268: Chris@268: // the two rects are equal in x and width Chris@268: Chris@268: if (pixrect.y() == mr.pixrect.y()) { Chris@268: return pixrect.height() < mr.pixrect.height(); Chris@268: } else { Chris@268: return pixrect.y() < mr.pixrect.y(); Chris@268: } Chris@268: } Chris@268: Chris@268: QString Chris@269: Layer::MeasureRect::toXmlString(QString indent) const Chris@269: { Chris@269: QString s; Chris@269: Chris@269: s += indent; Chris@269: s += QString("\n") Chris@273: .arg(startY).arg(endY); Chris@269: Chris@269: return s; Chris@269: } Chris@269: Chris@269: void Chris@269: Layer::addMeasurementRect(const QXmlAttributes &attributes) Chris@269: { Chris@269: MeasureRect rect; Chris@269: QString fs = attributes.value("startFrame"); Chris@273: int x0 = 0, x1 = 0; Chris@269: if (fs != "") { Chris@269: rect.startFrame = fs.toLong(); Chris@269: rect.endFrame = attributes.value("endFrame").toLong(); Chris@269: rect.haveFrames = true; Chris@269: } else { Chris@269: x0 = attributes.value("startX").toInt(); Chris@269: x1 = attributes.value("endX").toInt(); Chris@269: rect.haveFrames = false; Chris@269: } Chris@273: rect.startY = attributes.value("startY").toDouble(); Chris@273: rect.endY = attributes.value("endY").toDouble(); Chris@273: rect.pixrect = QRect(x0, 0, x1 - x0, 0); Chris@269: addMeasureRectToSet(rect); Chris@269: } Chris@269: Chris@269: QString Chris@268: Layer::AddMeasurementRectCommand::getName() const Chris@268: { Chris@268: return tr("Make Measurement"); Chris@268: } Chris@268: Chris@268: void Chris@268: Layer::AddMeasurementRectCommand::execute() Chris@268: { Chris@269: m_layer->addMeasureRectToSet(m_rect); Chris@268: } Chris@268: Chris@268: void Chris@268: Layer::AddMeasurementRectCommand::unexecute() Chris@268: { Chris@269: m_layer->deleteMeasureRectFromSet(m_rect); Chris@268: } Chris@268: Chris@267: void Chris@267: Layer::measureStart(View *v, QMouseEvent *e) Chris@267: { Chris@267: m_draggingRect.pixrect = QRect(e->x(), e->y(), 0, 0); Chris@267: if (hasTimeXAxis()) { Chris@268: m_draggingRect.haveFrames = true; Chris@267: m_draggingRect.startFrame = v->getFrameForX(e->x()); Chris@267: m_draggingRect.endFrame = m_draggingRect.startFrame; Chris@268: } else { Chris@268: m_draggingRect.haveFrames = false; Chris@267: } Chris@273: setMeasureRectYCoord(v, m_draggingRect, true, e->y()); Chris@267: m_haveDraggingRect = true; Chris@267: } Chris@267: Chris@267: void Chris@267: Layer::measureDrag(View *v, QMouseEvent *e) Chris@267: { Chris@267: if (!m_haveDraggingRect) return; Chris@268: Chris@267: m_draggingRect.pixrect = QRect(m_draggingRect.pixrect.x(), Chris@267: m_draggingRect.pixrect.y(), Chris@267: e->x() - m_draggingRect.pixrect.x(), Chris@274: e->y() - m_draggingRect.pixrect.y()); Chris@268: Chris@273: setMeasureRectYCoord(v, m_draggingRect, false, e->y()); Chris@273: Chris@267: if (hasTimeXAxis()) { Chris@267: m_draggingRect.endFrame = v->getFrameForX(e->x()); Chris@267: } Chris@267: } Chris@267: Chris@267: void Chris@267: Layer::measureEnd(View *v, QMouseEvent *e) Chris@267: { Chris@267: if (!m_haveDraggingRect) return; Chris@267: measureDrag(v, e); Chris@268: Chris@268: CommandHistory::getInstance()->addCommand Chris@268: (new AddMeasurementRectCommand(this, m_draggingRect)); Chris@268: Chris@267: m_haveDraggingRect = false; Chris@267: } Chris@267: Chris@267: void Chris@272: Layer::paintMeasurementRects(View *v, QPainter &paint, Chris@272: bool showFocus, QPoint focusPoint) const Chris@267: { Chris@273: updateMeasurePixrects(v); Chris@272: Chris@272: MeasureRectSet::const_iterator focusRectItr = m_measureRects.end(); Chris@272: Chris@267: if (m_haveDraggingRect) { Chris@272: Chris@270: paintMeasurementRect(v, paint, m_draggingRect, true); Chris@272: Chris@272: } else if (showFocus) { Chris@272: Chris@272: focusRectItr = findFocusedMeasureRect(focusPoint); Chris@267: } Chris@267: Chris@268: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@268: i != m_measureRects.end(); ++i) { Chris@272: paintMeasurementRect(v, paint, *i, i == focusRectItr); Chris@267: } Chris@267: } Chris@267: Chris@272: bool Chris@272: Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const Chris@272: { Chris@273: updateMeasurePixrects(v); Chris@272: Chris@272: MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev); Chris@272: MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now); Chris@272: Chris@272: return (i0 != i1); Chris@272: } Chris@272: Chris@272: void Chris@273: Layer::updateMeasurePixrects(View *v) const Chris@272: { Chris@272: long sf = v->getStartFrame(); Chris@272: long ef = v->getEndFrame(); Chris@272: Chris@272: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@272: i != m_measureRects.end(); ++i) { Chris@272: Chris@273: // This logic depends on the fact that if one measure rect in Chris@273: // a layer has frame values, they all will. That is in fact Chris@273: // the case, because haveFrames is based on whether the layer Chris@273: // hasTimeXAxis() or not. Measure rect ordering in the rect Chris@273: // set wouldn't work correctly either, if haveFrames could Chris@273: // vary. Chris@272: Chris@273: if (i->haveFrames) { Chris@273: if (i->startFrame >= ef) break; Chris@273: if (i->endFrame <= sf) continue; Chris@273: } Chris@272: Chris@273: int x0 = i->pixrect.x(); Chris@273: int x1 = x0 + i->pixrect.width(); Chris@273: Chris@273: if (i->haveFrames) { Chris@273: if (i->startFrame >= v->getStartFrame()) { Chris@273: x0 = v->getXForFrame(i->startFrame); Chris@273: } Chris@273: if (i->endFrame <= long(v->getEndFrame())) { Chris@273: x1 = v->getXForFrame(i->endFrame); Chris@273: } Chris@272: } Chris@272: Chris@273: i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height()); Chris@273: Chris@273: updateMeasureRectYCoords(v, *i); Chris@273: } Chris@273: } Chris@273: Chris@273: void Chris@273: Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const Chris@273: { Chris@273: int y0 = lrint(r.startY * v->height()); Chris@273: int y1 = lrint(r.endY * v->height()); Chris@273: r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); Chris@273: } Chris@273: Chris@273: void Chris@273: Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const Chris@273: { Chris@273: if (start) { Chris@273: r.startY = double(y) / double(v->height()); Chris@273: r.endY = r.startY; Chris@273: } else { Chris@273: r.endY = double(y) / double(v->height()); Chris@272: } Chris@272: } Chris@272: Chris@272: Layer::MeasureRectSet::const_iterator Chris@272: Layer::findFocusedMeasureRect(QPoint focusPoint) const Chris@272: { Chris@272: float frDist = 0; Chris@272: MeasureRectSet::const_iterator focusRectItr = m_measureRects.end(); Chris@272: Chris@272: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@272: i != m_measureRects.end(); ++i) { Chris@272: Chris@272: if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue; Chris@272: Chris@272: int cx = i->pixrect.x() + i->pixrect.width()/2; Chris@272: int cy = i->pixrect.y() + i->pixrect.height()/2; Chris@272: int xd = focusPoint.x() - cx; Chris@272: int yd = focusPoint.y() - cy; Chris@272: Chris@272: float d = sqrt(xd * xd + yd * yd); Chris@272: Chris@272: if (focusRectItr == m_measureRects.end() || d < frDist) { Chris@272: focusRectItr = i; Chris@272: frDist = d; Chris@272: } Chris@272: } Chris@272: Chris@272: return focusRectItr; Chris@272: } Chris@272: Chris@268: void Chris@270: Layer::paintMeasurementRect(View *v, QPainter &paint, Chris@270: const MeasureRect &r, bool focus) const Chris@268: { Chris@268: if (r.haveFrames) { Chris@268: Chris@268: int x0 = -1; Chris@268: int x1 = v->width() + 1; Chris@268: Chris@268: if (r.startFrame >= v->getStartFrame()) { Chris@268: x0 = v->getXForFrame(r.startFrame); Chris@268: } Chris@272: if (r.endFrame <= long(v->getEndFrame())) { Chris@268: x1 = v->getXForFrame(r.endFrame); Chris@268: } Chris@268: Chris@272: QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height()); Chris@268: r.pixrect = pr; Chris@268: } Chris@274: Chris@274: v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus); Chris@268: } Chris@268: Chris@268: QString Chris@268: Layer::toXmlString(QString indent, QString extraAttributes) const Chris@268: { Chris@268: QString s; Chris@268: Chris@268: s += indent; Chris@268: Chris@269: s += QString("getLayerTypeName Chris@268: (LayerFactory::getInstance()->getLayerType(this)))) Chris@268: .arg(getObjectExportId(this)) Chris@268: .arg(encodeEntities(objectName())) Chris@268: .arg(getObjectExportId(getModel())) Chris@268: .arg(extraAttributes); Chris@268: Chris@269: if (m_measureRects.empty()) { Chris@269: s += QString("/>\n"); Chris@269: return s; Chris@269: } Chris@269: Chris@269: s += QString(">\n"); Chris@269: Chris@269: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@269: i != m_measureRects.end(); ++i) { Chris@269: s += i->toXmlString(indent + " "); Chris@269: } Chris@269: Chris@269: s += QString("\n"); Chris@269: Chris@268: return s; Chris@268: } Chris@269: Chris@269: QString Chris@269: Layer::toBriefXmlString(QString indent, QString extraAttributes) const Chris@269: { Chris@269: QString s; Chris@269: Chris@269: s += indent; Chris@269: Chris@269: s += QString("\n") Chris@269: .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName Chris@269: (LayerFactory::getInstance()->getLayerType(this)))) Chris@269: .arg(getObjectExportId(this)) Chris@269: .arg(encodeEntities(objectName())) Chris@269: .arg(getObjectExportId(getModel())) Chris@269: .arg(extraAttributes); Chris@269: Chris@269: return s; Chris@269: } Chris@269: