annotate layer/Layer.cpp @ 1588:0f36e0eca6b0

Add right-button context menu to panner widget
author Chris Cannam
date Mon, 30 Mar 2020 11:29:16 +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