annotate layer/Layer.cpp @ 1447:8afea53332f3 single-point

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