annotate layer/Layer.cpp @ 1127:9fb8dfd7ce4c spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents 4fe7a09be0fe
children a34a2a25907c
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@908 55 this, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)));
Chris@320 56
Chris@320 57 connect(model, SIGNAL(completionChanged()),
Chris@320 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@127 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@127 88
Chris@127 89 QString text;
Chris@127 90 if (modelName != "") {
Chris@127 91 text = QString("%1: %2").arg(modelName).arg(layerName);
Chris@127 92 } else {
Chris@127 93 text = layerName;
Chris@127 94 }
Chris@127 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@127 112 return PlayParameterRepository::getInstance()->getPlayParameters(model);
Chris@127 113 }
Chris@127 114 return 0;
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@587 172 SVDEBUG << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << 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@587 184 SVDEBUG << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << 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@360 235 for (Clipboard::PointList::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@360 255 if (i->haveReferenceFrame()) {
Chris@360 256 referenceFrame = i->getReferenceFrame();
Chris@360 257 }
Chris@905 258 sv_frame_t myMappedFrame = alignToReference(v, sourceFrame);
Chris@360 259
Chris@682 260 // cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), 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@283 376 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 377 QRect(e->x(), e->y(), 0, 0));
Chris@267 378 m_haveDraggingRect = true;
Chris@267 379 }
Chris@267 380
Chris@267 381 void
Chris@918 382 Layer::measureDrag(LayerGeometryProvider *v, QMouseEvent *e)
Chris@267 383 {
Chris@267 384 if (!m_haveDraggingRect) return;
Chris@268 385
Chris@283 386 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 387 QRect(m_draggingRect.pixrect.x(),
Chris@283 388 m_draggingRect.pixrect.y(),
Chris@283 389 e->x() - m_draggingRect.pixrect.x(),
Chris@283 390 e->y() - m_draggingRect.pixrect.y()));
Chris@267 391 }
Chris@267 392
Chris@267 393 void
Chris@918 394 Layer::measureEnd(LayerGeometryProvider *v, QMouseEvent *e)
Chris@267 395 {
Chris@267 396 if (!m_haveDraggingRect) return;
Chris@267 397 measureDrag(v, e);
Chris@283 398
Chris@283 399 if (!m_draggingRect.pixrect.isNull()) {
Chris@283 400 CommandHistory::getInstance()->addCommand
Chris@283 401 (new AddMeasurementRectCommand(this, m_draggingRect));
Chris@283 402 }
Chris@268 403
Chris@267 404 m_haveDraggingRect = false;
Chris@267 405 }
Chris@267 406
Chris@267 407 void
Chris@918 408 Layer::measureDoubleClick(LayerGeometryProvider *, QMouseEvent *)
Chris@280 409 {
Chris@283 410 // nothing, in the base class
Chris@283 411 }
Chris@283 412
Chris@283 413 void
Chris@283 414 Layer::deleteCurrentMeasureRect()
Chris@283 415 {
Chris@283 416 if (!m_haveCurrentMeasureRect) return;
Chris@283 417
Chris@283 418 MeasureRectSet::const_iterator focusRectItr =
Chris@283 419 findFocusedMeasureRect(m_currentMeasureRectPoint);
Chris@283 420
Chris@283 421 if (focusRectItr == m_measureRects.end()) return;
Chris@283 422
Chris@283 423 CommandHistory::getInstance()->addCommand
Chris@283 424 (new DeleteMeasurementRectCommand(this, *focusRectItr));
Chris@280 425 }
Chris@280 426
Chris@280 427 void
Chris@918 428 Layer::paintMeasurementRects(LayerGeometryProvider *v, QPainter &paint,
Chris@272 429 bool showFocus, QPoint focusPoint) const
Chris@267 430 {
Chris@273 431 updateMeasurePixrects(v);
Chris@272 432
Chris@272 433 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 434
Chris@267 435 if (m_haveDraggingRect) {
Chris@272 436
Chris@270 437 paintMeasurementRect(v, paint, m_draggingRect, true);
Chris@272 438
Chris@272 439 } else if (showFocus) {
Chris@272 440
Chris@272 441 focusRectItr = findFocusedMeasureRect(focusPoint);
Chris@267 442 }
Chris@267 443
Chris@283 444 m_haveCurrentMeasureRect = false;
Chris@283 445
Chris@268 446 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@268 447 i != m_measureRects.end(); ++i) {
Chris@283 448
Chris@283 449 bool focused = (i == focusRectItr);
Chris@283 450 paintMeasurementRect(v, paint, *i, focused);
Chris@283 451
Chris@283 452 if (focused) {
Chris@283 453 m_haveCurrentMeasureRect = true;
Chris@283 454 m_currentMeasureRectPoint = focusPoint;
Chris@283 455 }
Chris@267 456 }
Chris@267 457 }
Chris@267 458
Chris@272 459 bool
Chris@918 460 Layer::nearestMeasurementRectChanged(LayerGeometryProvider *v, QPoint prev, QPoint now) const
Chris@272 461 {
Chris@273 462 updateMeasurePixrects(v);
Chris@272 463
Chris@272 464 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
Chris@272 465 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
Chris@272 466
Chris@272 467 return (i0 != i1);
Chris@272 468 }
Chris@272 469
Chris@272 470 void
Chris@918 471 Layer::updateMeasurePixrects(LayerGeometryProvider *v) const
Chris@272 472 {
Chris@905 473 sv_frame_t sf = v->getStartFrame();
Chris@905 474 sv_frame_t ef = v->getEndFrame();
Chris@272 475
Chris@272 476 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 477 i != m_measureRects.end(); ++i) {
Chris@272 478
Chris@273 479 // This logic depends on the fact that if one measure rect in
Chris@273 480 // a layer has frame values, they all will. That is in fact
Chris@273 481 // the case, because haveFrames is based on whether the layer
Chris@273 482 // hasTimeXAxis() or not. Measure rect ordering in the rect
Chris@273 483 // set wouldn't work correctly either, if haveFrames could
Chris@273 484 // vary.
Chris@272 485
Chris@273 486 if (i->haveFrames) {
Chris@273 487 if (i->startFrame >= ef) break;
Chris@273 488 if (i->endFrame <= sf) continue;
Chris@273 489 }
Chris@272 490
Chris@273 491 int x0 = i->pixrect.x();
Chris@273 492 int x1 = x0 + i->pixrect.width();
Chris@273 493
Chris@273 494 if (i->haveFrames) {
Chris@273 495 if (i->startFrame >= v->getStartFrame()) {
Chris@273 496 x0 = v->getXForFrame(i->startFrame);
Chris@273 497 }
Chris@806 498 if (i->endFrame <= int(v->getEndFrame())) {
Chris@273 499 x1 = v->getXForFrame(i->endFrame);
Chris@273 500 }
Chris@272 501 }
Chris@272 502
Chris@273 503 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
Chris@273 504
Chris@273 505 updateMeasureRectYCoords(v, *i);
Chris@273 506 }
Chris@273 507 }
Chris@273 508
Chris@273 509 void
Chris@918 510 Layer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const
Chris@273 511 {
Chris@918 512 int y0 = int(lrint(r.startY * v->getPaintHeight()));
Chris@918 513 int y1 = int(lrint(r.endY * v->getPaintHeight()));
Chris@273 514 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
Chris@273 515 }
Chris@273 516
Chris@273 517 void
Chris@918 518 Layer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const
Chris@273 519 {
Chris@273 520 if (start) {
Chris@918 521 r.startY = double(y) / double(v->getPaintHeight());
Chris@273 522 r.endY = r.startY;
Chris@273 523 } else {
Chris@918 524 r.endY = double(y) / double(v->getPaintHeight());
Chris@272 525 }
Chris@272 526 }
Chris@272 527
Chris@283 528 void
Chris@918 529 Layer::setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const
Chris@283 530 {
Chris@283 531 r.pixrect = pixrect;
Chris@283 532 r.haveFrames = hasTimeXAxis();
Chris@283 533 if (r.haveFrames) {
Chris@283 534 r.startFrame = v->getFrameForX(pixrect.x());
Chris@283 535 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
Chris@283 536 }
Chris@283 537 setMeasureRectYCoord(v, r, true, pixrect.y());
Chris@283 538 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
Chris@283 539 }
Chris@283 540
Chris@272 541 Layer::MeasureRectSet::const_iterator
Chris@272 542 Layer::findFocusedMeasureRect(QPoint focusPoint) const
Chris@272 543 {
Chris@904 544 double frDist = 0;
Chris@272 545 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 546
Chris@272 547 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 548 i != m_measureRects.end(); ++i) {
Chris@272 549
Chris@272 550 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
Chris@272 551
Chris@272 552 int cx = i->pixrect.x() + i->pixrect.width()/2;
Chris@272 553 int cy = i->pixrect.y() + i->pixrect.height()/2;
Chris@272 554 int xd = focusPoint.x() - cx;
Chris@272 555 int yd = focusPoint.y() - cy;
Chris@272 556
Chris@904 557 double d = sqrt(double(xd * xd + yd * yd));
Chris@272 558
Chris@272 559 if (focusRectItr == m_measureRects.end() || d < frDist) {
Chris@272 560 focusRectItr = i;
Chris@272 561 frDist = d;
Chris@272 562 }
Chris@272 563 }
Chris@272 564
Chris@272 565 return focusRectItr;
Chris@272 566 }
Chris@272 567
Chris@268 568 void
Chris@918 569 Layer::paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint,
Chris@270 570 const MeasureRect &r, bool focus) const
Chris@268 571 {
Chris@268 572 if (r.haveFrames) {
Chris@268 573
Chris@268 574 int x0 = -1;
Chris@918 575 int x1 = v->getPaintWidth() + 1;
Chris@268 576
Chris@268 577 if (r.startFrame >= v->getStartFrame()) {
Chris@268 578 x0 = v->getXForFrame(r.startFrame);
Chris@268 579 }
Chris@806 580 if (r.endFrame <= v->getEndFrame()) {
Chris@268 581 x1 = v->getXForFrame(r.endFrame);
Chris@268 582 }
Chris@268 583
Chris@272 584 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
Chris@268 585 r.pixrect = pr;
Chris@268 586 }
Chris@274 587
Chris@274 588 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
Chris@268 589 }
Chris@268 590
Chris@316 591 void
Chris@316 592 Layer::toXml(QTextStream &stream,
Chris@316 593 QString indent, QString extraAttributes) const
Chris@268 594 {
Chris@316 595 stream << indent;
Chris@268 596
Chris@363 597 if (m_presentationName != "") {
Chris@363 598 extraAttributes = QString("%1 presentationName=\"%2\"")
Chris@363 599 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
Chris@363 600 }
Chris@363 601
Chris@316 602 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
Chris@268 603 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@268 604 (LayerFactory::getInstance()->getLayerType(this))))
Chris@268 605 .arg(getObjectExportId(this))
Chris@268 606 .arg(encodeEntities(objectName()))
Chris@268 607 .arg(getObjectExportId(getModel()))
Chris@268 608 .arg(extraAttributes);
Chris@268 609
Chris@269 610 if (m_measureRects.empty()) {
Chris@316 611 stream << QString("/>\n");
Chris@316 612 return;
Chris@269 613 }
Chris@269 614
Chris@316 615 stream << QString(">\n");
Chris@269 616
Chris@269 617 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@269 618 i != m_measureRects.end(); ++i) {
Chris@316 619 i->toXml(stream, indent + " ");
Chris@269 620 }
Chris@269 621
Chris@316 622 stream << QString("</layer>\n");
Chris@268 623 }
Chris@269 624
Chris@316 625 void
Chris@316 626 Layer::toBriefXml(QTextStream &stream,
Chris@316 627 QString indent, QString extraAttributes) const
Chris@269 628 {
Chris@316 629 stream << indent;
Chris@269 630
Chris@363 631 if (m_presentationName != "") {
Chris@363 632 extraAttributes = QString("%1 presentationName=\"%2\"")
Chris@363 633 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
Chris@363 634 }
Chris@363 635
Chris@316 636 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
Chris@269 637 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@269 638 (LayerFactory::getInstance()->getLayerType(this))))
Chris@269 639 .arg(getObjectExportId(this))
Chris@269 640 .arg(encodeEntities(objectName()))
Chris@269 641 .arg(getObjectExportId(getModel()))
Chris@269 642 .arg(extraAttributes);
Chris@269 643 }
Chris@269 644