annotate layer/Layer.cpp @ 326:4f4f38a11cd2

* Factor out uses of "Sonic Visualiser" in "common" code to applicationName() * Add ability to show work title + artist in top-left of pane (thinking of Vect but may be useful in SV in future) * A few other generalisations useful for Vect
author Chris Cannam
date Fri, 09 Nov 2007 17:46:58 +0000
parents 984c1975f1ff
children 020c485aa7e0 0895517bb2d1
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@127 16 #include "Layer.h"
Chris@128 17 #include "view/View.h"
Chris@128 18 #include "data/model/Model.h"
Chris@268 19 #include "base/CommandHistory.h"
Chris@127 20
Chris@127 21 #include <iostream>
Chris@127 22
Chris@131 23 #include <QMutexLocker>
Chris@267 24 #include <QMouseEvent>
Chris@316 25 #include <QTextStream>
Chris@131 26
Chris@326 27 #include <QDomDocument>
Chris@326 28 #include <QDomElement>
Chris@326 29 #include <QDomNamedNodeMap>
Chris@326 30 #include <QDomAttr>
Chris@326 31
Chris@131 32 #include "LayerFactory.h"
Chris@128 33 #include "base/PlayParameterRepository.h"
Chris@127 34
Chris@272 35 #include <cmath>
Chris@272 36
Chris@267 37 Layer::Layer() :
Chris@283 38 m_haveDraggingRect(false),
Chris@283 39 m_haveCurrentMeasureRect(false)
Chris@127 40 {
Chris@127 41 }
Chris@127 42
Chris@127 43 Layer::~Layer()
Chris@127 44 {
Chris@127 45 // std::cerr << "Layer::~Layer(" << this << ")" << std::endl;
Chris@127 46 }
Chris@127 47
Chris@320 48 void
Chris@320 49 Layer::connectSignals(const Model *model)
Chris@320 50 {
Chris@320 51 connect(model, SIGNAL(modelChanged()),
Chris@320 52 this, SIGNAL(modelChanged()));
Chris@320 53
Chris@320 54 connect(model, SIGNAL(modelChanged(size_t, size_t)),
Chris@320 55 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@320 56
Chris@320 57 connect(model, SIGNAL(completionChanged()),
Chris@320 58 this, SIGNAL(modelCompletionChanged()));
Chris@320 59
Chris@320 60 connect(model, SIGNAL(alignmentCompletionChanged()),
Chris@320 61 this, SIGNAL(modelAlignmentCompletionChanged()));
Chris@320 62 }
Chris@320 63
Chris@127 64 QString
Chris@127 65 Layer::getPropertyContainerIconName() const
Chris@127 66 {
Chris@127 67 return LayerFactory::getInstance()->getLayerIconName
Chris@127 68 (LayerFactory::getInstance()->getLayerType(this));
Chris@127 69 }
Chris@127 70
Chris@127 71 QString
Chris@127 72 Layer::getLayerPresentationName() const
Chris@127 73 {
Chris@203 74 // QString layerName = objectName();
Chris@203 75
Chris@203 76 LayerFactory *factory = LayerFactory::getInstance();
Chris@203 77 QString layerName = factory->getLayerPresentationName
Chris@203 78 (factory->getLayerType(this));
Chris@203 79
Chris@127 80 QString modelName;
Chris@127 81 if (getModel()) modelName = getModel()->objectName();
Chris@127 82
Chris@127 83 QString text;
Chris@127 84 if (modelName != "") {
Chris@127 85 text = QString("%1: %2").arg(modelName).arg(layerName);
Chris@127 86 } else {
Chris@127 87 text = layerName;
Chris@127 88 }
Chris@127 89
Chris@127 90 return text;
Chris@127 91 }
Chris@127 92
Chris@127 93 void
Chris@127 94 Layer::setObjectName(const QString &name)
Chris@127 95 {
Chris@127 96 QObject::setObjectName(name);
Chris@127 97 emit layerNameChanged();
Chris@127 98 }
Chris@127 99
Chris@127 100 PlayParameters *
Chris@127 101 Layer::getPlayParameters()
Chris@127 102 {
Chris@127 103 // std::cerr << "Layer (" << this << ", " << objectName().toStdString() << ")::getPlayParameters: model is "<< getModel() << std::endl;
Chris@127 104 const Model *model = getModel();
Chris@127 105 if (model) {
Chris@127 106 return PlayParameterRepository::getInstance()->getPlayParameters(model);
Chris@127 107 }
Chris@127 108 return 0;
Chris@127 109 }
Chris@127 110
Chris@127 111 void
Chris@131 112 Layer::setLayerDormant(const View *v, bool dormant)
Chris@131 113 {
Chris@131 114 const void *vv = (const void *)v;
Chris@131 115 QMutexLocker locker(&m_dormancyMutex);
Chris@131 116 m_dormancy[vv] = dormant;
Chris@131 117 }
Chris@131 118
Chris@131 119 bool
Chris@131 120 Layer::isLayerDormant(const View *v) const
Chris@131 121 {
Chris@131 122 const void *vv = (const void *)v;
Chris@131 123 QMutexLocker locker(&m_dormancyMutex);
Chris@131 124 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
Chris@131 125 return m_dormancy.find(vv)->second;
Chris@131 126 }
Chris@131 127
Chris@131 128 void
Chris@127 129 Layer::showLayer(View *view, bool show)
Chris@127 130 {
Chris@127 131 setLayerDormant(view, !show);
Chris@127 132 emit layerParametersChanged();
Chris@127 133 }
Chris@127 134
Chris@260 135 bool
Chris@267 136 Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
Chris@260 137 {
Chris@260 138 if (!hasTimeXAxis()) return false;
Chris@260 139
Chris@260 140 const Model *m = getModel();
Chris@260 141 if (!m) return false;
Chris@260 142
Chris@260 143 value = float(v->getFrameForX(x)) / m->getSampleRate();
Chris@260 144 unit = "s";
Chris@260 145 return true;
Chris@260 146 }
Chris@260 147
Chris@268 148 bool
Chris@274 149 Layer::getYScaleDifference(const View *v, int y0, int y1,
Chris@274 150 float &diff, QString &unit) const
Chris@274 151 {
Chris@274 152 float v0, v1;
Chris@274 153 if (!getYScaleValue(v, y0, v0, unit) ||
Chris@274 154 !getYScaleValue(v, y1, v1, unit)) {
Chris@274 155 diff = 0.f;
Chris@274 156 return false;
Chris@274 157 }
Chris@274 158 diff = fabsf(v1 - v0);
Chris@274 159 return true;
Chris@274 160 }
Chris@274 161
Chris@274 162 bool
Chris@268 163 Layer::MeasureRect::operator<(const MeasureRect &mr) const
Chris@268 164 {
Chris@268 165 if (haveFrames) {
Chris@268 166 if (startFrame == mr.startFrame) {
Chris@268 167 if (endFrame != mr.endFrame) {
Chris@268 168 return endFrame < mr.endFrame;
Chris@268 169 }
Chris@268 170 } else {
Chris@268 171 return startFrame < mr.startFrame;
Chris@268 172 }
Chris@268 173 } else {
Chris@268 174 if (pixrect.x() == mr.pixrect.x()) {
Chris@268 175 if (pixrect.width() != mr.pixrect.width()) {
Chris@268 176 return pixrect.width() < mr.pixrect.width();
Chris@268 177 }
Chris@268 178 } else {
Chris@268 179 return pixrect.x() < mr.pixrect.x();
Chris@268 180 }
Chris@268 181 }
Chris@268 182
Chris@268 183 // the two rects are equal in x and width
Chris@268 184
Chris@268 185 if (pixrect.y() == mr.pixrect.y()) {
Chris@268 186 return pixrect.height() < mr.pixrect.height();
Chris@268 187 } else {
Chris@268 188 return pixrect.y() < mr.pixrect.y();
Chris@268 189 }
Chris@268 190 }
Chris@268 191
Chris@316 192 void
Chris@316 193 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
Chris@269 194 {
Chris@316 195 stream << indent;
Chris@316 196 stream << QString("<measurement ");
Chris@269 197
Chris@269 198 if (haveFrames) {
Chris@316 199 stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
Chris@269 200 .arg(startFrame).arg(endFrame);
Chris@269 201 } else {
Chris@316 202 stream << QString("startX=\"%1\" endX=\"%2\" ")
Chris@316 203 .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
Chris@269 204 }
Chris@269 205
Chris@316 206 stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
Chris@273 207 .arg(startY).arg(endY);
Chris@269 208 }
Chris@269 209
Chris@269 210 void
Chris@269 211 Layer::addMeasurementRect(const QXmlAttributes &attributes)
Chris@269 212 {
Chris@269 213 MeasureRect rect;
Chris@269 214 QString fs = attributes.value("startFrame");
Chris@273 215 int x0 = 0, x1 = 0;
Chris@269 216 if (fs != "") {
Chris@269 217 rect.startFrame = fs.toLong();
Chris@269 218 rect.endFrame = attributes.value("endFrame").toLong();
Chris@269 219 rect.haveFrames = true;
Chris@269 220 } else {
Chris@269 221 x0 = attributes.value("startX").toInt();
Chris@269 222 x1 = attributes.value("endX").toInt();
Chris@269 223 rect.haveFrames = false;
Chris@269 224 }
Chris@273 225 rect.startY = attributes.value("startY").toDouble();
Chris@273 226 rect.endY = attributes.value("endY").toDouble();
Chris@273 227 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
Chris@269 228 addMeasureRectToSet(rect);
Chris@269 229 }
Chris@269 230
Chris@269 231 QString
Chris@268 232 Layer::AddMeasurementRectCommand::getName() const
Chris@268 233 {
Chris@268 234 return tr("Make Measurement");
Chris@268 235 }
Chris@268 236
Chris@268 237 void
Chris@268 238 Layer::AddMeasurementRectCommand::execute()
Chris@268 239 {
Chris@269 240 m_layer->addMeasureRectToSet(m_rect);
Chris@268 241 }
Chris@268 242
Chris@268 243 void
Chris@268 244 Layer::AddMeasurementRectCommand::unexecute()
Chris@268 245 {
Chris@269 246 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@268 247 }
Chris@268 248
Chris@283 249 QString
Chris@283 250 Layer::DeleteMeasurementRectCommand::getName() const
Chris@283 251 {
Chris@283 252 return tr("Delete Measurement");
Chris@283 253 }
Chris@283 254
Chris@283 255 void
Chris@283 256 Layer::DeleteMeasurementRectCommand::execute()
Chris@283 257 {
Chris@283 258 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@283 259 }
Chris@283 260
Chris@283 261 void
Chris@283 262 Layer::DeleteMeasurementRectCommand::unexecute()
Chris@283 263 {
Chris@283 264 m_layer->addMeasureRectToSet(m_rect);
Chris@283 265 }
Chris@283 266
Chris@267 267 void
Chris@267 268 Layer::measureStart(View *v, QMouseEvent *e)
Chris@267 269 {
Chris@283 270 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 271 QRect(e->x(), e->y(), 0, 0));
Chris@267 272 m_haveDraggingRect = true;
Chris@267 273 }
Chris@267 274
Chris@267 275 void
Chris@267 276 Layer::measureDrag(View *v, QMouseEvent *e)
Chris@267 277 {
Chris@267 278 if (!m_haveDraggingRect) return;
Chris@268 279
Chris@283 280 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 281 QRect(m_draggingRect.pixrect.x(),
Chris@283 282 m_draggingRect.pixrect.y(),
Chris@283 283 e->x() - m_draggingRect.pixrect.x(),
Chris@283 284 e->y() - m_draggingRect.pixrect.y()));
Chris@267 285 }
Chris@267 286
Chris@267 287 void
Chris@267 288 Layer::measureEnd(View *v, QMouseEvent *e)
Chris@267 289 {
Chris@267 290 if (!m_haveDraggingRect) return;
Chris@267 291 measureDrag(v, e);
Chris@283 292
Chris@283 293 if (!m_draggingRect.pixrect.isNull()) {
Chris@283 294 CommandHistory::getInstance()->addCommand
Chris@283 295 (new AddMeasurementRectCommand(this, m_draggingRect));
Chris@283 296 }
Chris@268 297
Chris@267 298 m_haveDraggingRect = false;
Chris@267 299 }
Chris@267 300
Chris@267 301 void
Chris@280 302 Layer::measureDoubleClick(View *v, QMouseEvent *e)
Chris@280 303 {
Chris@283 304 // nothing, in the base class
Chris@283 305 }
Chris@283 306
Chris@283 307 void
Chris@283 308 Layer::deleteCurrentMeasureRect()
Chris@283 309 {
Chris@283 310 if (!m_haveCurrentMeasureRect) return;
Chris@283 311
Chris@283 312 MeasureRectSet::const_iterator focusRectItr =
Chris@283 313 findFocusedMeasureRect(m_currentMeasureRectPoint);
Chris@283 314
Chris@283 315 if (focusRectItr == m_measureRects.end()) return;
Chris@283 316
Chris@283 317 CommandHistory::getInstance()->addCommand
Chris@283 318 (new DeleteMeasurementRectCommand(this, *focusRectItr));
Chris@280 319 }
Chris@280 320
Chris@280 321 void
Chris@272 322 Layer::paintMeasurementRects(View *v, QPainter &paint,
Chris@272 323 bool showFocus, QPoint focusPoint) const
Chris@267 324 {
Chris@273 325 updateMeasurePixrects(v);
Chris@272 326
Chris@272 327 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 328
Chris@267 329 if (m_haveDraggingRect) {
Chris@272 330
Chris@270 331 paintMeasurementRect(v, paint, m_draggingRect, true);
Chris@272 332
Chris@272 333 } else if (showFocus) {
Chris@272 334
Chris@272 335 focusRectItr = findFocusedMeasureRect(focusPoint);
Chris@267 336 }
Chris@267 337
Chris@283 338 m_haveCurrentMeasureRect = false;
Chris@283 339
Chris@268 340 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@268 341 i != m_measureRects.end(); ++i) {
Chris@283 342
Chris@283 343 bool focused = (i == focusRectItr);
Chris@283 344 paintMeasurementRect(v, paint, *i, focused);
Chris@283 345
Chris@283 346 if (focused) {
Chris@283 347 m_haveCurrentMeasureRect = true;
Chris@283 348 m_currentMeasureRectPoint = focusPoint;
Chris@283 349 }
Chris@267 350 }
Chris@267 351 }
Chris@267 352
Chris@272 353 bool
Chris@272 354 Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const
Chris@272 355 {
Chris@273 356 updateMeasurePixrects(v);
Chris@272 357
Chris@272 358 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
Chris@272 359 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
Chris@272 360
Chris@272 361 return (i0 != i1);
Chris@272 362 }
Chris@272 363
Chris@272 364 void
Chris@273 365 Layer::updateMeasurePixrects(View *v) const
Chris@272 366 {
Chris@272 367 long sf = v->getStartFrame();
Chris@272 368 long ef = v->getEndFrame();
Chris@272 369
Chris@272 370 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 371 i != m_measureRects.end(); ++i) {
Chris@272 372
Chris@273 373 // This logic depends on the fact that if one measure rect in
Chris@273 374 // a layer has frame values, they all will. That is in fact
Chris@273 375 // the case, because haveFrames is based on whether the layer
Chris@273 376 // hasTimeXAxis() or not. Measure rect ordering in the rect
Chris@273 377 // set wouldn't work correctly either, if haveFrames could
Chris@273 378 // vary.
Chris@272 379
Chris@273 380 if (i->haveFrames) {
Chris@273 381 if (i->startFrame >= ef) break;
Chris@273 382 if (i->endFrame <= sf) continue;
Chris@273 383 }
Chris@272 384
Chris@273 385 int x0 = i->pixrect.x();
Chris@273 386 int x1 = x0 + i->pixrect.width();
Chris@273 387
Chris@273 388 if (i->haveFrames) {
Chris@273 389 if (i->startFrame >= v->getStartFrame()) {
Chris@273 390 x0 = v->getXForFrame(i->startFrame);
Chris@273 391 }
Chris@273 392 if (i->endFrame <= long(v->getEndFrame())) {
Chris@273 393 x1 = v->getXForFrame(i->endFrame);
Chris@273 394 }
Chris@272 395 }
Chris@272 396
Chris@273 397 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
Chris@273 398
Chris@273 399 updateMeasureRectYCoords(v, *i);
Chris@273 400 }
Chris@273 401 }
Chris@273 402
Chris@273 403 void
Chris@273 404 Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const
Chris@273 405 {
Chris@273 406 int y0 = lrint(r.startY * v->height());
Chris@273 407 int y1 = lrint(r.endY * v->height());
Chris@273 408 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
Chris@273 409 }
Chris@273 410
Chris@273 411 void
Chris@273 412 Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const
Chris@273 413 {
Chris@273 414 if (start) {
Chris@273 415 r.startY = double(y) / double(v->height());
Chris@273 416 r.endY = r.startY;
Chris@273 417 } else {
Chris@273 418 r.endY = double(y) / double(v->height());
Chris@272 419 }
Chris@272 420 }
Chris@272 421
Chris@283 422 void
Chris@283 423 Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const
Chris@283 424 {
Chris@283 425 r.pixrect = pixrect;
Chris@283 426 r.haveFrames = hasTimeXAxis();
Chris@283 427 if (r.haveFrames) {
Chris@283 428 r.startFrame = v->getFrameForX(pixrect.x());
Chris@283 429 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
Chris@283 430 }
Chris@283 431 setMeasureRectYCoord(v, r, true, pixrect.y());
Chris@283 432 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
Chris@283 433 }
Chris@283 434
Chris@272 435 Layer::MeasureRectSet::const_iterator
Chris@272 436 Layer::findFocusedMeasureRect(QPoint focusPoint) const
Chris@272 437 {
Chris@272 438 float frDist = 0;
Chris@272 439 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 440
Chris@272 441 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 442 i != m_measureRects.end(); ++i) {
Chris@272 443
Chris@272 444 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
Chris@272 445
Chris@272 446 int cx = i->pixrect.x() + i->pixrect.width()/2;
Chris@272 447 int cy = i->pixrect.y() + i->pixrect.height()/2;
Chris@272 448 int xd = focusPoint.x() - cx;
Chris@272 449 int yd = focusPoint.y() - cy;
Chris@272 450
Chris@272 451 float d = sqrt(xd * xd + yd * yd);
Chris@272 452
Chris@272 453 if (focusRectItr == m_measureRects.end() || d < frDist) {
Chris@272 454 focusRectItr = i;
Chris@272 455 frDist = d;
Chris@272 456 }
Chris@272 457 }
Chris@272 458
Chris@272 459 return focusRectItr;
Chris@272 460 }
Chris@272 461
Chris@268 462 void
Chris@270 463 Layer::paintMeasurementRect(View *v, QPainter &paint,
Chris@270 464 const MeasureRect &r, bool focus) const
Chris@268 465 {
Chris@268 466 if (r.haveFrames) {
Chris@268 467
Chris@268 468 int x0 = -1;
Chris@268 469 int x1 = v->width() + 1;
Chris@268 470
Chris@268 471 if (r.startFrame >= v->getStartFrame()) {
Chris@268 472 x0 = v->getXForFrame(r.startFrame);
Chris@268 473 }
Chris@272 474 if (r.endFrame <= long(v->getEndFrame())) {
Chris@268 475 x1 = v->getXForFrame(r.endFrame);
Chris@268 476 }
Chris@268 477
Chris@272 478 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
Chris@268 479 r.pixrect = pr;
Chris@268 480 }
Chris@274 481
Chris@274 482 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
Chris@268 483 }
Chris@268 484
Chris@316 485 void
Chris@316 486 Layer::toXml(QTextStream &stream,
Chris@316 487 QString indent, QString extraAttributes) const
Chris@268 488 {
Chris@316 489 stream << indent;
Chris@268 490
Chris@316 491 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
Chris@268 492 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@268 493 (LayerFactory::getInstance()->getLayerType(this))))
Chris@268 494 .arg(getObjectExportId(this))
Chris@268 495 .arg(encodeEntities(objectName()))
Chris@268 496 .arg(getObjectExportId(getModel()))
Chris@268 497 .arg(extraAttributes);
Chris@268 498
Chris@269 499 if (m_measureRects.empty()) {
Chris@316 500 stream << QString("/>\n");
Chris@316 501 return;
Chris@269 502 }
Chris@269 503
Chris@316 504 stream << QString(">\n");
Chris@269 505
Chris@269 506 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@269 507 i != m_measureRects.end(); ++i) {
Chris@316 508 i->toXml(stream, indent + " ");
Chris@269 509 }
Chris@269 510
Chris@316 511 stream << QString("</layer>\n");
Chris@268 512 }
Chris@269 513
Chris@316 514 void
Chris@316 515 Layer::toBriefXml(QTextStream &stream,
Chris@316 516 QString indent, QString extraAttributes) const
Chris@269 517 {
Chris@316 518 stream << indent;
Chris@269 519
Chris@316 520 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
Chris@269 521 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@269 522 (LayerFactory::getInstance()->getLayerType(this))))
Chris@269 523 .arg(getObjectExportId(this))
Chris@269 524 .arg(encodeEntities(objectName()))
Chris@269 525 .arg(getObjectExportId(getModel()))
Chris@269 526 .arg(extraAttributes);
Chris@269 527 }
Chris@269 528