annotate layer/Layer.cpp @ 1605:ae2d5f8ff005

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