annotate layer/RegionLayer.cpp @ 1403:10e768adaee5

Retain consistent min freq (rather than min bin no) when changing fft parameters in spectrum; scale ffts by window size rather than fft size in case of oversampling, to avoid fading out because of scale factor including zero padding
author Chris Cannam
date Thu, 15 Nov 2018 15:08:08 +0000
parents c39f2d439d59
children c8a6fd3f9dff 24234307c9b2
rev   line source
Chris@411 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@411 2
Chris@411 3 /*
Chris@411 4 Sonic Visualiser
Chris@411 5 An audio file viewer and annotation editor.
Chris@411 6 Centre for Digital Music, Queen Mary, University of London.
Chris@411 7 This file copyright 2006-2008 Chris Cannam and QMUL.
Chris@411 8
Chris@411 9 This program is free software; you can redistribute it and/or
Chris@411 10 modify it under the terms of the GNU General Public License as
Chris@411 11 published by the Free Software Foundation; either version 2 of the
Chris@411 12 License, or (at your option) any later version. See the file
Chris@411 13 COPYING included with this distribution for more information.
Chris@411 14 */
Chris@411 15
Chris@411 16 #include "RegionLayer.h"
Chris@411 17
Chris@411 18 #include "data/model/Model.h"
Chris@411 19 #include "base/RealTime.h"
Chris@411 20 #include "base/Profiler.h"
Chris@411 21 #include "base/LogRange.h"
Chris@1078 22
Chris@411 23 #include "ColourDatabase.h"
Chris@427 24 #include "ColourMapper.h"
Chris@701 25 #include "LinearNumericalScale.h"
Chris@701 26 #include "LogNumericalScale.h"
Chris@701 27 #include "LinearColourScale.h"
Chris@701 28 #include "LogColourScale.h"
Chris@1078 29 #include "PaintAssistant.h"
Chris@701 30
Chris@411 31 #include "view/View.h"
Chris@411 32
Chris@411 33 #include "data/model/RegionModel.h"
Chris@411 34
Chris@411 35 #include "widgets/ItemEditDialog.h"
Chris@701 36 #include "widgets/TextAbbrev.h"
Chris@411 37
Chris@411 38 #include <QPainter>
Chris@411 39 #include <QPainterPath>
Chris@411 40 #include <QMouseEvent>
Chris@411 41 #include <QTextStream>
Chris@411 42 #include <QMessageBox>
Chris@411 43
Chris@411 44 #include <iostream>
Chris@411 45 #include <cmath>
Chris@411 46
Chris@411 47 RegionLayer::RegionLayer() :
Chris@411 48 SingleColourLayer(),
Chris@411 49 m_model(0),
Chris@411 50 m_editing(false),
Chris@846 51 m_dragPointX(0),
Chris@846 52 m_dragPointY(0),
Chris@846 53 m_dragStartX(0),
Chris@846 54 m_dragStartY(0),
Chris@543 55 m_originalPoint(0, 0.0, 0, tr("New Region")),
Chris@543 56 m_editingPoint(0, 0.0, 0, tr("New Region")),
Chris@411 57 m_editingCommand(0),
Chris@433 58 m_verticalScale(EqualSpaced),
Chris@427 59 m_colourMap(0),
Chris@1362 60 m_colourInverted(false),
Chris@412 61 m_plotStyle(PlotLines)
Chris@411 62 {
Chris@411 63
Chris@411 64 }
Chris@411 65
Chris@411 66 void
Chris@411 67 RegionLayer::setModel(RegionModel *model)
Chris@411 68 {
Chris@411 69 if (m_model == model) return;
Chris@411 70 m_model = model;
Chris@411 71
Chris@411 72 connectSignals(m_model);
Chris@411 73
Chris@433 74 connect(m_model, SIGNAL(modelChanged()), this, SLOT(recalcSpacing()));
Chris@433 75 recalcSpacing();
Chris@433 76
Chris@587 77 // SVDEBUG << "RegionLayer::setModel(" << model << ")" << endl;
Chris@411 78
Chris@610 79 if (m_model && m_model->getRDFTypeURI().endsWith("Segment")) {
Chris@610 80 setPlotStyle(PlotSegmentation);
Chris@610 81 }
Chris@610 82 if (m_model && m_model->getRDFTypeURI().endsWith("Change")) {
Chris@610 83 setPlotStyle(PlotSegmentation);
Chris@610 84 }
Chris@610 85
Chris@411 86 emit modelReplaced();
Chris@411 87 }
Chris@411 88
Chris@411 89 Layer::PropertyList
Chris@411 90 RegionLayer::getProperties() const
Chris@411 91 {
Chris@411 92 PropertyList list = SingleColourLayer::getProperties();
Chris@411 93 list.push_back("Vertical Scale");
Chris@411 94 list.push_back("Scale Units");
Chris@412 95 list.push_back("Plot Type");
Chris@411 96 return list;
Chris@411 97 }
Chris@411 98
Chris@411 99 QString
Chris@411 100 RegionLayer::getPropertyLabel(const PropertyName &name) const
Chris@411 101 {
Chris@411 102 if (name == "Vertical Scale") return tr("Vertical Scale");
Chris@411 103 if (name == "Scale Units") return tr("Scale Units");
Chris@412 104 if (name == "Plot Type") return tr("Plot Type");
Chris@411 105 return SingleColourLayer::getPropertyLabel(name);
Chris@411 106 }
Chris@411 107
Chris@411 108 Layer::PropertyType
Chris@411 109 RegionLayer::getPropertyType(const PropertyName &name) const
Chris@411 110 {
Chris@411 111 if (name == "Scale Units") return UnitsProperty;
Chris@411 112 if (name == "Vertical Scale") return ValueProperty;
Chris@412 113 if (name == "Plot Type") return ValueProperty;
Chris@427 114 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty;
Chris@411 115 return SingleColourLayer::getPropertyType(name);
Chris@411 116 }
Chris@411 117
Chris@411 118 QString
Chris@411 119 RegionLayer::getPropertyGroupName(const PropertyName &name) const
Chris@411 120 {
Chris@411 121 if (name == "Vertical Scale" || name == "Scale Units") {
Chris@411 122 return tr("Scale");
Chris@411 123 }
Chris@411 124 return SingleColourLayer::getPropertyGroupName(name);
Chris@411 125 }
Chris@411 126
Chris@411 127 int
Chris@411 128 RegionLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@411 129 int *min, int *max, int *deflt) const
Chris@411 130 {
Chris@411 131 int val = 0;
Chris@411 132
Chris@427 133 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@427 134
Chris@427 135 if (min) *min = 0;
Chris@427 136 if (max) *max = ColourMapper::getColourMapCount() - 1;
Chris@427 137 if (deflt) *deflt = 0;
Chris@427 138
Chris@427 139 val = m_colourMap;
Chris@427 140
Chris@427 141 } else if (name == "Plot Type") {
Chris@1266 142
Chris@1266 143 if (min) *min = 0;
Chris@1266 144 if (max) *max = 1;
Chris@412 145 if (deflt) *deflt = 0;
Chris@1266 146
Chris@1266 147 val = int(m_plotStyle);
Chris@412 148
Chris@412 149 } else if (name == "Vertical Scale") {
Chris@1266 150
Chris@1266 151 if (min) *min = 0;
Chris@1266 152 if (max) *max = 3;
Chris@433 153 if (deflt) *deflt = int(EqualSpaced);
Chris@1266 154
Chris@1266 155 val = int(m_verticalScale);
Chris@411 156
Chris@411 157 } else if (name == "Scale Units") {
Chris@411 158
Chris@411 159 if (deflt) *deflt = 0;
Chris@411 160 if (m_model) {
Chris@411 161 val = UnitDatabase::getInstance()->getUnitId
Chris@701 162 (getScaleUnits());
Chris@411 163 }
Chris@411 164
Chris@411 165 } else {
Chris@411 166
Chris@1266 167 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@411 168 }
Chris@411 169
Chris@411 170 return val;
Chris@411 171 }
Chris@411 172
Chris@411 173 QString
Chris@411 174 RegionLayer::getPropertyValueLabel(const PropertyName &name,
Chris@427 175 int value) const
Chris@411 176 {
Chris@427 177 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@1362 178 return ColourMapper::getColourMapLabel(value);
Chris@427 179 } else if (name == "Plot Type") {
Chris@412 180
Chris@1266 181 switch (value) {
Chris@1266 182 default:
Chris@1266 183 case 0: return tr("Bars");
Chris@1266 184 case 1: return tr("Segmentation");
Chris@1266 185 }
Chris@412 186
Chris@412 187 } else if (name == "Vertical Scale") {
Chris@1266 188 switch (value) {
Chris@1266 189 default:
Chris@1266 190 case 0: return tr("Auto-Align");
Chris@1266 191 case 1: return tr("Equal Spaced");
Chris@1266 192 case 2: return tr("Linear");
Chris@1266 193 case 3: return tr("Log");
Chris@1266 194 }
Chris@411 195 }
Chris@411 196 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@411 197 }
Chris@411 198
Chris@411 199 void
Chris@411 200 RegionLayer::setProperty(const PropertyName &name, int value)
Chris@411 201 {
Chris@427 202 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@427 203 setFillColourMap(value);
Chris@427 204 } else if (name == "Plot Type") {
Chris@1266 205 setPlotStyle(PlotStyle(value));
Chris@412 206 } else if (name == "Vertical Scale") {
Chris@1266 207 setVerticalScale(VerticalScale(value));
Chris@411 208 } else if (name == "Scale Units") {
Chris@411 209 if (m_model) {
Chris@411 210 m_model->setScaleUnits
Chris@411 211 (UnitDatabase::getInstance()->getUnitById(value));
Chris@411 212 emit modelChanged();
Chris@411 213 }
Chris@411 214 } else {
Chris@411 215 return SingleColourLayer::setProperty(name, value);
Chris@411 216 }
Chris@411 217 }
Chris@411 218
Chris@411 219 void
Chris@427 220 RegionLayer::setFillColourMap(int map)
Chris@427 221 {
Chris@427 222 if (m_colourMap == map) return;
Chris@427 223 m_colourMap = map;
Chris@427 224 emit layerParametersChanged();
Chris@427 225 }
Chris@427 226
Chris@427 227 void
Chris@412 228 RegionLayer::setPlotStyle(PlotStyle style)
Chris@412 229 {
Chris@412 230 if (m_plotStyle == style) return;
Chris@427 231 bool colourTypeChanged = (style == PlotSegmentation ||
Chris@427 232 m_plotStyle == PlotSegmentation);
Chris@412 233 m_plotStyle = style;
Chris@427 234 if (colourTypeChanged) {
Chris@427 235 emit layerParameterRangesChanged();
Chris@427 236 }
Chris@412 237 emit layerParametersChanged();
Chris@412 238 }
Chris@412 239
Chris@412 240 void
Chris@411 241 RegionLayer::setVerticalScale(VerticalScale scale)
Chris@411 242 {
Chris@411 243 if (m_verticalScale == scale) return;
Chris@411 244 m_verticalScale = scale;
Chris@411 245 emit layerParametersChanged();
Chris@411 246 }
Chris@411 247
Chris@411 248 bool
Chris@918 249 RegionLayer::isLayerScrollable(const LayerGeometryProvider *v) const
Chris@411 250 {
Chris@411 251 QPoint discard;
Chris@411 252 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@411 253 }
Chris@411 254
Chris@433 255 void
Chris@433 256 RegionLayer::recalcSpacing()
Chris@433 257 {
Chris@433 258 m_spacingMap.clear();
Chris@551 259 m_distributionMap.clear();
Chris@433 260 if (!m_model) return;
Chris@433 261
Chris@587 262 // SVDEBUG << "RegionLayer::recalcSpacing" << endl;
Chris@433 263
Chris@433 264 for (RegionModel::PointList::const_iterator i = m_model->getPoints().begin();
Chris@433 265 i != m_model->getPoints().end(); ++i) {
Chris@551 266 m_distributionMap[i->value]++;
Chris@587 267 // SVDEBUG << "RegionLayer::recalcSpacing: value found: " << i->value << " (now have " << m_distributionMap[i->value] << " of this value)" << endl;
Chris@433 268 }
Chris@433 269
Chris@433 270 int n = 0;
Chris@433 271
Chris@551 272 for (SpacingMap::const_iterator i = m_distributionMap.begin();
Chris@551 273 i != m_distributionMap.end(); ++i) {
Chris@551 274 m_spacingMap[i->first] = n++;
Chris@587 275 // SVDEBUG << "RegionLayer::recalcSpacing: " << i->first << " -> " << m_spacingMap[i->first] << endl;
Chris@433 276 }
Chris@433 277 }
Chris@433 278
Chris@411 279 bool
Chris@905 280 RegionLayer::getValueExtents(double &min, double &max,
Chris@411 281 bool &logarithmic, QString &unit) const
Chris@411 282 {
Chris@411 283 if (!m_model) return false;
Chris@411 284 min = m_model->getValueMinimum();
Chris@411 285 max = m_model->getValueMaximum();
Chris@701 286 unit = getScaleUnits();
Chris@411 287
Chris@411 288 if (m_verticalScale == LogScale) logarithmic = true;
Chris@411 289
Chris@411 290 return true;
Chris@411 291 }
Chris@411 292
Chris@411 293 bool
Chris@905 294 RegionLayer::getDisplayExtents(double &min, double &max) const
Chris@411 295 {
Chris@433 296 if (!m_model ||
Chris@433 297 m_verticalScale == AutoAlignScale ||
Chris@433 298 m_verticalScale == EqualSpaced) return false;
Chris@411 299
Chris@411 300 min = m_model->getValueMinimum();
Chris@411 301 max = m_model->getValueMaximum();
Chris@411 302
Chris@411 303 return true;
Chris@411 304 }
Chris@411 305
Chris@411 306 RegionModel::PointList
Chris@918 307 RegionLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
Chris@411 308 {
Chris@411 309 if (!m_model) return RegionModel::PointList();
Chris@411 310
Chris@989 311 sv_frame_t frame = v->getFrameForX(x);
Chris@411 312
Chris@411 313 RegionModel::PointList onPoints =
Chris@1266 314 m_model->getPoints(frame);
Chris@411 315
Chris@411 316 if (!onPoints.empty()) {
Chris@1266 317 return onPoints;
Chris@411 318 }
Chris@411 319
Chris@411 320 RegionModel::PointList prevPoints =
Chris@1266 321 m_model->getPreviousPoints(frame);
Chris@411 322 RegionModel::PointList nextPoints =
Chris@1266 323 m_model->getNextPoints(frame);
Chris@411 324
Chris@411 325 RegionModel::PointList usePoints = prevPoints;
Chris@411 326
Chris@411 327 if (prevPoints.empty()) {
Chris@1266 328 usePoints = nextPoints;
Chris@411 329 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
Chris@1266 330 !(nextPoints.begin()->frame > v->getEndFrame())) {
Chris@1266 331 usePoints = nextPoints;
Chris@411 332 } else if (long(nextPoints.begin()->frame) - frame <
Chris@1266 333 frame - long(prevPoints.begin()->frame)) {
Chris@1266 334 usePoints = nextPoints;
Chris@411 335 }
Chris@411 336
Chris@411 337 if (!usePoints.empty()) {
Chris@1391 338 int fuzz = ViewManager::scalePixelSize(2);
Chris@1266 339 int px = v->getXForFrame(usePoints.begin()->frame);
Chris@1266 340 if ((px > x && px - x > fuzz) ||
Chris@1266 341 (px < x && x - px > fuzz + 1)) {
Chris@1266 342 usePoints.clear();
Chris@1266 343 }
Chris@411 344 }
Chris@411 345
Chris@411 346 return usePoints;
Chris@411 347 }
Chris@411 348
Chris@550 349 bool
Chris@918 350 RegionLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, RegionModel::Point &p) const
Chris@550 351 {
Chris@550 352 if (!m_model) return false;
Chris@550 353
Chris@989 354 sv_frame_t frame = v->getFrameForX(x);
Chris@550 355
Chris@550 356 RegionModel::PointList onPoints = m_model->getPoints(frame);
Chris@550 357 if (onPoints.empty()) return false;
Chris@550 358
Chris@550 359 int nearestDistance = -1;
Chris@550 360
Chris@550 361 for (RegionModel::PointList::const_iterator i = onPoints.begin();
Chris@550 362 i != onPoints.end(); ++i) {
Chris@550 363
Chris@550 364 int distance = getYForValue(v, (*i).value) - y;
Chris@550 365 if (distance < 0) distance = -distance;
Chris@550 366 if (nearestDistance == -1 || distance < nearestDistance) {
Chris@550 367 nearestDistance = distance;
Chris@550 368 p = *i;
Chris@550 369 }
Chris@550 370 }
Chris@550 371
Chris@550 372 return true;
Chris@550 373 }
Chris@550 374
Chris@411 375 QString
Chris@909 376 RegionLayer::getLabelPreceding(sv_frame_t frame) const
Chris@552 377 {
Chris@552 378 if (!m_model) return "";
Chris@552 379 RegionModel::PointList points = m_model->getPreviousPoints(frame);
Chris@552 380 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@552 381 i != points.end(); ++i) {
Chris@552 382 if (i->label != "") return i->label;
Chris@552 383 }
Chris@552 384 return "";
Chris@552 385 }
Chris@552 386
Chris@552 387 QString
Chris@918 388 RegionLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
Chris@411 389 {
Chris@411 390 int x = pos.x();
Chris@411 391
Chris@411 392 if (!m_model || !m_model->getSampleRate()) return "";
Chris@411 393
Chris@411 394 RegionModel::PointList points = getLocalPoints(v, x);
Chris@411 395
Chris@411 396 if (points.empty()) {
Chris@1266 397 if (!m_model->isReady()) {
Chris@1266 398 return tr("In progress");
Chris@1266 399 } else {
Chris@1266 400 return tr("No local points");
Chris@1266 401 }
Chris@411 402 }
Chris@411 403
Chris@411 404 RegionRec region(0);
Chris@411 405 RegionModel::PointList::iterator i;
Chris@411 406
Chris@413 407 //!!! harmonise with whatever decision is made about point y
Chris@413 408 //!!! coords in paint method
Chris@413 409
Chris@411 410 for (i = points.begin(); i != points.end(); ++i) {
Chris@411 411
Chris@1266 412 int y = getYForValue(v, i->value);
Chris@1266 413 int h = 3;
Chris@411 414
Chris@1266 415 if (m_model->getValueQuantization() != 0.0) {
Chris@1266 416 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
Chris@1266 417 if (h < 3) h = 3;
Chris@1266 418 }
Chris@411 419
Chris@1266 420 if (pos.y() >= y - h && pos.y() <= y) {
Chris@1266 421 region = *i;
Chris@1266 422 break;
Chris@1266 423 }
Chris@411 424 }
Chris@411 425
Chris@411 426 if (i == points.end()) return tr("No local points");
Chris@411 427
Chris@411 428 RealTime rt = RealTime::frame2RealTime(region.frame,
Chris@1266 429 m_model->getSampleRate());
Chris@411 430 RealTime rd = RealTime::frame2RealTime(region.duration,
Chris@1266 431 m_model->getSampleRate());
Chris@411 432
Chris@411 433 QString valueText;
Chris@411 434
Chris@701 435 valueText = tr("%1 %2").arg(region.value).arg(getScaleUnits());
Chris@411 436
Chris@411 437 QString text;
Chris@411 438
Chris@411 439 if (region.label == "") {
Chris@1266 440 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label"))
Chris@1266 441 .arg(rt.toText(true).c_str())
Chris@1266 442 .arg(valueText)
Chris@1266 443 .arg(rd.toText(true).c_str());
Chris@411 444 } else {
Chris@1266 445 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4"))
Chris@1266 446 .arg(rt.toText(true).c_str())
Chris@1266 447 .arg(valueText)
Chris@1266 448 .arg(rd.toText(true).c_str())
Chris@1266 449 .arg(region.label);
Chris@411 450 }
Chris@411 451
Chris@411 452 pos = QPoint(v->getXForFrame(region.frame),
Chris@1266 453 getYForValue(v, region.value));
Chris@411 454 return text;
Chris@411 455 }
Chris@411 456
Chris@411 457 bool
Chris@918 458 RegionLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 459 int &resolution,
Chris@414 460 SnapType snap) const
Chris@411 461 {
Chris@411 462 if (!m_model) {
Chris@1266 463 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@411 464 }
Chris@411 465
Chris@411 466 resolution = m_model->getResolution();
Chris@411 467 RegionModel::PointList points;
Chris@411 468
Chris@411 469 if (snap == SnapNeighbouring) {
Chris@1266 470
Chris@1266 471 points = getLocalPoints(v, v->getXForFrame(frame));
Chris@1266 472 if (points.empty()) return false;
Chris@1266 473 frame = points.begin()->frame;
Chris@1266 474 return true;
Chris@411 475 }
Chris@411 476
Chris@411 477 points = m_model->getPoints(frame, frame);
Chris@905 478 sv_frame_t snapped = frame;
Chris@411 479 bool found = false;
Chris@411 480
Chris@411 481 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@1266 482 i != points.end(); ++i) {
Chris@411 483
Chris@1266 484 if (snap == SnapRight) {
Chris@411 485
Chris@414 486 // The best frame to snap to is the end frame of whichever
Chris@414 487 // feature we would have snapped to the start frame of if
Chris@414 488 // we had been snapping left.
Chris@414 489
Chris@1266 490 if (i->frame <= frame) {
Chris@414 491 if (i->frame + i->duration > frame) {
Chris@414 492 snapped = i->frame + i->duration;
Chris@414 493 found = true; // don't break, as the next may be better
Chris@414 494 }
Chris@414 495 } else {
Chris@414 496 if (!found) {
Chris@414 497 snapped = i->frame;
Chris@414 498 found = true;
Chris@414 499 }
Chris@414 500 break;
Chris@414 501 }
Chris@411 502
Chris@1266 503 } else if (snap == SnapLeft) {
Chris@411 504
Chris@1266 505 if (i->frame <= frame) {
Chris@1266 506 snapped = i->frame;
Chris@1266 507 found = true; // don't break, as the next may be better
Chris@1266 508 } else {
Chris@1266 509 break;
Chris@1266 510 }
Chris@411 511
Chris@1266 512 } else { // nearest
Chris@411 513
Chris@1266 514 RegionModel::PointList::const_iterator j = i;
Chris@1266 515 ++j;
Chris@411 516
Chris@1266 517 if (j == points.end()) {
Chris@411 518
Chris@1266 519 snapped = i->frame;
Chris@1266 520 found = true;
Chris@1266 521 break;
Chris@411 522
Chris@1266 523 } else if (j->frame >= frame) {
Chris@411 524
Chris@1266 525 if (j->frame - frame < frame - i->frame) {
Chris@1266 526 snapped = j->frame;
Chris@1266 527 } else {
Chris@1266 528 snapped = i->frame;
Chris@1266 529 }
Chris@1266 530 found = true;
Chris@1266 531 break;
Chris@1266 532 }
Chris@1266 533 }
Chris@411 534 }
Chris@411 535
Chris@411 536 frame = snapped;
Chris@411 537 return found;
Chris@411 538 }
Chris@411 539
Chris@559 540 bool
Chris@918 541 RegionLayer::snapToSimilarFeature(LayerGeometryProvider *v, sv_frame_t &frame,
Chris@805 542 int &resolution,
Chris@559 543 SnapType snap) const
Chris@559 544 {
Chris@559 545 if (!m_model) {
Chris@1266 546 return Layer::snapToSimilarFeature(v, frame, resolution, snap);
Chris@559 547 }
Chris@559 548
Chris@559 549 resolution = m_model->getResolution();
Chris@559 550
Chris@559 551 const RegionModel::PointList &points = m_model->getPoints();
Chris@559 552 RegionModel::PointList close = m_model->getPoints(frame, frame);
Chris@559 553
Chris@559 554 RegionModel::PointList::const_iterator i;
Chris@559 555
Chris@905 556 sv_frame_t matchframe = frame;
Chris@905 557 double matchvalue = 0.f;
Chris@559 558
Chris@559 559 for (i = close.begin(); i != close.end(); ++i) {
Chris@559 560 if (i->frame > frame) break;
Chris@559 561 matchvalue = i->value;
Chris@559 562 matchframe = i->frame;
Chris@559 563 }
Chris@559 564
Chris@905 565 sv_frame_t snapped = frame;
Chris@559 566 bool found = false;
Chris@559 567 bool distant = false;
Chris@905 568 double epsilon = 0.0001;
Chris@559 569
Chris@559 570 i = close.begin();
Chris@559 571
Chris@559 572 // Scan through the close points first, then the more distant ones
Chris@846 573 // if no suitable close one is found. So the while-termination
Chris@846 574 // condition here can only happen once i has passed through the
Chris@846 575 // whole of the close container and then the whole of the separate
Chris@846 576 // points container. The two iterators are totally distinct, but
Chris@846 577 // have the same type so we cheekily use the same variable and a
Chris@846 578 // single loop for both.
Chris@559 579
Chris@559 580 while (i != points.end()) {
Chris@559 581
Chris@846 582 if (!distant) {
Chris@846 583 if (i == close.end()) {
Chris@846 584 // switch from the close container to the points container
Chris@846 585 i = points.begin();
Chris@846 586 distant = true;
Chris@846 587 }
Chris@559 588 }
Chris@559 589
Chris@1266 590 if (snap == SnapRight) {
Chris@559 591
Chris@1266 592 if (i->frame > matchframe &&
Chris@905 593 fabs(i->value - matchvalue) < epsilon) {
Chris@1266 594 snapped = i->frame;
Chris@1266 595 found = true;
Chris@1266 596 break;
Chris@1266 597 }
Chris@559 598
Chris@1266 599 } else if (snap == SnapLeft) {
Chris@559 600
Chris@1266 601 if (i->frame < matchframe) {
Chris@905 602 if (fabs(i->value - matchvalue) < epsilon) {
Chris@559 603 snapped = i->frame;
Chris@559 604 found = true; // don't break, as the next may be better
Chris@559 605 }
Chris@1266 606 } else if (found || distant) {
Chris@1266 607 break;
Chris@1266 608 }
Chris@559 609
Chris@1266 610 } else {
Chris@559 611 // no other snap types supported
Chris@1266 612 }
Chris@559 613
Chris@559 614 ++i;
Chris@559 615 }
Chris@559 616
Chris@559 617 frame = snapped;
Chris@559 618 return found;
Chris@559 619 }
Chris@559 620
Chris@701 621 QString
Chris@701 622 RegionLayer::getScaleUnits() const
Chris@701 623 {
Chris@701 624 if (m_model) return m_model->getScaleUnits();
Chris@701 625 else return "";
Chris@701 626 }
Chris@701 627
Chris@411 628 void
Chris@918 629 RegionLayer::getScaleExtents(LayerGeometryProvider *v, double &min, double &max, bool &log) const
Chris@411 630 {
Chris@411 631 min = 0.0;
Chris@411 632 max = 0.0;
Chris@411 633 log = false;
Chris@411 634
Chris@411 635 QString queryUnits;
Chris@701 636 queryUnits = getScaleUnits();
Chris@411 637
Chris@411 638 if (m_verticalScale == AutoAlignScale) {
Chris@411 639
Chris@411 640 if (!v->getValueExtents(queryUnits, min, max, log)) {
Chris@411 641
Chris@411 642 min = m_model->getValueMinimum();
Chris@411 643 max = m_model->getValueMaximum();
Chris@411 644
Chris@682 645 // cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
Chris@411 646
Chris@411 647 } else if (log) {
Chris@411 648
Chris@411 649 LogRange::mapRange(min, max);
Chris@411 650
Chris@682 651 // cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << endl;
Chris@411 652
Chris@411 653 }
Chris@411 654
Chris@433 655 } else if (m_verticalScale == EqualSpaced) {
Chris@433 656
Chris@433 657 if (!m_spacingMap.empty()) {
Chris@433 658 SpacingMap::const_iterator i = m_spacingMap.begin();
Chris@433 659 min = i->second;
Chris@433 660 i = m_spacingMap.end();
Chris@433 661 --i;
Chris@433 662 max = i->second;
Chris@682 663 // cerr << "RegionLayer[" << this << "]::getScaleExtents: equal spaced; min = " << min << ", max = " << max << ", log = " << log << endl;
Chris@433 664 }
Chris@433 665
Chris@411 666 } else {
Chris@411 667
Chris@411 668 min = m_model->getValueMinimum();
Chris@411 669 max = m_model->getValueMaximum();
Chris@411 670
Chris@411 671 if (m_verticalScale == LogScale) {
Chris@411 672 LogRange::mapRange(min, max);
Chris@411 673 log = true;
Chris@411 674 }
Chris@411 675 }
Chris@411 676
Chris@411 677 if (max == min) max = min + 1.0;
Chris@411 678 }
Chris@411 679
Chris@411 680 int
Chris@918 681 RegionLayer::spacingIndexToY(LayerGeometryProvider *v, int i) const
Chris@542 682 {
Chris@918 683 int h = v->getPaintHeight();
Chris@905 684 int n = int(m_spacingMap.size());
Chris@542 685 // this maps from i (spacing of the value from the spacing
Chris@542 686 // map) and n (number of region types) to y
Chris@542 687 int y = h - (((h * i) / n) + (h / (2 * n)));
Chris@542 688 return y;
Chris@542 689 }
Chris@542 690
Chris@905 691 double
Chris@918 692 RegionLayer::yToSpacingIndex(LayerGeometryProvider *v, int y) const
Chris@542 693 {
Chris@905 694 // we return an inexact result here (double rather than int)
Chris@918 695 int h = v->getPaintHeight();
Chris@905 696 int n = int(m_spacingMap.size());
Chris@551 697 // from y = h - ((h * i) / n) + (h / (2 * n)) as above (vh taking place of i)
Chris@905 698 double vh = double(2*h*n - h - 2*n*y) / double(2*h);
Chris@542 699 return vh;
Chris@542 700 }
Chris@542 701
Chris@542 702 int
Chris@918 703 RegionLayer::getYForValue(LayerGeometryProvider *v, double val) const
Chris@411 704 {
Chris@905 705 double min = 0.0, max = 0.0;
Chris@411 706 bool logarithmic = false;
Chris@918 707 int h = v->getPaintHeight();
Chris@411 708
Chris@433 709 if (m_verticalScale == EqualSpaced) {
Chris@433 710
Chris@433 711 if (m_spacingMap.empty()) return h/2;
Chris@433 712
Chris@433 713 SpacingMap::const_iterator i = m_spacingMap.lower_bound(val);
Chris@433 714 //!!! what now, if i->first != v?
Chris@433 715
Chris@542 716 int y = spacingIndexToY(v, i->second);
Chris@433 717
Chris@587 718 // SVDEBUG << "RegionLayer::getYForValue: value " << val << " -> i->second " << i->second << " -> y " << y << endl;
Chris@542 719 return y;
Chris@433 720
Chris@433 721
Chris@433 722 } else {
Chris@433 723
Chris@433 724 getScaleExtents(v, min, max, logarithmic);
Chris@411 725
Chris@682 726 // cerr << "RegionLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << endl;
Chris@682 727 // cerr << "h = " << h << ", margin = " << margin << endl;
Chris@411 728
Chris@433 729 if (logarithmic) {
Chris@433 730 val = LogRange::map(val);
Chris@433 731 }
Chris@433 732
Chris@433 733 return int(h - ((val - min) * h) / (max - min));
Chris@411 734 }
Chris@411 735 }
Chris@411 736
Chris@905 737 double
Chris@918 738 RegionLayer::getValueForY(LayerGeometryProvider *v, int y) const
Chris@701 739 {
Chris@701 740 return getValueForY(v, y, -1);
Chris@701 741 }
Chris@701 742
Chris@905 743 double
Chris@918 744 RegionLayer::getValueForY(LayerGeometryProvider *v, int y, int avoid) const
Chris@542 745 {
Chris@905 746 double min = 0.0, max = 0.0;
Chris@542 747 bool logarithmic = false;
Chris@918 748 int h = v->getPaintHeight();
Chris@542 749
Chris@542 750 if (m_verticalScale == EqualSpaced) {
Chris@542 751
Chris@542 752 // if we're equal spaced, we probably want to snap to the
Chris@542 753 // nearest item when close to it, and give some notification
Chris@542 754 // that we're doing so
Chris@542 755
Chris@542 756 if (m_spacingMap.empty()) return 1.f;
Chris@542 757
Chris@542 758 // n is the number of distinct regions. if we are close to
Chris@542 759 // one of the m/n divisions in the y scale, we should snap to
Chris@542 760 // the value of the mth region.
Chris@542 761
Chris@905 762 double vh = yToSpacingIndex(v, y);
Chris@542 763
Chris@542 764 // spacings in the map are integral, so find the closest one,
Chris@542 765 // map it back to its y coordinate, and see how far we are
Chris@542 766 // from it
Chris@542 767
Chris@905 768 int n = int(m_spacingMap.size());
Chris@905 769 int ivh = int(lrint(vh));
Chris@542 770 if (ivh < 0) ivh = 0;
Chris@542 771 if (ivh > n-1) ivh = n-1;
Chris@542 772 int iy = spacingIndexToY(v, ivh);
Chris@542 773
Chris@542 774 int dist = iy - y;
Chris@542 775 int gap = h / n; // between region lines
Chris@542 776
Chris@682 777 // cerr << "getValueForY: y = " << y << ", vh = " << vh << ", ivh = " << ivh << " of " << n << ", iy = " << iy << ", dist = " << dist << ", gap = " << gap << endl;
Chris@542 778
Chris@542 779 SpacingMap::const_iterator i = m_spacingMap.begin();
Chris@542 780 while (i != m_spacingMap.end()) {
Chris@542 781 if (i->second == ivh) break;
Chris@542 782 ++i;
Chris@542 783 }
Chris@542 784 if (i == m_spacingMap.end()) i = m_spacingMap.begin();
Chris@542 785
Chris@682 786 // cerr << "nearest existing value = " << i->first << " at " << iy << endl;
Chris@551 787
Chris@905 788 double val = 0;
Chris@542 789
Chris@682 790 // cerr << "note: avoid = " << avoid << ", i->second = " << i->second << endl;
Chris@551 791
Chris@551 792 if (dist < -gap/3 &&
Chris@551 793 ((avoid == -1) ||
Chris@551 794 (avoid != i->second && avoid != i->second - 1))) {
Chris@542 795 // bisect gap to prior
Chris@542 796 if (i == m_spacingMap.begin()) {
Chris@542 797 val = i->first - 1.f;
Chris@682 798 // cerr << "extended down to " << val << endl;
Chris@542 799 } else {
Chris@542 800 SpacingMap::const_iterator j = i;
Chris@542 801 --j;
Chris@542 802 val = (i->first + j->first) / 2;
Chris@682 803 // cerr << "bisected down to " << val << endl;
Chris@542 804 }
Chris@551 805 } else if (dist > gap/3 &&
Chris@551 806 ((avoid == -1) ||
Chris@551 807 (avoid != i->second && avoid != i->second + 1))) {
Chris@542 808 // bisect gap to following
Chris@542 809 SpacingMap::const_iterator j = i;
Chris@542 810 ++j;
Chris@542 811 if (j == m_spacingMap.end()) {
Chris@542 812 val = i->first + 1.f;
Chris@682 813 // cerr << "extended up to " << val << endl;
Chris@542 814 } else {
Chris@542 815 val = (i->first + j->first) / 2;
Chris@682 816 // cerr << "bisected up to " << val << endl;
Chris@542 817 }
Chris@551 818 } else {
Chris@551 819 // snap
Chris@551 820 val = i->first;
Chris@682 821 // cerr << "snapped to " << val << endl;
Chris@542 822 }
Chris@542 823
Chris@542 824 return val;
Chris@542 825
Chris@542 826 } else {
Chris@542 827
Chris@542 828 getScaleExtents(v, min, max, logarithmic);
Chris@542 829
Chris@905 830 double val = min + (double(h - y) * double(max - min)) / h;
Chris@542 831
Chris@542 832 if (logarithmic) {
Chris@905 833 val = pow(10.0, val);
Chris@542 834 }
Chris@542 835
Chris@542 836 return val;
Chris@542 837 }
Chris@542 838 }
Chris@542 839
Chris@427 840 QColor
Chris@918 841 RegionLayer::getColourForValue(LayerGeometryProvider *v, double val) const
Chris@427 842 {
Chris@905 843 double min, max;
Chris@427 844 bool log;
Chris@427 845 getScaleExtents(v, min, max, log);
Chris@427 846
Chris@427 847 if (min > max) std::swap(min, max);
Chris@427 848 if (max == min) max = min + 1;
Chris@427 849
Chris@427 850 if (log) {
Chris@427 851 LogRange::mapRange(min, max);
Chris@427 852 val = LogRange::map(val);
Chris@427 853 }
Chris@427 854
Chris@587 855 // SVDEBUG << "RegionLayer::getColourForValue: min " << min << ", max "
Chris@585 856 // << max << ", log " << log << ", value " << val << endl;
Chris@427 857
Chris@1362 858 QColor solid = ColourMapper(m_colourMap, m_colourInverted, min, max).map(val);
Chris@427 859 return QColor(solid.red(), solid.green(), solid.blue(), 120);
Chris@427 860 }
Chris@427 861
Chris@427 862 int
Chris@427 863 RegionLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@427 864 {
Chris@427 865 impose = false;
Chris@427 866 return ColourDatabase::getInstance()->getColourIndex
Chris@427 867 (QString(darkbg ? "Bright Blue" : "Blue"));
Chris@427 868 }
Chris@427 869
Chris@411 870 void
Chris@916 871 RegionLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
Chris@411 872 {
Chris@411 873 if (!m_model || !m_model->isOK()) return;
Chris@411 874
Chris@905 875 sv_samplerate_t sampleRate = m_model->getSampleRate();
Chris@411 876 if (!sampleRate) return;
Chris@411 877
Chris@411 878 // Profiler profiler("RegionLayer::paint", true);
Chris@411 879
Chris@552 880 int x0 = rect.left() - 40, x1 = rect.right();
Chris@905 881 sv_frame_t frame0 = v->getFrameForX(x0);
Chris@905 882 sv_frame_t frame1 = v->getFrameForX(x1);
Chris@411 883
Chris@411 884 RegionModel::PointList points(m_model->getPoints(frame0, frame1));
Chris@411 885 if (points.empty()) return;
Chris@411 886
Chris@411 887 paint.setPen(getBaseQColor());
Chris@411 888
Chris@411 889 QColor brushColour(getBaseQColor());
Chris@411 890 brushColour.setAlpha(80);
Chris@411 891
Chris@587 892 // SVDEBUG << "RegionLayer::paint: resolution is "
Chris@1266 893 // << m_model->getResolution() << " frames" << endl;
Chris@411 894
Chris@905 895 double min = m_model->getValueMinimum();
Chris@905 896 double max = m_model->getValueMaximum();
Chris@411 897 if (max == min) max = min + 1.0;
Chris@411 898
Chris@411 899 QPoint localPos;
Chris@551 900 RegionModel::Point illuminatePoint(0);
Chris@551 901 bool shouldIlluminate = false;
Chris@411 902
Chris@411 903 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@551 904 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
Chris@551 905 illuminatePoint);
Chris@411 906 }
Chris@411 907
Chris@411 908 paint.save();
Chris@411 909 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@411 910
Chris@413 911 //!!! point y coords if model does not haveDistinctValues() should
Chris@413 912 //!!! be assigned to avoid overlaps
Chris@413 913
Chris@413 914 //!!! if it does have distinct values, we should still ensure y
Chris@413 915 //!!! coord is never completely flat on the top or bottom
Chris@413 916
Chris@550 917 int fontHeight = paint.fontMetrics().height();
Chris@550 918
Chris@411 919 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@1266 920 i != points.end(); ++i) {
Chris@411 921
Chris@1266 922 const RegionModel::Point &p(*i);
Chris@411 923
Chris@1266 924 int x = v->getXForFrame(p.frame);
Chris@1266 925 int y = getYForValue(v, p.value);
Chris@1266 926 int w = v->getXForFrame(p.frame + p.duration) - x;
Chris@1266 927 int h = 9;
Chris@1266 928 int ex = x + w;
Chris@427 929
Chris@427 930 RegionModel::PointList::const_iterator j = i;
Chris@1266 931 ++j;
Chris@427 932
Chris@1266 933 if (j != points.end()) {
Chris@1266 934 const RegionModel::Point &q(*j);
Chris@1266 935 int nx = v->getXForFrame(q.frame);
Chris@433 936 if (nx < ex) ex = nx;
Chris@427 937 }
Chris@427 938
Chris@1266 939 if (m_model->getValueQuantization() != 0.0) {
Chris@1266 940 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
Chris@1266 941 if (h < 3) h = 3;
Chris@1266 942 }
Chris@411 943
Chris@1266 944 if (w < 1) w = 1;
Chris@411 945
Chris@1266 946 if (m_plotStyle == PlotSegmentation) {
Chris@918 947 paint.setPen(getForegroundQColor(v->getView()));
Chris@427 948 paint.setBrush(getColourForValue(v, p.value));
Chris@427 949 } else {
Chris@427 950 paint.setPen(getBaseQColor());
Chris@427 951 paint.setBrush(brushColour);
Chris@427 952 }
Chris@427 953
Chris@1266 954 if (m_plotStyle == PlotSegmentation) {
Chris@427 955
Chris@1266 956 if (ex <= x) continue;
Chris@427 957
Chris@551 958 if (!shouldIlluminate ||
Chris@551 959 // "illuminatePoint != p"
Chris@551 960 RegionModel::Point::Comparator()(illuminatePoint, p) ||
Chris@551 961 RegionModel::Point::Comparator()(p, illuminatePoint)) {
Chris@551 962
Chris@918 963 paint.setPen(QPen(getForegroundQColor(v->getView()), 1));
Chris@918 964 paint.drawLine(x, 0, x, v->getPaintHeight());
Chris@551 965 paint.setPen(Qt::NoPen);
Chris@552 966
Chris@552 967 } else {
Chris@918 968 paint.setPen(QPen(getForegroundQColor(v->getView()), 2));
Chris@551 969 }
Chris@427 970
Chris@1266 971 paint.drawRect(x, -1, ex - x, v->getPaintHeight() + 2);
Chris@427 972
Chris@1266 973 } else {
Chris@427 974
Chris@551 975 if (shouldIlluminate &&
Chris@551 976 // "illuminatePoint == p"
Chris@551 977 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
Chris@551 978 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
Chris@551 979
Chris@551 980 paint.setPen(v->getForeground());
Chris@551 981 paint.setBrush(v->getForeground());
Chris@551 982
Chris@701 983 QString vlabel = QString("%1%2").arg(p.value).arg(getScaleUnits());
Chris@1078 984 PaintAssistant::drawVisibleText(v, paint,
Chris@551 985 x - paint.fontMetrics().width(vlabel) - 2,
Chris@551 986 y + paint.fontMetrics().height()/2
Chris@551 987 - paint.fontMetrics().descent(),
Chris@1078 988 vlabel, PaintAssistant::OutlinedText);
Chris@551 989
Chris@551 990 QString hlabel = RealTime::frame2RealTime
Chris@551 991 (p.frame, m_model->getSampleRate()).toText(true).c_str();
Chris@1078 992 PaintAssistant::drawVisibleText(v, paint,
Chris@551 993 x,
Chris@551 994 y - h/2 - paint.fontMetrics().descent() - 2,
Chris@1078 995 hlabel, PaintAssistant::OutlinedText);
Chris@427 996 }
Chris@551 997
Chris@427 998 paint.drawLine(x, y-1, x + w, y-1);
Chris@427 999 paint.drawLine(x, y+1, x + w, y+1);
Chris@427 1000 paint.drawLine(x, y - h/2, x, y + h/2);
Chris@427 1001 paint.drawLine(x+w, y - h/2, x + w, y + h/2);
Chris@427 1002 }
Chris@552 1003 }
Chris@552 1004
Chris@552 1005 int nextLabelMinX = -100;
Chris@552 1006 int lastLabelY = 0;
Chris@552 1007
Chris@552 1008 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@1266 1009 i != points.end(); ++i) {
Chris@552 1010
Chris@1266 1011 const RegionModel::Point &p(*i);
Chris@552 1012
Chris@1266 1013 int x = v->getXForFrame(p.frame);
Chris@1266 1014 int y = getYForValue(v, p.value);
Chris@552 1015
Chris@552 1016 bool illuminated = false;
Chris@552 1017
Chris@1266 1018 if (m_plotStyle != PlotSegmentation) {
Chris@552 1019
Chris@552 1020 if (shouldIlluminate &&
Chris@552 1021 // "illuminatePoint == p"
Chris@552 1022 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
Chris@552 1023 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
Chris@552 1024
Chris@552 1025 illuminated = true;
Chris@552 1026 }
Chris@552 1027 }
Chris@427 1028
Chris@551 1029 if (!illuminated) {
Chris@551 1030 QString label = p.label;
Chris@551 1031 if (label == "") {
Chris@701 1032 label = QString("%1%2").arg(p.value).arg(getScaleUnits());
Chris@551 1033 }
Chris@551 1034
Chris@552 1035 int labelX, labelY;
Chris@552 1036
Chris@551 1037 if (m_plotStyle != PlotSegmentation) {
Chris@552 1038 labelX = x - paint.fontMetrics().width(label) - 2;
Chris@552 1039 labelY = y + paint.fontMetrics().height()/2
Chris@552 1040 - paint.fontMetrics().descent();
Chris@551 1041 } else {
Chris@552 1042 labelX = x + 5;
Chris@552 1043 labelY = v->getTextLabelHeight(this, paint);
Chris@552 1044 if (labelX < nextLabelMinX) {
Chris@918 1045 if (lastLabelY < v->getPaintHeight()/2) {
Chris@552 1046 labelY = lastLabelY + fontHeight;
Chris@552 1047 }
Chris@552 1048 }
Chris@552 1049 lastLabelY = labelY;
Chris@552 1050 nextLabelMinX = labelX + paint.fontMetrics().width(label);
Chris@551 1051 }
Chris@552 1052
Chris@1078 1053 PaintAssistant::drawVisibleText(v, paint, labelX, labelY, label, PaintAssistant::OutlinedText);
Chris@550 1054 }
Chris@411 1055 }
Chris@411 1056
Chris@411 1057 paint.restore();
Chris@411 1058 }
Chris@411 1059
Chris@701 1060 int
Chris@918 1061 RegionLayer::getVerticalScaleWidth(LayerGeometryProvider *v, bool, QPainter &paint) const
Chris@701 1062 {
Chris@701 1063 if (!m_model ||
Chris@701 1064 m_verticalScale == AutoAlignScale ||
Chris@701 1065 m_verticalScale == EqualSpaced) {
Chris@701 1066 return 0;
Chris@701 1067 } else if (m_plotStyle == PlotSegmentation) {
Chris@701 1068 if (m_verticalScale == LogScale) {
Chris@701 1069 return LogColourScale().getWidth(v, paint);
Chris@701 1070 } else {
Chris@701 1071 return LinearColourScale().getWidth(v, paint);
Chris@701 1072 }
Chris@701 1073 } else {
Chris@701 1074 if (m_verticalScale == LogScale) {
Chris@701 1075 return LogNumericalScale().getWidth(v, paint);
Chris@701 1076 } else {
Chris@701 1077 return LinearNumericalScale().getWidth(v, paint);
Chris@701 1078 }
Chris@701 1079 }
Chris@701 1080 }
Chris@701 1081
Chris@701 1082 void
Chris@918 1083 RegionLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const
Chris@701 1084 {
Chris@717 1085 if (!m_model || m_model->getPoints().empty()) return;
Chris@701 1086
Chris@701 1087 QString unit;
Chris@905 1088 double min, max;
Chris@701 1089 bool logarithmic;
Chris@701 1090
Chris@701 1091 int w = getVerticalScaleWidth(v, false, paint);
Chris@701 1092
Chris@701 1093 if (m_plotStyle == PlotSegmentation) {
Chris@701 1094
Chris@701 1095 getValueExtents(min, max, logarithmic, unit);
Chris@701 1096
Chris@701 1097 if (logarithmic) {
Chris@701 1098 LogRange::mapRange(min, max);
Chris@701 1099 LogColourScale().paintVertical(v, this, paint, 0, min, max);
Chris@701 1100 } else {
Chris@701 1101 LinearColourScale().paintVertical(v, this, paint, 0, min, max);
Chris@701 1102 }
Chris@701 1103
Chris@701 1104 } else {
Chris@701 1105
Chris@701 1106 getScaleExtents(v, min, max, logarithmic);
Chris@701 1107
Chris@701 1108 if (logarithmic) {
Chris@701 1109 LogNumericalScale().paintVertical(v, this, paint, 0, min, max);
Chris@701 1110 } else {
Chris@701 1111 LinearNumericalScale().paintVertical(v, this, paint, 0, min, max);
Chris@701 1112 }
Chris@701 1113 }
Chris@701 1114
Chris@701 1115 if (getScaleUnits() != "") {
Chris@701 1116 int mw = w - 5;
Chris@701 1117 paint.drawText(5,
Chris@701 1118 5 + paint.fontMetrics().ascent(),
Chris@701 1119 TextAbbrev::abbreviate(getScaleUnits(),
Chris@701 1120 paint.fontMetrics(),
Chris@701 1121 mw));
Chris@701 1122 }
Chris@701 1123 }
Chris@701 1124
Chris@411 1125 void
Chris@918 1126 RegionLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1127 {
Chris@411 1128 if (!m_model) return;
Chris@411 1129
Chris@989 1130 sv_frame_t frame = v->getFrameForX(e->x());
Chris@411 1131 if (frame < 0) frame = 0;
Chris@411 1132 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 1133
Chris@905 1134 double value = getValueForY(v, e->y());
Chris@411 1135
Chris@905 1136 m_editingPoint = RegionModel::Point(frame, float(value), 0, "");
Chris@411 1137 m_originalPoint = m_editingPoint;
Chris@411 1138
Chris@411 1139 if (m_editingCommand) finish(m_editingCommand);
Chris@411 1140 m_editingCommand = new RegionModel::EditCommand(m_model,
Chris@543 1141 tr("Draw Region"));
Chris@411 1142 m_editingCommand->addPoint(m_editingPoint);
Chris@411 1143
Chris@550 1144 recalcSpacing();
Chris@550 1145
Chris@411 1146 m_editing = true;
Chris@411 1147 }
Chris@411 1148
Chris@411 1149 void
Chris@918 1150 RegionLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1151 {
Chris@411 1152 if (!m_model || !m_editing) return;
Chris@411 1153
Chris@905 1154 sv_frame_t frame = v->getFrameForX(e->x());
Chris@411 1155 if (frame < 0) frame = 0;
Chris@411 1156 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 1157
Chris@905 1158 double newValue = m_editingPoint.value;
Chris@542 1159 if (m_verticalScale != EqualSpaced) newValue = getValueForY(v, e->y());
Chris@411 1160
Chris@905 1161 sv_frame_t newFrame = m_editingPoint.frame;
Chris@905 1162 sv_frame_t newDuration = frame - newFrame;
Chris@411 1163 if (newDuration < 0) {
Chris@411 1164 newFrame = frame;
Chris@411 1165 newDuration = -newDuration;
Chris@411 1166 } else if (newDuration == 0) {
Chris@411 1167 newDuration = 1;
Chris@411 1168 }
Chris@411 1169
Chris@411 1170 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 1171 m_editingPoint.frame = newFrame;
Chris@905 1172 m_editingPoint.value = float(newValue);
Chris@411 1173 m_editingPoint.duration = newDuration;
Chris@411 1174 m_editingCommand->addPoint(m_editingPoint);
Chris@550 1175
Chris@551 1176 recalcSpacing();
Chris@411 1177 }
Chris@411 1178
Chris@411 1179 void
Chris@918 1180 RegionLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *)
Chris@411 1181 {
Chris@411 1182 if (!m_model || !m_editing) return;
Chris@411 1183 finish(m_editingCommand);
Chris@411 1184 m_editingCommand = 0;
Chris@411 1185 m_editing = false;
Chris@550 1186
Chris@550 1187 recalcSpacing();
Chris@411 1188 }
Chris@411 1189
Chris@411 1190 void
Chris@918 1191 RegionLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1192 {
Chris@411 1193 if (!m_model) return;
Chris@411 1194
Chris@550 1195 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
Chris@411 1196
Chris@411 1197 if (m_editingCommand) {
Chris@1266 1198 finish(m_editingCommand);
Chris@1266 1199 m_editingCommand = 0;
Chris@411 1200 }
Chris@411 1201
Chris@411 1202 m_editing = true;
Chris@550 1203 recalcSpacing();
Chris@411 1204 }
Chris@411 1205
Chris@411 1206 void
Chris@918 1207 RegionLayer::eraseDrag(LayerGeometryProvider *, QMouseEvent *)
Chris@411 1208 {
Chris@411 1209 }
Chris@411 1210
Chris@411 1211 void
Chris@918 1212 RegionLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1213 {
Chris@411 1214 if (!m_model || !m_editing) return;
Chris@411 1215
Chris@411 1216 m_editing = false;
Chris@551 1217
Chris@550 1218 RegionModel::Point p(0);
Chris@550 1219 if (!getPointToDrag(v, e->x(), e->y(), p)) return;
Chris@550 1220 if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return;
Chris@411 1221
Chris@411 1222 m_editingCommand = new RegionModel::EditCommand
Chris@543 1223 (m_model, tr("Erase Region"));
Chris@411 1224
Chris@411 1225 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 1226
Chris@411 1227 finish(m_editingCommand);
Chris@411 1228 m_editingCommand = 0;
Chris@411 1229 m_editing = false;
Chris@550 1230 recalcSpacing();
Chris@411 1231 }
Chris@411 1232
Chris@411 1233 void
Chris@918 1234 RegionLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1235 {
Chris@411 1236 if (!m_model) return;
Chris@411 1237
Chris@550 1238 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) {
Chris@550 1239 return;
Chris@550 1240 }
Chris@550 1241
Chris@551 1242 m_dragPointX = v->getXForFrame(m_editingPoint.frame);
Chris@551 1243 m_dragPointY = getYForValue(v, m_editingPoint.value);
Chris@551 1244
Chris@411 1245 m_originalPoint = m_editingPoint;
Chris@411 1246
Chris@411 1247 if (m_editingCommand) {
Chris@1266 1248 finish(m_editingCommand);
Chris@1266 1249 m_editingCommand = 0;
Chris@411 1250 }
Chris@411 1251
Chris@411 1252 m_editing = true;
Chris@551 1253 m_dragStartX = e->x();
Chris@551 1254 m_dragStartY = e->y();
Chris@550 1255 recalcSpacing();
Chris@411 1256 }
Chris@411 1257
Chris@411 1258 void
Chris@918 1259 RegionLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1260 {
Chris@411 1261 if (!m_model || !m_editing) return;
Chris@411 1262
Chris@551 1263 int xdist = e->x() - m_dragStartX;
Chris@551 1264 int ydist = e->y() - m_dragStartY;
Chris@551 1265 int newx = m_dragPointX + xdist;
Chris@551 1266 int newy = m_dragPointY + ydist;
Chris@551 1267
Chris@989 1268 sv_frame_t frame = v->getFrameForX(newx);
Chris@411 1269 if (frame < 0) frame = 0;
Chris@411 1270 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 1271
Chris@551 1272 // Do not bisect between two values, if one of those values is
Chris@551 1273 // that of the point we're actually moving ...
Chris@551 1274 int avoid = m_spacingMap[m_editingPoint.value];
Chris@551 1275
Chris@551 1276 // ... unless there are other points with the same value
Chris@551 1277 if (m_distributionMap[m_editingPoint.value] > 1) avoid = -1;
Chris@551 1278
Chris@905 1279 double value = getValueForY(v, newy, avoid);
Chris@411 1280
Chris@411 1281 if (!m_editingCommand) {
Chris@1266 1282 m_editingCommand = new RegionModel::EditCommand(m_model,
Chris@1266 1283 tr("Drag Region"));
Chris@411 1284 }
Chris@411 1285
Chris@411 1286 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 1287 m_editingPoint.frame = frame;
Chris@905 1288 m_editingPoint.value = float(value);
Chris@411 1289 m_editingCommand->addPoint(m_editingPoint);
Chris@550 1290 recalcSpacing();
Chris@411 1291 }
Chris@411 1292
Chris@411 1293 void
Chris@918 1294 RegionLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
Chris@411 1295 {
Chris@411 1296 if (!m_model || !m_editing) return;
Chris@411 1297
Chris@411 1298 if (m_editingCommand) {
Chris@411 1299
Chris@1266 1300 QString newName = m_editingCommand->getName();
Chris@411 1301
Chris@1266 1302 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@1266 1303 if (m_editingPoint.value != m_originalPoint.value) {
Chris@1266 1304 newName = tr("Edit Region");
Chris@1266 1305 } else {
Chris@1266 1306 newName = tr("Relocate Region");
Chris@1266 1307 }
Chris@1266 1308 } else {
Chris@1266 1309 newName = tr("Change Point Value");
Chris@1266 1310 }
Chris@411 1311
Chris@1266 1312 m_editingCommand->setName(newName);
Chris@1266 1313 finish(m_editingCommand);
Chris@411 1314 }
Chris@411 1315
Chris@411 1316 m_editingCommand = 0;
Chris@411 1317 m_editing = false;
Chris@550 1318 recalcSpacing();
Chris@411 1319 }
Chris@411 1320
Chris@411 1321 bool
Chris@918 1322 RegionLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
Chris@411 1323 {
Chris@411 1324 if (!m_model) return false;
Chris@411 1325
Chris@550 1326 RegionModel::Point region(0);
Chris@550 1327 if (!getPointToDrag(v, e->x(), e->y(), region)) return false;
Chris@550 1328
Chris@411 1329 ItemEditDialog *dialog = new ItemEditDialog
Chris@411 1330 (m_model->getSampleRate(),
Chris@411 1331 ItemEditDialog::ShowTime |
Chris@411 1332 ItemEditDialog::ShowDuration |
Chris@411 1333 ItemEditDialog::ShowValue |
Chris@411 1334 ItemEditDialog::ShowText,
Chris@701 1335 getScaleUnits());
Chris@411 1336
Chris@411 1337 dialog->setFrameTime(region.frame);
Chris@411 1338 dialog->setValue(region.value);
Chris@411 1339 dialog->setFrameDuration(region.duration);
Chris@411 1340 dialog->setText(region.label);
Chris@411 1341
Chris@411 1342 if (dialog->exec() == QDialog::Accepted) {
Chris@411 1343
Chris@411 1344 RegionModel::Point newRegion = region;
Chris@411 1345 newRegion.frame = dialog->getFrameTime();
Chris@411 1346 newRegion.value = dialog->getValue();
Chris@411 1347 newRegion.duration = dialog->getFrameDuration();
Chris@411 1348 newRegion.label = dialog->getText();
Chris@411 1349
Chris@411 1350 RegionModel::EditCommand *command = new RegionModel::EditCommand
Chris@543 1351 (m_model, tr("Edit Region"));
Chris@411 1352 command->deletePoint(region);
Chris@411 1353 command->addPoint(newRegion);
Chris@411 1354 finish(command);
Chris@411 1355 }
Chris@411 1356
Chris@411 1357 delete dialog;
Chris@550 1358 recalcSpacing();
Chris@411 1359 return true;
Chris@411 1360 }
Chris@411 1361
Chris@411 1362 void
Chris@905 1363 RegionLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
Chris@411 1364 {
Chris@411 1365 if (!m_model) return;
Chris@411 1366
Chris@411 1367 RegionModel::EditCommand *command =
Chris@1266 1368 new RegionModel::EditCommand(m_model, tr("Drag Selection"));
Chris@411 1369
Chris@411 1370 RegionModel::PointList points =
Chris@1266 1371 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 1372
Chris@411 1373 for (RegionModel::PointList::iterator i = points.begin();
Chris@1266 1374 i != points.end(); ++i) {
Chris@411 1375
Chris@1266 1376 if (s.contains(i->frame)) {
Chris@1266 1377 RegionModel::Point newPoint(*i);
Chris@1266 1378 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@1266 1379 command->deletePoint(*i);
Chris@1266 1380 command->addPoint(newPoint);
Chris@1266 1381 }
Chris@411 1382 }
Chris@411 1383
Chris@411 1384 finish(command);
Chris@550 1385 recalcSpacing();
Chris@411 1386 }
Chris@411 1387
Chris@411 1388 void
Chris@411 1389 RegionLayer::resizeSelection(Selection s, Selection newSize)
Chris@411 1390 {
Chris@411 1391 if (!m_model) return;
Chris@411 1392
Chris@411 1393 RegionModel::EditCommand *command =
Chris@1266 1394 new RegionModel::EditCommand(m_model, tr("Resize Selection"));
Chris@411 1395
Chris@411 1396 RegionModel::PointList points =
Chris@1266 1397 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 1398
Chris@411 1399 double ratio =
Chris@1266 1400 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@1266 1401 double(s.getEndFrame() - s.getStartFrame());
Chris@411 1402
Chris@411 1403 for (RegionModel::PointList::iterator i = points.begin();
Chris@1266 1404 i != points.end(); ++i) {
Chris@411 1405
Chris@1266 1406 if (s.contains(i->frame)) {
Chris@411 1407
Chris@1266 1408 double targetStart = double(i->frame);
Chris@1266 1409 targetStart = double(newSize.getStartFrame()) +
Chris@1266 1410 targetStart - double(s.getStartFrame()) * ratio;
Chris@411 1411
Chris@1266 1412 double targetEnd = double(i->frame + i->duration);
Chris@1266 1413 targetEnd = double(newSize.getStartFrame()) +
Chris@1266 1414 targetEnd - double(s.getStartFrame()) * ratio;
Chris@411 1415
Chris@1266 1416 RegionModel::Point newPoint(*i);
Chris@1266 1417 newPoint.frame = lrint(targetStart);
Chris@1266 1418 newPoint.duration = lrint(targetEnd - targetStart);
Chris@1266 1419 command->deletePoint(*i);
Chris@1266 1420 command->addPoint(newPoint);
Chris@1266 1421 }
Chris@411 1422 }
Chris@411 1423
Chris@411 1424 finish(command);
Chris@550 1425 recalcSpacing();
Chris@411 1426 }
Chris@411 1427
Chris@411 1428 void
Chris@411 1429 RegionLayer::deleteSelection(Selection s)
Chris@411 1430 {
Chris@411 1431 if (!m_model) return;
Chris@411 1432
Chris@411 1433 RegionModel::EditCommand *command =
Chris@1266 1434 new RegionModel::EditCommand(m_model, tr("Delete Selected Points"));
Chris@411 1435
Chris@411 1436 RegionModel::PointList points =
Chris@1266 1437 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 1438
Chris@411 1439 for (RegionModel::PointList::iterator i = points.begin();
Chris@1266 1440 i != points.end(); ++i) {
Chris@411 1441
Chris@411 1442 if (s.contains(i->frame)) {
Chris@411 1443 command->deletePoint(*i);
Chris@411 1444 }
Chris@411 1445 }
Chris@411 1446
Chris@411 1447 finish(command);
Chris@550 1448 recalcSpacing();
Chris@411 1449 }
Chris@411 1450
Chris@411 1451 void
Chris@918 1452 RegionLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
Chris@411 1453 {
Chris@411 1454 if (!m_model) return;
Chris@411 1455
Chris@411 1456 RegionModel::PointList points =
Chris@1266 1457 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 1458
Chris@411 1459 for (RegionModel::PointList::iterator i = points.begin();
Chris@1266 1460 i != points.end(); ++i) {
Chris@1266 1461 if (s.contains(i->frame)) {
Chris@411 1462 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
Chris@411 1463 point.setReferenceFrame(alignToReference(v, i->frame));
Chris@411 1464 to.addPoint(point);
Chris@411 1465 }
Chris@411 1466 }
Chris@411 1467 }
Chris@411 1468
Chris@411 1469 bool
Chris@918 1470 RegionLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */)
Chris@411 1471 {
Chris@411 1472 if (!m_model) return false;
Chris@411 1473
Chris@411 1474 const Clipboard::PointList &points = from.getPoints();
Chris@411 1475
Chris@411 1476 bool realign = false;
Chris@411 1477
Chris@411 1478 if (clipboardHasDifferentAlignment(v, from)) {
Chris@411 1479
Chris@411 1480 QMessageBox::StandardButton button =
Chris@918 1481 QMessageBox::question(v->getView(), tr("Re-align pasted items?"),
Chris@411 1482 tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"),
Chris@411 1483 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@411 1484 QMessageBox::Yes);
Chris@411 1485
Chris@411 1486 if (button == QMessageBox::Cancel) {
Chris@411 1487 return false;
Chris@411 1488 }
Chris@411 1489
Chris@411 1490 if (button == QMessageBox::Yes) {
Chris@411 1491 realign = true;
Chris@411 1492 }
Chris@411 1493 }
Chris@411 1494
Chris@411 1495 RegionModel::EditCommand *command =
Chris@1266 1496 new RegionModel::EditCommand(m_model, tr("Paste"));
Chris@411 1497
Chris@411 1498 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@411 1499 i != points.end(); ++i) {
Chris@411 1500
Chris@411 1501 if (!i->haveFrame()) continue;
Chris@905 1502 sv_frame_t frame = 0;
Chris@411 1503
Chris@411 1504 if (!realign) {
Chris@411 1505
Chris@411 1506 frame = i->getFrame();
Chris@411 1507
Chris@411 1508 } else {
Chris@411 1509
Chris@411 1510 if (i->haveReferenceFrame()) {
Chris@411 1511 frame = i->getReferenceFrame();
Chris@411 1512 frame = alignFromReference(v, frame);
Chris@411 1513 } else {
Chris@411 1514 frame = i->getFrame();
Chris@411 1515 }
Chris@411 1516 }
Chris@411 1517
Chris@411 1518 RegionModel::Point newPoint(frame);
Chris@411 1519
Chris@411 1520 if (i->haveLabel()) newPoint.label = i->getLabel();
Chris@411 1521 if (i->haveValue()) newPoint.value = i->getValue();
Chris@411 1522 else newPoint.value = (m_model->getValueMinimum() +
Chris@411 1523 m_model->getValueMaximum()) / 2;
Chris@411 1524 if (i->haveDuration()) newPoint.duration = i->getDuration();
Chris@411 1525 else {
Chris@905 1526 sv_frame_t nextFrame = frame;
Chris@411 1527 Clipboard::PointList::const_iterator j = i;
Chris@411 1528 for (; j != points.end(); ++j) {
Chris@411 1529 if (!j->haveFrame()) continue;
Chris@411 1530 if (j != i) break;
Chris@411 1531 }
Chris@411 1532 if (j != points.end()) {
Chris@411 1533 nextFrame = j->getFrame();
Chris@411 1534 }
Chris@411 1535 if (nextFrame == frame) {
Chris@411 1536 newPoint.duration = m_model->getResolution();
Chris@411 1537 } else {
Chris@411 1538 newPoint.duration = nextFrame - frame;
Chris@411 1539 }
Chris@411 1540 }
Chris@411 1541
Chris@411 1542 command->addPoint(newPoint);
Chris@411 1543 }
Chris@411 1544
Chris@411 1545 finish(command);
Chris@550 1546 recalcSpacing();
Chris@411 1547 return true;
Chris@411 1548 }
Chris@411 1549
Chris@411 1550 void
Chris@411 1551 RegionLayer::toXml(QTextStream &stream,
Chris@411 1552 QString indent, QString extraAttributes) const
Chris@411 1553 {
Chris@1362 1554 QString s;
Chris@1362 1555
Chris@1362 1556 s += QString("verticalScale=\"%1\" "
Chris@1362 1557 "plotStyle=\"%2\" ")
Chris@1362 1558 .arg(m_verticalScale)
Chris@1362 1559 .arg(m_plotStyle);
Chris@1362 1560
Chris@1362 1561 // New-style colour map attribute, by string id rather than by
Chris@1362 1562 // number
Chris@1362 1563
Chris@1362 1564 s += QString("fillColourMap=\"%1\" ")
Chris@1362 1565 .arg(ColourMapper::getColourMapId(m_colourMap));
Chris@1362 1566
Chris@1362 1567 // Old-style colour map attribute
Chris@1362 1568
Chris@1362 1569 s += QString("colourMap=\"%1\" ")
Chris@1362 1570 .arg(ColourMapper::getBackwardCompatibilityColourMap(m_colourMap));
Chris@1362 1571
Chris@1362 1572 SingleColourLayer::toXml(stream, indent, extraAttributes + " " + s);
Chris@411 1573 }
Chris@411 1574
Chris@411 1575 void
Chris@411 1576 RegionLayer::setProperties(const QXmlAttributes &attributes)
Chris@411 1577 {
Chris@411 1578 SingleColourLayer::setProperties(attributes);
Chris@411 1579
Chris@411 1580 bool ok;
Chris@411 1581 VerticalScale scale = (VerticalScale)
Chris@1266 1582 attributes.value("verticalScale").toInt(&ok);
Chris@411 1583 if (ok) setVerticalScale(scale);
Chris@412 1584 PlotStyle style = (PlotStyle)
Chris@1266 1585 attributes.value("plotStyle").toInt(&ok);
Chris@412 1586 if (ok) setPlotStyle(style);
Chris@1362 1587
Chris@1362 1588 QString colourMapId = attributes.value("fillColourMap");
Chris@1362 1589 int colourMap = ColourMapper::getColourMapById(colourMapId);
Chris@1362 1590 if (colourMap >= 0) {
Chris@1362 1591 setFillColourMap(colourMap);
Chris@1362 1592 } else {
Chris@1362 1593 colourMap = attributes.value("colourMap").toInt(&ok);
Chris@1362 1594 if (ok && colourMap < ColourMapper::getColourMapCount()) {
Chris@1362 1595 setFillColourMap(colourMap);
Chris@1362 1596 }
Chris@1362 1597 }
Chris@411 1598 }
Chris@411 1599
Chris@411 1600