annotate layer/Layer.cpp @ 320:984c1975f1ff

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