annotate layer/Layer.cpp @ 283:86a112b5b319

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