annotate layer/Layer.cpp @ 1548:bd6af89982d7

Permit getScaleProvidingLayerForUnit to return a dormant layer if there is no visible alternative. This is necessary to avoid the scale disappearing in Tony when the spectrogram is toggled off.
author Chris Cannam
date Thu, 17 Oct 2019 14:44:22 +0100
parents 4f8c72adbf43
children 073ef72e8e60
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@376 19 #include "widgets/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@587 45 // SVDEBUG << "Layer::~Layer(" << this << ")" << endl;
Chris@127 46 }
Chris@127 47
Chris@320 48 void
Chris@1469 49 Layer::connectSignals(ModelId modelId)
Chris@320 50 {
Chris@1469 51 auto model = ModelById::get(modelId);
Chris@1469 52 if (!model) return;
Chris@1469 53
Chris@1481 54 connect(model.get(), SIGNAL(modelChanged(ModelId)),
Chris@1481 55 this, SIGNAL(modelChanged(ModelId)));
Chris@320 56
Chris@1481 57 connect(model.get(), SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
Chris@1481 58 this, SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)));
Chris@320 59
Chris@1481 60 connect(model.get(), SIGNAL(completionChanged(ModelId)),
Chris@1481 61 this, SIGNAL(modelCompletionChanged(ModelId)));
Chris@320 62
Chris@1481 63 connect(model.get(), SIGNAL(alignmentCompletionChanged(ModelId)),
Chris@1481 64 this, SIGNAL(modelAlignmentCompletionChanged(ModelId)));
Chris@320 65 }
Chris@320 66
Chris@1489 67 ModelId
Chris@1489 68 Layer::getSourceModel() const
Chris@1489 69 {
Chris@1489 70 ModelId sourceId;
Chris@1489 71 auto model = ModelById::get(getModel());
Chris@1489 72 while (model && !model->getSourceModel().isNone()) {
Chris@1489 73 sourceId = model->getSourceModel();
Chris@1489 74 model = ModelById::get(sourceId);
Chris@1489 75 }
Chris@1489 76 return sourceId;
Chris@1489 77 }
Chris@1489 78
Chris@127 79 QString
Chris@127 80 Layer::getPropertyContainerIconName() const
Chris@127 81 {
Chris@127 82 return LayerFactory::getInstance()->getLayerIconName
Chris@1266 83 (LayerFactory::getInstance()->getLayerType(this));
Chris@127 84 }
Chris@127 85
Chris@363 86 void
Chris@363 87 Layer::setPresentationName(QString name)
Chris@363 88 {
Chris@363 89 m_presentationName = name;
Chris@363 90 }
Chris@363 91
Chris@127 92 QString
Chris@127 93 Layer::getLayerPresentationName() const
Chris@127 94 {
Chris@363 95 if (m_presentationName != "") return m_presentationName;
Chris@203 96
Chris@203 97 LayerFactory *factory = LayerFactory::getInstance();
Chris@203 98 QString layerName = factory->getLayerPresentationName
Chris@203 99 (factory->getLayerType(this));
Chris@203 100
Chris@127 101 QString modelName;
Chris@1469 102 auto model = ModelById::get(getModel());
Chris@1469 103 if (model) modelName = model->objectName();
Chris@1266 104
Chris@127 105 QString text;
Chris@127 106 if (modelName != "") {
Chris@1266 107 text = QString("%1: %2").arg(modelName).arg(layerName);
Chris@127 108 } else {
Chris@1266 109 text = layerName;
Chris@127 110 }
Chris@1266 111
Chris@127 112 return text;
Chris@127 113 }
Chris@127 114
Chris@127 115 void
Chris@127 116 Layer::setObjectName(const QString &name)
Chris@127 117 {
Chris@127 118 QObject::setObjectName(name);
Chris@127 119 emit layerNameChanged();
Chris@127 120 }
Chris@127 121
Chris@1480 122 std::shared_ptr<PlayParameters>
Chris@127 123 Layer::getPlayParameters()
Chris@127 124 {
Chris@1470 125 return PlayParameterRepository::getInstance()->getPlayParameters
Chris@1470 126 (getModel().untyped);
Chris@127 127 }
Chris@127 128
Chris@127 129 void
Chris@918 130 Layer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
Chris@131 131 {
Chris@131 132 const void *vv = (const void *)v;
Chris@131 133 QMutexLocker locker(&m_dormancyMutex);
Chris@131 134 m_dormancy[vv] = dormant;
Chris@131 135 }
Chris@131 136
Chris@131 137 bool
Chris@918 138 Layer::isLayerDormant(const LayerGeometryProvider *v) const
Chris@131 139 {
Chris@131 140 const void *vv = (const void *)v;
Chris@131 141 QMutexLocker locker(&m_dormancyMutex);
Chris@131 142 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
Chris@131 143 return m_dormancy.find(vv)->second;
Chris@131 144 }
Chris@131 145
Chris@131 146 void
Chris@918 147 Layer::showLayer(LayerGeometryProvider *view, bool show)
Chris@127 148 {
Chris@127 149 setLayerDormant(view, !show);
Chris@127 150 emit layerParametersChanged();
Chris@127 151 }
Chris@127 152
Chris@260 153 bool
Chris@918 154 Layer::getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const
Chris@260 155 {
Chris@260 156 if (!hasTimeXAxis()) return false;
Chris@260 157
Chris@1469 158 auto model = ModelById::get(getModel());
Chris@1469 159 if (!model) return false;
Chris@260 160
Chris@1469 161 value = double(v->getFrameForX(x)) / model->getSampleRate();
Chris@260 162 unit = "s";
Chris@260 163 return true;
Chris@260 164 }
Chris@260 165
Chris@268 166 bool
Chris@918 167 Layer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
Chris@904 168 double &diff, QString &unit) const
Chris@274 169 {
Chris@904 170 double v0, v1;
Chris@274 171 if (!getYScaleValue(v, y0, v0, unit) ||
Chris@274 172 !getYScaleValue(v, y1, v1, unit)) {
Chris@274 173 diff = 0.f;
Chris@274 174 return false;
Chris@274 175 }
Chris@904 176 diff = fabs(v1 - v0);
Chris@274 177 return true;
Chris@274 178 }
Chris@274 179
Chris@904 180 sv_frame_t
Chris@918 181 Layer::alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const
Chris@359 182 {
Chris@1469 183 auto model = ModelById::get(getModel());
Chris@1469 184 if (model && !model->getAlignmentReference().isNone()) {
Chris@1469 185 return model->alignToReference(frame);
Chris@359 186 } else {
Chris@918 187 return v->getView()->alignToReference(frame);
Chris@359 188 }
Chris@359 189 }
Chris@359 190
Chris@904 191 sv_frame_t
Chris@918 192 Layer::alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const
Chris@359 193 {
Chris@1469 194 auto model = ModelById::get(getModel());
Chris@1469 195 if (model && !model->getAlignmentReference().isNone()) {
Chris@1469 196 return model->alignFromReference(frame);
Chris@359 197 } else {
Chris@918 198 return v->getView()->alignFromReference(frame);
Chris@359 199 }
Chris@359 200 }
Chris@359 201
Chris@274 202 bool
Chris@918 203 Layer::clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const
Chris@360 204 {
Chris@360 205 // Notes on pasting to an aligned layer:
Chris@360 206 //
Chris@360 207 // Each point may have a reference frame that may differ from the
Chris@360 208 // point's given frame (in its source model). If it has no
Chris@360 209 // reference frame, we have to assume the source model was not
Chris@360 210 // aligned or was the reference model: when cutting or copying
Chris@360 211 // points from a layer, we must always set their reference frame
Chris@360 212 // correctly if we are aligned.
Chris@360 213 //
Chris@360 214 // When pasting:
Chris@360 215 // - if point's reference and aligned frames differ:
Chris@360 216 // - if this layer is aligned:
Chris@360 217 // - if point's aligned frame matches this layer's aligned version
Chris@360 218 // of point's reference frame:
Chris@360 219 // - we can paste at reference frame or our frame
Chris@360 220 // - else
Chris@360 221 // - we can paste at reference frame, result of aligning reference
Chris@360 222 // frame in our model, or literal source frame
Chris@360 223 // - else
Chris@360 224 // - we can paste at reference (our) frame, or literal source frame
Chris@360 225 // - else
Chris@360 226 // - if this layer is aligned:
Chris@360 227 // - we can paste at reference (point's only available) frame,
Chris@360 228 // or result of aligning reference frame in our model
Chris@360 229 // - else
Chris@360 230 // - we can only paste at reference frame
Chris@360 231 //
Chris@360 232 // Which of these alternatives are useful?
Chris@360 233 //
Chris@360 234 // Example: we paste between two tracks that are aligned to the
Chris@360 235 // same reference, and the points are at 10s and 20s in the source
Chris@360 236 // track, corresponding to 5s and 10s in the reference but 20s and
Chris@360 237 // 30s in the target track.
Chris@360 238 //
Chris@360 239 // The obvious default is to paste at 20s and 30s; if we aren't
Chris@360 240 // doing that, would it be better to paste at 5s and 10s or at 10s
Chris@360 241 // and 20s? We probably don't ever want to do the former, do we?
Chris@360 242 // We either want to be literal all the way through, or aligned
Chris@360 243 // all the way through.
Chris@360 244
Chris@1423 245 for (EventVector::const_iterator i = clip.getPoints().begin();
Chris@360 246 i != clip.getPoints().end(); ++i) {
Chris@360 247
Chris@360 248 // In principle, we want to know whether the aligned version
Chris@360 249 // of the reference frame in our layer is the same as the
Chris@360 250 // source frame contained in the clipboard point. However,
Chris@360 251 // because of rounding during alignment, that won't
Chris@360 252 // necessarily be the case even if the clipboard point came
Chris@360 253 // from our layer! What we need to check is whether, if we
Chris@360 254 // aligned the clipboard point's frame back to the reference
Chris@360 255 // using this layer's alignment, we would obtain the same
Chris@360 256 // reference frame as that for the clipboard point.
Chris@360 257
Chris@360 258 // What if the clipboard point has no reference frame? Then
Chris@360 259 // we have to treat it as having its own frame as the
Chris@360 260 // reference (i.e. having been copied from the reference
Chris@360 261 // model).
Chris@360 262
Chris@905 263 sv_frame_t sourceFrame = i->getFrame();
Chris@905 264 sv_frame_t referenceFrame = sourceFrame;
Chris@1423 265 if (i->hasReferenceFrame()) {
Chris@360 266 referenceFrame = i->getReferenceFrame();
Chris@360 267 }
Chris@905 268 sv_frame_t myMappedFrame = alignToReference(v, sourceFrame);
Chris@360 269
Chris@1423 270 // cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->hasReferenceFrame() << "), myMappedFrame = " << myMappedFrame << endl;
Chris@360 271
Chris@360 272 if (myMappedFrame != referenceFrame) return true;
Chris@360 273 }
Chris@360 274
Chris@360 275 return false;
Chris@360 276 }
Chris@360 277
Chris@360 278 bool
Chris@268 279 Layer::MeasureRect::operator<(const MeasureRect &mr) const
Chris@268 280 {
Chris@268 281 if (haveFrames) {
Chris@268 282 if (startFrame == mr.startFrame) {
Chris@268 283 if (endFrame != mr.endFrame) {
Chris@268 284 return endFrame < mr.endFrame;
Chris@268 285 }
Chris@268 286 } else {
Chris@268 287 return startFrame < mr.startFrame;
Chris@268 288 }
Chris@268 289 } else {
Chris@268 290 if (pixrect.x() == mr.pixrect.x()) {
Chris@268 291 if (pixrect.width() != mr.pixrect.width()) {
Chris@268 292 return pixrect.width() < mr.pixrect.width();
Chris@268 293 }
Chris@268 294 } else {
Chris@268 295 return pixrect.x() < mr.pixrect.x();
Chris@268 296 }
Chris@268 297 }
Chris@268 298
Chris@268 299 // the two rects are equal in x and width
Chris@268 300
Chris@268 301 if (pixrect.y() == mr.pixrect.y()) {
Chris@268 302 return pixrect.height() < mr.pixrect.height();
Chris@268 303 } else {
Chris@268 304 return pixrect.y() < mr.pixrect.y();
Chris@268 305 }
Chris@268 306 }
Chris@268 307
Chris@316 308 void
Chris@316 309 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
Chris@269 310 {
Chris@316 311 stream << indent;
Chris@316 312 stream << QString("<measurement ");
Chris@269 313
Chris@269 314 if (haveFrames) {
Chris@316 315 stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
Chris@269 316 .arg(startFrame).arg(endFrame);
Chris@269 317 } else {
Chris@316 318 stream << QString("startX=\"%1\" endX=\"%2\" ")
Chris@316 319 .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
Chris@269 320 }
Chris@269 321
Chris@316 322 stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
Chris@273 323 .arg(startY).arg(endY);
Chris@269 324 }
Chris@269 325
Chris@269 326 void
Chris@269 327 Layer::addMeasurementRect(const QXmlAttributes &attributes)
Chris@269 328 {
Chris@269 329 MeasureRect rect;
Chris@269 330 QString fs = attributes.value("startFrame");
Chris@273 331 int x0 = 0, x1 = 0;
Chris@269 332 if (fs != "") {
Chris@806 333 rect.startFrame = fs.toInt();
Chris@806 334 rect.endFrame = attributes.value("endFrame").toInt();
Chris@269 335 rect.haveFrames = true;
Chris@269 336 } else {
Chris@269 337 x0 = attributes.value("startX").toInt();
Chris@269 338 x1 = attributes.value("endX").toInt();
Chris@269 339 rect.haveFrames = false;
Chris@269 340 }
Chris@273 341 rect.startY = attributes.value("startY").toDouble();
Chris@273 342 rect.endY = attributes.value("endY").toDouble();
Chris@273 343 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
Chris@269 344 addMeasureRectToSet(rect);
Chris@269 345 }
Chris@269 346
Chris@269 347 QString
Chris@268 348 Layer::AddMeasurementRectCommand::getName() const
Chris@268 349 {
Chris@268 350 return tr("Make Measurement");
Chris@268 351 }
Chris@268 352
Chris@268 353 void
Chris@268 354 Layer::AddMeasurementRectCommand::execute()
Chris@268 355 {
Chris@269 356 m_layer->addMeasureRectToSet(m_rect);
Chris@268 357 }
Chris@268 358
Chris@268 359 void
Chris@268 360 Layer::AddMeasurementRectCommand::unexecute()
Chris@268 361 {
Chris@269 362 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@268 363 }
Chris@268 364
Chris@283 365 QString
Chris@283 366 Layer::DeleteMeasurementRectCommand::getName() const
Chris@283 367 {
Chris@283 368 return tr("Delete Measurement");
Chris@283 369 }
Chris@283 370
Chris@283 371 void
Chris@283 372 Layer::DeleteMeasurementRectCommand::execute()
Chris@283 373 {
Chris@283 374 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@283 375 }
Chris@283 376
Chris@283 377 void
Chris@283 378 Layer::DeleteMeasurementRectCommand::unexecute()
Chris@283 379 {
Chris@283 380 m_layer->addMeasureRectToSet(m_rect);
Chris@283 381 }
Chris@283 382
Chris@267 383 void
Chris@918 384 Layer::measureStart(LayerGeometryProvider *v, QMouseEvent *e)
Chris@267 385 {
Chris@1434 386 m_draggingRect.haveFrames = hasTimeXAxis();
Chris@1434 387
Chris@1434 388 // NB if haveFrames, then pixrect x and width will be rewritten on
Chris@1434 389 // every paint according to the current locations of the
Chris@1434 390 // definitive frame values. So we should set the start frame value
Chris@1434 391 // once on measureStart, and then not modify it on drag (to avoid
Chris@1434 392 // drift from repeated conversion back and forth).
Chris@1434 393
Chris@1434 394 m_draggingRect.pixrect = QRect(e->x(), e->y(), 0, 0);
Chris@1434 395
Chris@1434 396 if (m_draggingRect.haveFrames) {
Chris@1434 397 m_draggingRect.startFrame = v->getFrameForX(e->x());
Chris@1434 398 m_draggingRect.endFrame = v->getFrameForX(e->x());
Chris@1434 399 }
Chris@1434 400
Chris@1434 401 setMeasureRectYCoord(v, m_draggingRect, true, e->y());
Chris@1434 402 setMeasureRectYCoord(v, m_draggingRect, false, e->y());
Chris@1434 403
Chris@267 404 m_haveDraggingRect = true;
Chris@267 405 }
Chris@267 406
Chris@267 407 void
Chris@918 408 Layer::measureDrag(LayerGeometryProvider *v, QMouseEvent *e)
Chris@267 409 {
Chris@267 410 if (!m_haveDraggingRect) return;
Chris@268 411
Chris@1434 412 m_draggingRect.pixrect.setHeight(e->y() - m_draggingRect.pixrect.y());
Chris@1434 413
Chris@1434 414 if (m_draggingRect.haveFrames) {
Chris@1434 415 m_draggingRect.endFrame = v->getFrameForX(e->x());
Chris@1434 416 } else {
Chris@1434 417 m_draggingRect.pixrect.setWidth(e->x() - m_draggingRect.pixrect.x());
Chris@1434 418 }
Chris@1434 419
Chris@1434 420 setMeasureRectYCoord(v, m_draggingRect, false, e->y());
Chris@267 421 }
Chris@267 422
Chris@267 423 void
Chris@918 424 Layer::measureEnd(LayerGeometryProvider *v, QMouseEvent *e)
Chris@267 425 {
Chris@267 426 if (!m_haveDraggingRect) return;
Chris@267 427 measureDrag(v, e);
Chris@283 428
Chris@283 429 if (!m_draggingRect.pixrect.isNull()) {
Chris@283 430 CommandHistory::getInstance()->addCommand
Chris@283 431 (new AddMeasurementRectCommand(this, m_draggingRect));
Chris@283 432 }
Chris@268 433
Chris@267 434 m_haveDraggingRect = false;
Chris@267 435 }
Chris@267 436
Chris@267 437 void
Chris@918 438 Layer::measureDoubleClick(LayerGeometryProvider *, QMouseEvent *)
Chris@280 439 {
Chris@283 440 // nothing, in the base class
Chris@283 441 }
Chris@283 442
Chris@283 443 void
Chris@283 444 Layer::deleteCurrentMeasureRect()
Chris@283 445 {
Chris@283 446 if (!m_haveCurrentMeasureRect) return;
Chris@283 447
Chris@283 448 MeasureRectSet::const_iterator focusRectItr =
Chris@283 449 findFocusedMeasureRect(m_currentMeasureRectPoint);
Chris@283 450
Chris@283 451 if (focusRectItr == m_measureRects.end()) return;
Chris@283 452
Chris@283 453 CommandHistory::getInstance()->addCommand
Chris@283 454 (new DeleteMeasurementRectCommand(this, *focusRectItr));
Chris@280 455 }
Chris@280 456
Chris@280 457 void
Chris@918 458 Layer::paintMeasurementRects(LayerGeometryProvider *v, QPainter &paint,
Chris@272 459 bool showFocus, QPoint focusPoint) const
Chris@267 460 {
Chris@273 461 updateMeasurePixrects(v);
Chris@272 462
Chris@272 463 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 464
Chris@267 465 if (m_haveDraggingRect) {
Chris@272 466
Chris@270 467 paintMeasurementRect(v, paint, m_draggingRect, true);
Chris@272 468
Chris@272 469 } else if (showFocus) {
Chris@272 470
Chris@272 471 focusRectItr = findFocusedMeasureRect(focusPoint);
Chris@267 472 }
Chris@267 473
Chris@283 474 m_haveCurrentMeasureRect = false;
Chris@283 475
Chris@268 476 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@268 477 i != m_measureRects.end(); ++i) {
Chris@283 478
Chris@283 479 bool focused = (i == focusRectItr);
Chris@283 480 paintMeasurementRect(v, paint, *i, focused);
Chris@283 481
Chris@283 482 if (focused) {
Chris@283 483 m_haveCurrentMeasureRect = true;
Chris@283 484 m_currentMeasureRectPoint = focusPoint;
Chris@283 485 }
Chris@267 486 }
Chris@267 487 }
Chris@267 488
Chris@272 489 bool
Chris@918 490 Layer::nearestMeasurementRectChanged(LayerGeometryProvider *v, QPoint prev, QPoint now) const
Chris@272 491 {
Chris@273 492 updateMeasurePixrects(v);
Chris@272 493
Chris@272 494 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
Chris@272 495 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
Chris@272 496
Chris@272 497 return (i0 != i1);
Chris@272 498 }
Chris@272 499
Chris@272 500 void
Chris@918 501 Layer::updateMeasurePixrects(LayerGeometryProvider *v) const
Chris@272 502 {
Chris@905 503 sv_frame_t sf = v->getStartFrame();
Chris@905 504 sv_frame_t ef = v->getEndFrame();
Chris@272 505
Chris@272 506 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 507 i != m_measureRects.end(); ++i) {
Chris@272 508
Chris@273 509 // This logic depends on the fact that if one measure rect in
Chris@273 510 // a layer has frame values, they all will. That is in fact
Chris@273 511 // the case, because haveFrames is based on whether the layer
Chris@273 512 // hasTimeXAxis() or not. Measure rect ordering in the rect
Chris@273 513 // set wouldn't work correctly either, if haveFrames could
Chris@273 514 // vary.
Chris@272 515
Chris@273 516 if (i->haveFrames) {
Chris@273 517 if (i->startFrame >= ef) break;
Chris@273 518 if (i->endFrame <= sf) continue;
Chris@273 519 }
Chris@272 520
Chris@273 521 int x0 = i->pixrect.x();
Chris@273 522 int x1 = x0 + i->pixrect.width();
Chris@273 523
Chris@273 524 if (i->haveFrames) {
Chris@273 525 if (i->startFrame >= v->getStartFrame()) {
Chris@273 526 x0 = v->getXForFrame(i->startFrame);
Chris@273 527 }
Chris@806 528 if (i->endFrame <= int(v->getEndFrame())) {
Chris@273 529 x1 = v->getXForFrame(i->endFrame);
Chris@273 530 }
Chris@272 531 }
Chris@272 532
Chris@273 533 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
Chris@273 534
Chris@273 535 updateMeasureRectYCoords(v, *i);
Chris@273 536 }
Chris@273 537 }
Chris@273 538
Chris@273 539 void
Chris@918 540 Layer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const
Chris@273 541 {
Chris@918 542 int y0 = int(lrint(r.startY * v->getPaintHeight()));
Chris@918 543 int y1 = int(lrint(r.endY * v->getPaintHeight()));
Chris@273 544 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
Chris@273 545 }
Chris@273 546
Chris@273 547 void
Chris@918 548 Layer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const
Chris@273 549 {
Chris@273 550 if (start) {
Chris@918 551 r.startY = double(y) / double(v->getPaintHeight());
Chris@273 552 r.endY = r.startY;
Chris@273 553 } else {
Chris@918 554 r.endY = double(y) / double(v->getPaintHeight());
Chris@272 555 }
Chris@272 556 }
Chris@272 557
Chris@283 558 void
Chris@918 559 Layer::setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const
Chris@283 560 {
Chris@283 561 r.pixrect = pixrect;
Chris@283 562 r.haveFrames = hasTimeXAxis();
Chris@283 563 if (r.haveFrames) {
Chris@283 564 r.startFrame = v->getFrameForX(pixrect.x());
Chris@283 565 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
Chris@283 566 }
Chris@283 567 setMeasureRectYCoord(v, r, true, pixrect.y());
Chris@283 568 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
Chris@283 569 }
Chris@283 570
Chris@272 571 Layer::MeasureRectSet::const_iterator
Chris@272 572 Layer::findFocusedMeasureRect(QPoint focusPoint) const
Chris@272 573 {
Chris@904 574 double frDist = 0;
Chris@272 575 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 576
Chris@272 577 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 578 i != m_measureRects.end(); ++i) {
Chris@272 579
Chris@272 580 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
Chris@272 581
Chris@272 582 int cx = i->pixrect.x() + i->pixrect.width()/2;
Chris@272 583 int cy = i->pixrect.y() + i->pixrect.height()/2;
Chris@272 584 int xd = focusPoint.x() - cx;
Chris@272 585 int yd = focusPoint.y() - cy;
Chris@272 586
Chris@904 587 double d = sqrt(double(xd * xd + yd * yd));
Chris@272 588
Chris@272 589 if (focusRectItr == m_measureRects.end() || d < frDist) {
Chris@272 590 focusRectItr = i;
Chris@272 591 frDist = d;
Chris@272 592 }
Chris@272 593 }
Chris@272 594
Chris@272 595 return focusRectItr;
Chris@272 596 }
Chris@272 597
Chris@268 598 void
Chris@918 599 Layer::paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint,
Chris@270 600 const MeasureRect &r, bool focus) const
Chris@268 601 {
Chris@268 602 if (r.haveFrames) {
Chris@268 603
Chris@268 604 int x0 = -1;
Chris@918 605 int x1 = v->getPaintWidth() + 1;
Chris@268 606
Chris@268 607 if (r.startFrame >= v->getStartFrame()) {
Chris@268 608 x0 = v->getXForFrame(r.startFrame);
Chris@268 609 }
Chris@806 610 if (r.endFrame <= v->getEndFrame()) {
Chris@268 611 x1 = v->getXForFrame(r.endFrame);
Chris@268 612 }
Chris@268 613
Chris@272 614 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
Chris@268 615 r.pixrect = pr;
Chris@268 616 }
Chris@274 617
Chris@274 618 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
Chris@268 619 }
Chris@268 620
Chris@1315 621 bool
Chris@1315 622 Layer::valueExtentsMatchMine(LayerGeometryProvider *v) const
Chris@1315 623 {
Chris@1315 624 double min, min_;
Chris@1315 625 double max, max_;
Chris@1315 626 bool logarithmic, logarithmic_;
Chris@1315 627 QString unit;
Chris@1315 628
Chris@1315 629 if (!getValueExtents(min_, max_, logarithmic_, unit)) {
Chris@1315 630 return false;
Chris@1315 631 }
Chris@1315 632
Chris@1537 633 if (!v->getVisibleExtentsForUnit(unit, min, max, logarithmic)) {
Chris@1315 634 return false;
Chris@1315 635 }
Chris@1315 636
Chris@1315 637 if (min != min_ ||
Chris@1315 638 max != max_ ||
Chris@1315 639 logarithmic != logarithmic_) {
Chris@1315 640 return false;
Chris@1315 641 }
Chris@1315 642
Chris@1315 643 return true;
Chris@1315 644 }
Chris@1315 645
Chris@316 646 void
Chris@316 647 Layer::toXml(QTextStream &stream,
Chris@316 648 QString indent, QString extraAttributes) const
Chris@268 649 {
Chris@316 650 stream << indent;
Chris@268 651
Chris@363 652 if (m_presentationName != "") {
Chris@363 653 extraAttributes = QString("%1 presentationName=\"%2\"")
Chris@363 654 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
Chris@363 655 }
Chris@363 656
Chris@1469 657 int modelExportId = -1;
Chris@1469 658 auto model = ModelById::get(getModel());
Chris@1469 659 if (model) modelExportId = model->getExportId();
Chris@1469 660
Chris@316 661 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
Chris@1266 662 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@268 663 (LayerFactory::getInstance()->getLayerType(this))))
Chris@1439 664 .arg(getExportId())
Chris@1266 665 .arg(encodeEntities(objectName()))
Chris@1469 666 .arg(modelExportId)
Chris@1266 667 .arg(extraAttributes);
Chris@268 668
Chris@269 669 if (m_measureRects.empty()) {
Chris@316 670 stream << QString("/>\n");
Chris@316 671 return;
Chris@269 672 }
Chris@269 673
Chris@316 674 stream << QString(">\n");
Chris@269 675
Chris@269 676 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@269 677 i != m_measureRects.end(); ++i) {
Chris@316 678 i->toXml(stream, indent + " ");
Chris@269 679 }
Chris@269 680
Chris@316 681 stream << QString("</layer>\n");
Chris@268 682 }
Chris@269 683
Chris@316 684 void
Chris@316 685 Layer::toBriefXml(QTextStream &stream,
Chris@316 686 QString indent, QString extraAttributes) const
Chris@269 687 {
Chris@316 688 stream << indent;
Chris@269 689
Chris@363 690 if (m_presentationName != "") {
Chris@363 691 extraAttributes = QString("%1 presentationName=\"%2\"")
Chris@363 692 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
Chris@363 693 }
Chris@363 694
Chris@1469 695 int modelExportId = -1;
Chris@1469 696 auto model = ModelById::get(getModel());
Chris@1469 697 if (model) modelExportId = model->getExportId();
Chris@1469 698
Chris@316 699 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
Chris@1266 700 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@269 701 (LayerFactory::getInstance()->getLayerType(this))))
Chris@1439 702 .arg(getExportId())
Chris@1266 703 .arg(encodeEntities(objectName()))
Chris@1469 704 .arg(modelExportId)
Chris@269 705 .arg(extraAttributes);
Chris@269 706 }
Chris@269 707