annotate layer/RegionLayer.cpp @ 432:8b2b497d302c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 1304dbe4542e
children ac349afdb23f
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@411 22 #include "ColourDatabase.h"
Chris@427 23 #include "ColourMapper.h"
Chris@411 24 #include "view/View.h"
Chris@411 25
Chris@411 26 #include "data/model/RegionModel.h"
Chris@411 27
Chris@411 28 #include "widgets/ItemEditDialog.h"
Chris@411 29
Chris@411 30 #include <QPainter>
Chris@411 31 #include <QPainterPath>
Chris@411 32 #include <QMouseEvent>
Chris@411 33 #include <QTextStream>
Chris@411 34 #include <QMessageBox>
Chris@411 35
Chris@411 36 #include <iostream>
Chris@411 37 #include <cmath>
Chris@411 38
Chris@411 39 RegionLayer::RegionLayer() :
Chris@411 40 SingleColourLayer(),
Chris@411 41 m_model(0),
Chris@411 42 m_editing(false),
Chris@411 43 m_originalPoint(0, 0.0, 0, tr("New Point")),
Chris@411 44 m_editingPoint(0, 0.0, 0, tr("New Point")),
Chris@411 45 m_editingCommand(0),
Chris@412 46 m_verticalScale(AutoAlignScale),
Chris@427 47 m_colourMap(0),
Chris@412 48 m_plotStyle(PlotLines)
Chris@411 49 {
Chris@411 50
Chris@411 51 }
Chris@411 52
Chris@411 53 void
Chris@411 54 RegionLayer::setModel(RegionModel *model)
Chris@411 55 {
Chris@411 56 if (m_model == model) return;
Chris@411 57 m_model = model;
Chris@411 58
Chris@411 59 connectSignals(m_model);
Chris@411 60
Chris@411 61 // std::cerr << "RegionLayer::setModel(" << model << ")" << std::endl;
Chris@411 62
Chris@411 63 emit modelReplaced();
Chris@411 64 }
Chris@411 65
Chris@411 66 Layer::PropertyList
Chris@411 67 RegionLayer::getProperties() const
Chris@411 68 {
Chris@411 69 PropertyList list = SingleColourLayer::getProperties();
Chris@411 70 list.push_back("Vertical Scale");
Chris@411 71 list.push_back("Scale Units");
Chris@412 72 list.push_back("Plot Type");
Chris@411 73 return list;
Chris@411 74 }
Chris@411 75
Chris@411 76 QString
Chris@411 77 RegionLayer::getPropertyLabel(const PropertyName &name) const
Chris@411 78 {
Chris@411 79 if (name == "Vertical Scale") return tr("Vertical Scale");
Chris@411 80 if (name == "Scale Units") return tr("Scale Units");
Chris@412 81 if (name == "Plot Type") return tr("Plot Type");
Chris@411 82 return SingleColourLayer::getPropertyLabel(name);
Chris@411 83 }
Chris@411 84
Chris@411 85 Layer::PropertyType
Chris@411 86 RegionLayer::getPropertyType(const PropertyName &name) const
Chris@411 87 {
Chris@411 88 if (name == "Scale Units") return UnitsProperty;
Chris@411 89 if (name == "Vertical Scale") return ValueProperty;
Chris@412 90 if (name == "Plot Type") return ValueProperty;
Chris@427 91 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty;
Chris@411 92 return SingleColourLayer::getPropertyType(name);
Chris@411 93 }
Chris@411 94
Chris@411 95 QString
Chris@411 96 RegionLayer::getPropertyGroupName(const PropertyName &name) const
Chris@411 97 {
Chris@411 98 if (name == "Vertical Scale" || name == "Scale Units") {
Chris@411 99 return tr("Scale");
Chris@411 100 }
Chris@411 101 return SingleColourLayer::getPropertyGroupName(name);
Chris@411 102 }
Chris@411 103
Chris@411 104 int
Chris@411 105 RegionLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@411 106 int *min, int *max, int *deflt) const
Chris@411 107 {
Chris@411 108 int val = 0;
Chris@411 109
Chris@427 110 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@427 111
Chris@427 112 if (min) *min = 0;
Chris@427 113 if (max) *max = ColourMapper::getColourMapCount() - 1;
Chris@427 114 if (deflt) *deflt = 0;
Chris@427 115
Chris@427 116 val = m_colourMap;
Chris@427 117
Chris@427 118 } else if (name == "Plot Type") {
Chris@412 119
Chris@412 120 if (min) *min = 0;
Chris@412 121 if (max) *max = 1;
Chris@412 122 if (deflt) *deflt = 0;
Chris@412 123
Chris@412 124 val = int(m_plotStyle);
Chris@412 125
Chris@412 126 } else if (name == "Vertical Scale") {
Chris@411 127
Chris@411 128 if (min) *min = 0;
Chris@411 129 if (max) *max = 3;
Chris@411 130 if (deflt) *deflt = int(AutoAlignScale);
Chris@411 131
Chris@411 132 val = int(m_verticalScale);
Chris@411 133
Chris@411 134 } else if (name == "Scale Units") {
Chris@411 135
Chris@411 136 if (deflt) *deflt = 0;
Chris@411 137 if (m_model) {
Chris@411 138 val = UnitDatabase::getInstance()->getUnitId
Chris@411 139 (m_model->getScaleUnits());
Chris@411 140 }
Chris@411 141
Chris@411 142 } else {
Chris@411 143
Chris@411 144 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@411 145 }
Chris@411 146
Chris@411 147 return val;
Chris@411 148 }
Chris@411 149
Chris@411 150 QString
Chris@411 151 RegionLayer::getPropertyValueLabel(const PropertyName &name,
Chris@427 152 int value) const
Chris@411 153 {
Chris@427 154 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@427 155 return ColourMapper::getColourMapName(value);
Chris@427 156 } else if (name == "Plot Type") {
Chris@412 157
Chris@412 158 switch (value) {
Chris@412 159 default:
Chris@427 160 case 0: return tr("Bars");
Chris@412 161 case 1: return tr("Segmentation");
Chris@412 162 }
Chris@412 163
Chris@412 164 } else if (name == "Vertical Scale") {
Chris@411 165 switch (value) {
Chris@411 166 default:
Chris@411 167 case 0: return tr("Auto-Align");
Chris@411 168 case 1: return tr("Linear");
Chris@411 169 case 2: return tr("Log");
Chris@411 170 }
Chris@411 171 }
Chris@411 172 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@411 173 }
Chris@411 174
Chris@411 175 void
Chris@411 176 RegionLayer::setProperty(const PropertyName &name, int value)
Chris@411 177 {
Chris@427 178 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@427 179 setFillColourMap(value);
Chris@427 180 } else if (name == "Plot Type") {
Chris@412 181 setPlotStyle(PlotStyle(value));
Chris@412 182 } else if (name == "Vertical Scale") {
Chris@411 183 setVerticalScale(VerticalScale(value));
Chris@411 184 } else if (name == "Scale Units") {
Chris@411 185 if (m_model) {
Chris@411 186 m_model->setScaleUnits
Chris@411 187 (UnitDatabase::getInstance()->getUnitById(value));
Chris@411 188 emit modelChanged();
Chris@411 189 }
Chris@411 190 } else {
Chris@411 191 return SingleColourLayer::setProperty(name, value);
Chris@411 192 }
Chris@411 193 }
Chris@411 194
Chris@411 195 void
Chris@427 196 RegionLayer::setFillColourMap(int map)
Chris@427 197 {
Chris@427 198 if (m_colourMap == map) return;
Chris@427 199 m_colourMap = map;
Chris@427 200 emit layerParametersChanged();
Chris@427 201 }
Chris@427 202
Chris@427 203 void
Chris@412 204 RegionLayer::setPlotStyle(PlotStyle style)
Chris@412 205 {
Chris@412 206 if (m_plotStyle == style) return;
Chris@427 207 bool colourTypeChanged = (style == PlotSegmentation ||
Chris@427 208 m_plotStyle == PlotSegmentation);
Chris@412 209 m_plotStyle = style;
Chris@427 210 if (colourTypeChanged) {
Chris@427 211 emit layerParameterRangesChanged();
Chris@427 212 }
Chris@412 213 emit layerParametersChanged();
Chris@412 214 }
Chris@412 215
Chris@412 216 void
Chris@411 217 RegionLayer::setVerticalScale(VerticalScale scale)
Chris@411 218 {
Chris@411 219 if (m_verticalScale == scale) return;
Chris@411 220 m_verticalScale = scale;
Chris@411 221 emit layerParametersChanged();
Chris@411 222 }
Chris@411 223
Chris@411 224 bool
Chris@411 225 RegionLayer::isLayerScrollable(const View *v) const
Chris@411 226 {
Chris@411 227 QPoint discard;
Chris@411 228 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@411 229 }
Chris@411 230
Chris@411 231 bool
Chris@411 232 RegionLayer::getValueExtents(float &min, float &max,
Chris@411 233 bool &logarithmic, QString &unit) const
Chris@411 234 {
Chris@411 235 if (!m_model) return false;
Chris@411 236 min = m_model->getValueMinimum();
Chris@411 237 max = m_model->getValueMaximum();
Chris@411 238 unit = m_model->getScaleUnits();
Chris@411 239
Chris@411 240 if (m_verticalScale == LogScale) logarithmic = true;
Chris@411 241
Chris@411 242 return true;
Chris@411 243 }
Chris@411 244
Chris@411 245 bool
Chris@411 246 RegionLayer::getDisplayExtents(float &min, float &max) const
Chris@411 247 {
Chris@411 248 if (!m_model || m_verticalScale == AutoAlignScale) return false;
Chris@411 249
Chris@411 250 min = m_model->getValueMinimum();
Chris@411 251 max = m_model->getValueMaximum();
Chris@411 252
Chris@411 253 return true;
Chris@411 254 }
Chris@411 255
Chris@411 256 RegionModel::PointList
Chris@411 257 RegionLayer::getLocalPoints(View *v, int x) const
Chris@411 258 {
Chris@411 259 if (!m_model) return RegionModel::PointList();
Chris@411 260
Chris@411 261 long frame = v->getFrameForX(x);
Chris@411 262
Chris@411 263 RegionModel::PointList onPoints =
Chris@411 264 m_model->getPoints(frame);
Chris@411 265
Chris@411 266 if (!onPoints.empty()) {
Chris@411 267 return onPoints;
Chris@411 268 }
Chris@411 269
Chris@411 270 RegionModel::PointList prevPoints =
Chris@411 271 m_model->getPreviousPoints(frame);
Chris@411 272 RegionModel::PointList nextPoints =
Chris@411 273 m_model->getNextPoints(frame);
Chris@411 274
Chris@411 275 RegionModel::PointList usePoints = prevPoints;
Chris@411 276
Chris@411 277 if (prevPoints.empty()) {
Chris@411 278 usePoints = nextPoints;
Chris@411 279 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
Chris@411 280 !(nextPoints.begin()->frame > v->getEndFrame())) {
Chris@411 281 usePoints = nextPoints;
Chris@411 282 } else if (long(nextPoints.begin()->frame) - frame <
Chris@411 283 frame - long(prevPoints.begin()->frame)) {
Chris@411 284 usePoints = nextPoints;
Chris@411 285 }
Chris@411 286
Chris@411 287 if (!usePoints.empty()) {
Chris@411 288 int fuzz = 2;
Chris@411 289 int px = v->getXForFrame(usePoints.begin()->frame);
Chris@411 290 if ((px > x && px - x > fuzz) ||
Chris@411 291 (px < x && x - px > fuzz + 1)) {
Chris@411 292 usePoints.clear();
Chris@411 293 }
Chris@411 294 }
Chris@411 295
Chris@411 296 return usePoints;
Chris@411 297 }
Chris@411 298
Chris@411 299 QString
Chris@411 300 RegionLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@411 301 {
Chris@411 302 int x = pos.x();
Chris@411 303
Chris@411 304 if (!m_model || !m_model->getSampleRate()) return "";
Chris@411 305
Chris@411 306 RegionModel::PointList points = getLocalPoints(v, x);
Chris@411 307
Chris@411 308 if (points.empty()) {
Chris@411 309 if (!m_model->isReady()) {
Chris@411 310 return tr("In progress");
Chris@411 311 } else {
Chris@411 312 return tr("No local points");
Chris@411 313 }
Chris@411 314 }
Chris@411 315
Chris@411 316 RegionRec region(0);
Chris@411 317 RegionModel::PointList::iterator i;
Chris@411 318
Chris@413 319 //!!! harmonise with whatever decision is made about point y
Chris@413 320 //!!! coords in paint method
Chris@413 321
Chris@411 322 for (i = points.begin(); i != points.end(); ++i) {
Chris@411 323
Chris@411 324 int y = getYForValue(v, i->value);
Chris@411 325 int h = 3;
Chris@411 326
Chris@411 327 if (m_model->getValueQuantization() != 0.0) {
Chris@411 328 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
Chris@411 329 if (h < 3) h = 3;
Chris@411 330 }
Chris@411 331
Chris@411 332 if (pos.y() >= y - h && pos.y() <= y) {
Chris@411 333 region = *i;
Chris@411 334 break;
Chris@411 335 }
Chris@411 336 }
Chris@411 337
Chris@411 338 if (i == points.end()) return tr("No local points");
Chris@411 339
Chris@411 340 RealTime rt = RealTime::frame2RealTime(region.frame,
Chris@411 341 m_model->getSampleRate());
Chris@411 342 RealTime rd = RealTime::frame2RealTime(region.duration,
Chris@411 343 m_model->getSampleRate());
Chris@411 344
Chris@411 345 QString valueText;
Chris@411 346
Chris@411 347 valueText = tr("%1 %2").arg(region.value).arg(m_model->getScaleUnits());
Chris@411 348
Chris@411 349 QString text;
Chris@411 350
Chris@411 351 if (region.label == "") {
Chris@411 352 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label"))
Chris@411 353 .arg(rt.toText(true).c_str())
Chris@411 354 .arg(valueText)
Chris@411 355 .arg(rd.toText(true).c_str());
Chris@411 356 } else {
Chris@411 357 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4"))
Chris@411 358 .arg(rt.toText(true).c_str())
Chris@411 359 .arg(valueText)
Chris@411 360 .arg(rd.toText(true).c_str())
Chris@411 361 .arg(region.label);
Chris@411 362 }
Chris@411 363
Chris@411 364 pos = QPoint(v->getXForFrame(region.frame),
Chris@411 365 getYForValue(v, region.value));
Chris@411 366 return text;
Chris@411 367 }
Chris@411 368
Chris@411 369 bool
Chris@411 370 RegionLayer::snapToFeatureFrame(View *v, int &frame,
Chris@414 371 size_t &resolution,
Chris@414 372 SnapType snap) const
Chris@411 373 {
Chris@411 374 if (!m_model) {
Chris@411 375 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@411 376 }
Chris@411 377
Chris@411 378 resolution = m_model->getResolution();
Chris@411 379 RegionModel::PointList points;
Chris@411 380
Chris@411 381 if (snap == SnapNeighbouring) {
Chris@411 382
Chris@411 383 points = getLocalPoints(v, v->getXForFrame(frame));
Chris@411 384 if (points.empty()) return false;
Chris@411 385 frame = points.begin()->frame;
Chris@411 386 return true;
Chris@411 387 }
Chris@411 388
Chris@411 389 points = m_model->getPoints(frame, frame);
Chris@411 390 int snapped = frame;
Chris@411 391 bool found = false;
Chris@411 392
Chris@411 393 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@411 394 i != points.end(); ++i) {
Chris@411 395
Chris@411 396 if (snap == SnapRight) {
Chris@411 397
Chris@414 398 // The best frame to snap to is the end frame of whichever
Chris@414 399 // feature we would have snapped to the start frame of if
Chris@414 400 // we had been snapping left.
Chris@414 401
Chris@414 402 if (i->frame <= frame) {
Chris@414 403 if (i->frame + i->duration > frame) {
Chris@414 404 snapped = i->frame + i->duration;
Chris@414 405 found = true; // don't break, as the next may be better
Chris@414 406 }
Chris@414 407 } else {
Chris@414 408 if (!found) {
Chris@414 409 snapped = i->frame;
Chris@414 410 found = true;
Chris@414 411 }
Chris@414 412 break;
Chris@414 413 }
Chris@411 414
Chris@411 415 } else if (snap == SnapLeft) {
Chris@411 416
Chris@411 417 if (i->frame <= frame) {
Chris@411 418 snapped = i->frame;
Chris@411 419 found = true; // don't break, as the next may be better
Chris@411 420 } else {
Chris@411 421 break;
Chris@411 422 }
Chris@411 423
Chris@411 424 } else { // nearest
Chris@411 425
Chris@411 426 RegionModel::PointList::const_iterator j = i;
Chris@411 427 ++j;
Chris@411 428
Chris@411 429 if (j == points.end()) {
Chris@411 430
Chris@411 431 snapped = i->frame;
Chris@411 432 found = true;
Chris@411 433 break;
Chris@411 434
Chris@411 435 } else if (j->frame >= frame) {
Chris@411 436
Chris@411 437 if (j->frame - frame < frame - i->frame) {
Chris@411 438 snapped = j->frame;
Chris@411 439 } else {
Chris@411 440 snapped = i->frame;
Chris@411 441 }
Chris@411 442 found = true;
Chris@411 443 break;
Chris@411 444 }
Chris@411 445 }
Chris@411 446 }
Chris@411 447
Chris@411 448 frame = snapped;
Chris@411 449 return found;
Chris@411 450 }
Chris@411 451
Chris@411 452 void
Chris@411 453 RegionLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
Chris@411 454 {
Chris@411 455 min = 0.0;
Chris@411 456 max = 0.0;
Chris@411 457 log = false;
Chris@411 458
Chris@411 459 QString queryUnits;
Chris@411 460 queryUnits = m_model->getScaleUnits();
Chris@411 461
Chris@411 462 if (m_verticalScale == AutoAlignScale) {
Chris@411 463
Chris@411 464 if (!v->getValueExtents(queryUnits, min, max, log)) {
Chris@411 465
Chris@411 466 min = m_model->getValueMinimum();
Chris@411 467 max = m_model->getValueMaximum();
Chris@411 468
Chris@411 469 std::cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
Chris@411 470
Chris@411 471 } else if (log) {
Chris@411 472
Chris@411 473 LogRange::mapRange(min, max);
Chris@411 474
Chris@411 475 std::cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
Chris@411 476
Chris@411 477 }
Chris@411 478
Chris@411 479 } else {
Chris@411 480
Chris@411 481 min = m_model->getValueMinimum();
Chris@411 482 max = m_model->getValueMaximum();
Chris@411 483
Chris@411 484 if (m_verticalScale == LogScale) {
Chris@411 485 LogRange::mapRange(min, max);
Chris@411 486 log = true;
Chris@411 487 }
Chris@411 488 }
Chris@411 489
Chris@411 490 if (max == min) max = min + 1.0;
Chris@411 491 }
Chris@411 492
Chris@411 493 int
Chris@411 494 RegionLayer::getYForValue(View *v, float val) const
Chris@411 495 {
Chris@411 496 float min = 0.0, max = 0.0;
Chris@411 497 bool logarithmic = false;
Chris@411 498 int h = v->height();
Chris@413 499 int margin = 8;
Chris@413 500 if (h < margin * 8) margin = h / 8;
Chris@411 501
Chris@411 502 getScaleExtents(v, min, max, logarithmic);
Chris@411 503
Chris@432 504 // std::cerr << "RegionLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << std::endl;
Chris@432 505 // std::cerr << "h = " << h << ", margin = " << margin << std::endl;
Chris@411 506
Chris@411 507 if (logarithmic) {
Chris@411 508 val = LogRange::map(val);
Chris@413 509 std::cerr << "logarithmic true, val now = " << val << std::endl;
Chris@411 510 }
Chris@411 511
Chris@413 512 h -= margin * 2;
Chris@413 513 int y = margin + int(h - ((val - min) * h) / (max - min)) - 1;
Chris@432 514 // std::cerr << "y = " << y << std::endl;
Chris@411 515 return y;
Chris@411 516 }
Chris@411 517
Chris@427 518 QColor
Chris@427 519 RegionLayer::getColourForValue(View *v, float val) const
Chris@427 520 {
Chris@427 521 float min, max;
Chris@427 522 bool log;
Chris@427 523 getScaleExtents(v, min, max, log);
Chris@427 524
Chris@427 525 if (min > max) std::swap(min, max);
Chris@427 526 if (max == min) max = min + 1;
Chris@427 527
Chris@427 528 if (log) {
Chris@427 529 LogRange::mapRange(min, max);
Chris@427 530 val = LogRange::map(val);
Chris@427 531 }
Chris@427 532
Chris@427 533 // std::cerr << "RegionLayer::getColourForValue: min " << min << ", max "
Chris@427 534 // << max << ", log " << log << ", value " << val << std::endl;
Chris@427 535
Chris@427 536 QColor solid = ColourMapper(m_colourMap, min, max).map(val);
Chris@427 537 return QColor(solid.red(), solid.green(), solid.blue(), 120);
Chris@427 538 }
Chris@427 539
Chris@427 540 int
Chris@427 541 RegionLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@427 542 {
Chris@427 543 impose = false;
Chris@427 544 return ColourDatabase::getInstance()->getColourIndex
Chris@427 545 (QString(darkbg ? "Bright Blue" : "Blue"));
Chris@427 546 }
Chris@427 547
Chris@411 548 float
Chris@411 549 RegionLayer::getValueForY(View *v, int y) const
Chris@411 550 {
Chris@411 551 float min = 0.0, max = 0.0;
Chris@411 552 bool logarithmic = false;
Chris@411 553 int h = v->height();
Chris@411 554
Chris@411 555 getScaleExtents(v, min, max, logarithmic);
Chris@411 556
Chris@411 557 float val = min + (float(h - y) * float(max - min)) / h;
Chris@411 558
Chris@411 559 if (logarithmic) {
Chris@411 560 val = powf(10.f, val);
Chris@411 561 }
Chris@411 562
Chris@411 563 return val;
Chris@411 564 }
Chris@411 565
Chris@411 566 void
Chris@411 567 RegionLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@411 568 {
Chris@411 569 if (!m_model || !m_model->isOK()) return;
Chris@411 570
Chris@411 571 int sampleRate = m_model->getSampleRate();
Chris@411 572 if (!sampleRate) return;
Chris@411 573
Chris@411 574 // Profiler profiler("RegionLayer::paint", true);
Chris@411 575
Chris@411 576 int x0 = rect.left(), x1 = rect.right();
Chris@411 577 long frame0 = v->getFrameForX(x0);
Chris@411 578 long frame1 = v->getFrameForX(x1);
Chris@411 579
Chris@411 580 RegionModel::PointList points(m_model->getPoints(frame0, frame1));
Chris@411 581 if (points.empty()) return;
Chris@411 582
Chris@411 583 paint.setPen(getBaseQColor());
Chris@411 584
Chris@411 585 QColor brushColour(getBaseQColor());
Chris@411 586 brushColour.setAlpha(80);
Chris@411 587
Chris@411 588 // std::cerr << "RegionLayer::paint: resolution is "
Chris@411 589 // << m_model->getResolution() << " frames" << std::endl;
Chris@411 590
Chris@411 591 float min = m_model->getValueMinimum();
Chris@411 592 float max = m_model->getValueMaximum();
Chris@411 593 if (max == min) max = min + 1.0;
Chris@411 594
Chris@411 595 QPoint localPos;
Chris@411 596 long illuminateFrame = -1;
Chris@411 597
Chris@411 598 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@411 599 RegionModel::PointList localPoints =
Chris@411 600 getLocalPoints(v, localPos.x());
Chris@411 601 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
Chris@411 602 }
Chris@411 603
Chris@411 604 paint.save();
Chris@411 605 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@411 606
Chris@413 607 //!!! point y coords if model does not haveDistinctValues() should
Chris@413 608 //!!! be assigned to avoid overlaps
Chris@413 609
Chris@413 610 //!!! if it does have distinct values, we should still ensure y
Chris@413 611 //!!! coord is never completely flat on the top or bottom
Chris@413 612
Chris@427 613 int textY = 0;
Chris@427 614 if (m_plotStyle == PlotSegmentation) {
Chris@427 615 textY = v->getTextLabelHeight(this, paint);
Chris@427 616 }
Chris@427 617
Chris@411 618 for (RegionModel::PointList::const_iterator i = points.begin();
Chris@411 619 i != points.end(); ++i) {
Chris@411 620
Chris@411 621 const RegionModel::Point &p(*i);
Chris@411 622
Chris@411 623 int x = v->getXForFrame(p.frame);
Chris@411 624 int y = getYForValue(v, p.value);
Chris@411 625 int w = v->getXForFrame(p.frame + p.duration) - x;
Chris@413 626 int h = 9;
Chris@411 627
Chris@427 628 bool haveNext = false;
Chris@427 629 int nx = v->getXForFrame(v->getModelsEndFrame());
Chris@427 630
Chris@427 631 RegionModel::PointList::const_iterator j = i;
Chris@427 632 ++j;
Chris@427 633
Chris@427 634 if (j != points.end()) {
Chris@427 635 const RegionModel::Point &q(*j);
Chris@427 636 nx = v->getXForFrame(q.frame);
Chris@427 637 haveNext = true;
Chris@427 638 }
Chris@427 639
Chris@427 640 if (m_plotStyle != PlotSegmentation) {
Chris@427 641 textY = y - paint.fontMetrics().height()
Chris@427 642 + paint.fontMetrics().ascent();
Chris@427 643 if (textY < paint.fontMetrics().ascent() + 1) {
Chris@427 644 textY = paint.fontMetrics().ascent() + 1;
Chris@427 645 }
Chris@427 646 }
Chris@427 647
Chris@411 648 if (m_model->getValueQuantization() != 0.0) {
Chris@411 649 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
Chris@411 650 if (h < 3) h = 3;
Chris@411 651 }
Chris@411 652
Chris@411 653 if (w < 1) w = 1;
Chris@411 654
Chris@427 655 if (m_plotStyle == PlotSegmentation) {
Chris@427 656 paint.setPen(getForegroundQColor(v));
Chris@427 657 paint.setBrush(getColourForValue(v, p.value));
Chris@427 658 } else {
Chris@427 659 paint.setPen(getBaseQColor());
Chris@427 660 paint.setBrush(brushColour);
Chris@427 661 }
Chris@427 662
Chris@427 663 if (m_plotStyle == PlotSegmentation) {
Chris@427 664
Chris@427 665 if (nx <= x) continue;
Chris@427 666
Chris@427 667 if (illuminateFrame != p.frame &&
Chris@427 668 (nx < x + 5 || x >= v->width() - 1)) {
Chris@427 669 paint.setPen(Qt::NoPen);
Chris@411 670 }
Chris@427 671
Chris@427 672 paint.drawRect(x, -1, nx - x, v->height() + 1);
Chris@427 673
Chris@427 674 } else {
Chris@427 675
Chris@427 676 if (illuminateFrame == p.frame) {
Chris@427 677 if (localPos.y() >= y - h && localPos.y() < y) {
Chris@427 678 paint.setPen(v->getForeground());
Chris@427 679 paint.setBrush(v->getForeground());
Chris@427 680 }
Chris@427 681 }
Chris@427 682
Chris@427 683 paint.drawLine(x, y-1, x + w, y-1);
Chris@427 684 paint.drawLine(x, y+1, x + w, y+1);
Chris@427 685 paint.drawLine(x, y - h/2, x, y + h/2);
Chris@427 686 paint.drawLine(x+w, y - h/2, x + w, y + h/2);
Chris@427 687 }
Chris@427 688
Chris@427 689 if (p.label != "") {
Chris@427 690 if (!haveNext || nx > x + 6 + paint.fontMetrics().width(p.label)) {
Chris@427 691 paint.drawText(x + 5, textY, p.label);
Chris@427 692 }
Chris@411 693 }
Chris@411 694 }
Chris@411 695
Chris@411 696 paint.restore();
Chris@411 697 }
Chris@411 698
Chris@411 699 void
Chris@411 700 RegionLayer::drawStart(View *v, QMouseEvent *e)
Chris@411 701 {
Chris@411 702 // std::cerr << "RegionLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 703
Chris@411 704 if (!m_model) return;
Chris@411 705
Chris@411 706 long frame = v->getFrameForX(e->x());
Chris@411 707 if (frame < 0) frame = 0;
Chris@411 708 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 709
Chris@411 710 float value = getValueForY(v, e->y());
Chris@411 711
Chris@411 712 m_editingPoint = RegionModel::Point(frame, value, 0, tr("New Point"));
Chris@411 713 m_originalPoint = m_editingPoint;
Chris@411 714
Chris@411 715 if (m_editingCommand) finish(m_editingCommand);
Chris@411 716 m_editingCommand = new RegionModel::EditCommand(m_model,
Chris@411 717 tr("Draw Point"));
Chris@411 718 m_editingCommand->addPoint(m_editingPoint);
Chris@411 719
Chris@411 720 m_editing = true;
Chris@411 721 }
Chris@411 722
Chris@411 723 void
Chris@411 724 RegionLayer::drawDrag(View *v, QMouseEvent *e)
Chris@411 725 {
Chris@411 726 // std::cerr << "RegionLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 727
Chris@411 728 if (!m_model || !m_editing) return;
Chris@411 729
Chris@411 730 long frame = v->getFrameForX(e->x());
Chris@411 731 if (frame < 0) frame = 0;
Chris@411 732 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 733
Chris@411 734 float newValue = getValueForY(v, e->y());
Chris@411 735
Chris@411 736 long newFrame = m_editingPoint.frame;
Chris@411 737 long newDuration = frame - newFrame;
Chris@411 738 if (newDuration < 0) {
Chris@411 739 newFrame = frame;
Chris@411 740 newDuration = -newDuration;
Chris@411 741 } else if (newDuration == 0) {
Chris@411 742 newDuration = 1;
Chris@411 743 }
Chris@411 744
Chris@411 745 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 746 m_editingPoint.frame = newFrame;
Chris@411 747 m_editingPoint.value = newValue;
Chris@411 748 m_editingPoint.duration = newDuration;
Chris@411 749 m_editingCommand->addPoint(m_editingPoint);
Chris@411 750 }
Chris@411 751
Chris@411 752 void
Chris@411 753 RegionLayer::drawEnd(View *, QMouseEvent *)
Chris@411 754 {
Chris@411 755 // std::cerr << "RegionLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 756 if (!m_model || !m_editing) return;
Chris@411 757 finish(m_editingCommand);
Chris@411 758 m_editingCommand = 0;
Chris@411 759 m_editing = false;
Chris@411 760 }
Chris@411 761
Chris@411 762 void
Chris@411 763 RegionLayer::eraseStart(View *v, QMouseEvent *e)
Chris@411 764 {
Chris@411 765 if (!m_model) return;
Chris@411 766
Chris@411 767 RegionModel::PointList points = getLocalPoints(v, e->x());
Chris@411 768 if (points.empty()) return;
Chris@411 769
Chris@411 770 m_editingPoint = *points.begin();
Chris@411 771
Chris@411 772 if (m_editingCommand) {
Chris@411 773 finish(m_editingCommand);
Chris@411 774 m_editingCommand = 0;
Chris@411 775 }
Chris@411 776
Chris@411 777 m_editing = true;
Chris@411 778 }
Chris@411 779
Chris@411 780 void
Chris@411 781 RegionLayer::eraseDrag(View *v, QMouseEvent *e)
Chris@411 782 {
Chris@411 783 }
Chris@411 784
Chris@411 785 void
Chris@411 786 RegionLayer::eraseEnd(View *v, QMouseEvent *e)
Chris@411 787 {
Chris@411 788 if (!m_model || !m_editing) return;
Chris@411 789
Chris@411 790 m_editing = false;
Chris@411 791
Chris@411 792 RegionModel::PointList points = getLocalPoints(v, e->x());
Chris@411 793 if (points.empty()) return;
Chris@411 794 if (points.begin()->frame != m_editingPoint.frame ||
Chris@411 795 points.begin()->value != m_editingPoint.value) return;
Chris@411 796
Chris@411 797 m_editingCommand = new RegionModel::EditCommand
Chris@411 798 (m_model, tr("Erase Point"));
Chris@411 799
Chris@411 800 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 801
Chris@411 802 finish(m_editingCommand);
Chris@411 803 m_editingCommand = 0;
Chris@411 804 m_editing = false;
Chris@411 805 }
Chris@411 806
Chris@411 807 void
Chris@411 808 RegionLayer::editStart(View *v, QMouseEvent *e)
Chris@411 809 {
Chris@411 810 // std::cerr << "RegionLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 811
Chris@411 812 if (!m_model) return;
Chris@411 813
Chris@411 814 RegionModel::PointList points = getLocalPoints(v, e->x());
Chris@411 815 if (points.empty()) return;
Chris@411 816
Chris@411 817 m_editingPoint = *points.begin();
Chris@411 818 m_originalPoint = m_editingPoint;
Chris@411 819
Chris@411 820 if (m_editingCommand) {
Chris@411 821 finish(m_editingCommand);
Chris@411 822 m_editingCommand = 0;
Chris@411 823 }
Chris@411 824
Chris@411 825 m_editing = true;
Chris@411 826 }
Chris@411 827
Chris@411 828 void
Chris@411 829 RegionLayer::editDrag(View *v, QMouseEvent *e)
Chris@411 830 {
Chris@411 831 // std::cerr << "RegionLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 832
Chris@411 833 if (!m_model || !m_editing) return;
Chris@411 834
Chris@411 835 long frame = v->getFrameForX(e->x());
Chris@411 836 if (frame < 0) frame = 0;
Chris@411 837 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@411 838
Chris@411 839 float value = getValueForY(v, e->y());
Chris@411 840
Chris@411 841 if (!m_editingCommand) {
Chris@411 842 m_editingCommand = new RegionModel::EditCommand(m_model,
Chris@411 843 tr("Drag Point"));
Chris@411 844 }
Chris@411 845
Chris@411 846 m_editingCommand->deletePoint(m_editingPoint);
Chris@411 847 m_editingPoint.frame = frame;
Chris@411 848 m_editingPoint.value = value;
Chris@411 849 m_editingCommand->addPoint(m_editingPoint);
Chris@411 850 }
Chris@411 851
Chris@411 852 void
Chris@411 853 RegionLayer::editEnd(View *, QMouseEvent *)
Chris@411 854 {
Chris@411 855 // std::cerr << "RegionLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@411 856 if (!m_model || !m_editing) return;
Chris@411 857
Chris@411 858 if (m_editingCommand) {
Chris@411 859
Chris@411 860 QString newName = m_editingCommand->getName();
Chris@411 861
Chris@411 862 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@411 863 if (m_editingPoint.value != m_originalPoint.value) {
Chris@411 864 newName = tr("Edit Point");
Chris@411 865 } else {
Chris@411 866 newName = tr("Relocate Point");
Chris@411 867 }
Chris@411 868 } else {
Chris@411 869 newName = tr("Change Point Value");
Chris@411 870 }
Chris@411 871
Chris@411 872 m_editingCommand->setName(newName);
Chris@411 873 finish(m_editingCommand);
Chris@411 874 }
Chris@411 875
Chris@411 876 m_editingCommand = 0;
Chris@411 877 m_editing = false;
Chris@411 878 }
Chris@411 879
Chris@411 880 bool
Chris@411 881 RegionLayer::editOpen(View *v, QMouseEvent *e)
Chris@411 882 {
Chris@411 883 if (!m_model) return false;
Chris@411 884
Chris@411 885 RegionModel::PointList points = getLocalPoints(v, e->x());
Chris@411 886 if (points.empty()) return false;
Chris@411 887
Chris@411 888 RegionModel::Point region = *points.begin();
Chris@411 889
Chris@411 890 ItemEditDialog *dialog = new ItemEditDialog
Chris@411 891 (m_model->getSampleRate(),
Chris@411 892 ItemEditDialog::ShowTime |
Chris@411 893 ItemEditDialog::ShowDuration |
Chris@411 894 ItemEditDialog::ShowValue |
Chris@411 895 ItemEditDialog::ShowText,
Chris@411 896 m_model->getScaleUnits());
Chris@411 897
Chris@411 898 dialog->setFrameTime(region.frame);
Chris@411 899 dialog->setValue(region.value);
Chris@411 900 dialog->setFrameDuration(region.duration);
Chris@411 901 dialog->setText(region.label);
Chris@411 902
Chris@411 903 if (dialog->exec() == QDialog::Accepted) {
Chris@411 904
Chris@411 905 RegionModel::Point newRegion = region;
Chris@411 906 newRegion.frame = dialog->getFrameTime();
Chris@411 907 newRegion.value = dialog->getValue();
Chris@411 908 newRegion.duration = dialog->getFrameDuration();
Chris@411 909 newRegion.label = dialog->getText();
Chris@411 910
Chris@411 911 RegionModel::EditCommand *command = new RegionModel::EditCommand
Chris@411 912 (m_model, tr("Edit Point"));
Chris@411 913 command->deletePoint(region);
Chris@411 914 command->addPoint(newRegion);
Chris@411 915 finish(command);
Chris@411 916 }
Chris@411 917
Chris@411 918 delete dialog;
Chris@411 919 return true;
Chris@411 920 }
Chris@411 921
Chris@411 922 void
Chris@411 923 RegionLayer::moveSelection(Selection s, size_t newStartFrame)
Chris@411 924 {
Chris@411 925 if (!m_model) return;
Chris@411 926
Chris@411 927 RegionModel::EditCommand *command =
Chris@411 928 new RegionModel::EditCommand(m_model, tr("Drag Selection"));
Chris@411 929
Chris@411 930 RegionModel::PointList points =
Chris@411 931 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 932
Chris@411 933 for (RegionModel::PointList::iterator i = points.begin();
Chris@411 934 i != points.end(); ++i) {
Chris@411 935
Chris@411 936 if (s.contains(i->frame)) {
Chris@411 937 RegionModel::Point newPoint(*i);
Chris@411 938 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@411 939 command->deletePoint(*i);
Chris@411 940 command->addPoint(newPoint);
Chris@411 941 }
Chris@411 942 }
Chris@411 943
Chris@411 944 finish(command);
Chris@411 945 }
Chris@411 946
Chris@411 947 void
Chris@411 948 RegionLayer::resizeSelection(Selection s, Selection newSize)
Chris@411 949 {
Chris@411 950 if (!m_model) return;
Chris@411 951
Chris@411 952 RegionModel::EditCommand *command =
Chris@411 953 new RegionModel::EditCommand(m_model, tr("Resize Selection"));
Chris@411 954
Chris@411 955 RegionModel::PointList points =
Chris@411 956 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 957
Chris@411 958 double ratio =
Chris@411 959 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@411 960 double(s.getEndFrame() - s.getStartFrame());
Chris@411 961
Chris@411 962 for (RegionModel::PointList::iterator i = points.begin();
Chris@411 963 i != points.end(); ++i) {
Chris@411 964
Chris@411 965 if (s.contains(i->frame)) {
Chris@411 966
Chris@411 967 double targetStart = i->frame;
Chris@411 968 targetStart = newSize.getStartFrame() +
Chris@411 969 double(targetStart - s.getStartFrame()) * ratio;
Chris@411 970
Chris@411 971 double targetEnd = i->frame + i->duration;
Chris@411 972 targetEnd = newSize.getStartFrame() +
Chris@411 973 double(targetEnd - s.getStartFrame()) * ratio;
Chris@411 974
Chris@411 975 RegionModel::Point newPoint(*i);
Chris@411 976 newPoint.frame = lrint(targetStart);
Chris@411 977 newPoint.duration = lrint(targetEnd - targetStart);
Chris@411 978 command->deletePoint(*i);
Chris@411 979 command->addPoint(newPoint);
Chris@411 980 }
Chris@411 981 }
Chris@411 982
Chris@411 983 finish(command);
Chris@411 984 }
Chris@411 985
Chris@411 986 void
Chris@411 987 RegionLayer::deleteSelection(Selection s)
Chris@411 988 {
Chris@411 989 if (!m_model) return;
Chris@411 990
Chris@411 991 RegionModel::EditCommand *command =
Chris@411 992 new RegionModel::EditCommand(m_model, tr("Delete Selected Points"));
Chris@411 993
Chris@411 994 RegionModel::PointList points =
Chris@411 995 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 996
Chris@411 997 for (RegionModel::PointList::iterator i = points.begin();
Chris@411 998 i != points.end(); ++i) {
Chris@411 999
Chris@411 1000 if (s.contains(i->frame)) {
Chris@411 1001 command->deletePoint(*i);
Chris@411 1002 }
Chris@411 1003 }
Chris@411 1004
Chris@411 1005 finish(command);
Chris@411 1006 }
Chris@411 1007
Chris@411 1008 void
Chris@411 1009 RegionLayer::copy(View *v, Selection s, Clipboard &to)
Chris@411 1010 {
Chris@411 1011 if (!m_model) return;
Chris@411 1012
Chris@411 1013 RegionModel::PointList points =
Chris@411 1014 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@411 1015
Chris@411 1016 for (RegionModel::PointList::iterator i = points.begin();
Chris@411 1017 i != points.end(); ++i) {
Chris@411 1018 if (s.contains(i->frame)) {
Chris@411 1019 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
Chris@411 1020 point.setReferenceFrame(alignToReference(v, i->frame));
Chris@411 1021 to.addPoint(point);
Chris@411 1022 }
Chris@411 1023 }
Chris@411 1024 }
Chris@411 1025
Chris@411 1026 bool
Chris@411 1027 RegionLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */)
Chris@411 1028 {
Chris@411 1029 if (!m_model) return false;
Chris@411 1030
Chris@411 1031 const Clipboard::PointList &points = from.getPoints();
Chris@411 1032
Chris@411 1033 bool realign = false;
Chris@411 1034
Chris@411 1035 if (clipboardHasDifferentAlignment(v, from)) {
Chris@411 1036
Chris@411 1037 QMessageBox::StandardButton button =
Chris@411 1038 QMessageBox::question(v, tr("Re-align pasted items?"),
Chris@411 1039 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 1040 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@411 1041 QMessageBox::Yes);
Chris@411 1042
Chris@411 1043 if (button == QMessageBox::Cancel) {
Chris@411 1044 return false;
Chris@411 1045 }
Chris@411 1046
Chris@411 1047 if (button == QMessageBox::Yes) {
Chris@411 1048 realign = true;
Chris@411 1049 }
Chris@411 1050 }
Chris@411 1051
Chris@411 1052 RegionModel::EditCommand *command =
Chris@411 1053 new RegionModel::EditCommand(m_model, tr("Paste"));
Chris@411 1054
Chris@411 1055 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@411 1056 i != points.end(); ++i) {
Chris@411 1057
Chris@411 1058 if (!i->haveFrame()) continue;
Chris@411 1059 size_t frame = 0;
Chris@411 1060
Chris@411 1061 if (!realign) {
Chris@411 1062
Chris@411 1063 frame = i->getFrame();
Chris@411 1064
Chris@411 1065 } else {
Chris@411 1066
Chris@411 1067 if (i->haveReferenceFrame()) {
Chris@411 1068 frame = i->getReferenceFrame();
Chris@411 1069 frame = alignFromReference(v, frame);
Chris@411 1070 } else {
Chris@411 1071 frame = i->getFrame();
Chris@411 1072 }
Chris@411 1073 }
Chris@411 1074
Chris@411 1075 RegionModel::Point newPoint(frame);
Chris@411 1076
Chris@411 1077 if (i->haveLabel()) newPoint.label = i->getLabel();
Chris@411 1078 if (i->haveValue()) newPoint.value = i->getValue();
Chris@411 1079 else newPoint.value = (m_model->getValueMinimum() +
Chris@411 1080 m_model->getValueMaximum()) / 2;
Chris@411 1081 if (i->haveDuration()) newPoint.duration = i->getDuration();
Chris@411 1082 else {
Chris@411 1083 size_t nextFrame = frame;
Chris@411 1084 Clipboard::PointList::const_iterator j = i;
Chris@411 1085 for (; j != points.end(); ++j) {
Chris@411 1086 if (!j->haveFrame()) continue;
Chris@411 1087 if (j != i) break;
Chris@411 1088 }
Chris@411 1089 if (j != points.end()) {
Chris@411 1090 nextFrame = j->getFrame();
Chris@411 1091 }
Chris@411 1092 if (nextFrame == frame) {
Chris@411 1093 newPoint.duration = m_model->getResolution();
Chris@411 1094 } else {
Chris@411 1095 newPoint.duration = nextFrame - frame;
Chris@411 1096 }
Chris@411 1097 }
Chris@411 1098
Chris@411 1099 command->addPoint(newPoint);
Chris@411 1100 }
Chris@411 1101
Chris@411 1102 finish(command);
Chris@411 1103 return true;
Chris@411 1104 }
Chris@411 1105
Chris@411 1106 void
Chris@411 1107 RegionLayer::toXml(QTextStream &stream,
Chris@411 1108 QString indent, QString extraAttributes) const
Chris@411 1109 {
Chris@411 1110 SingleColourLayer::toXml(stream, indent, extraAttributes +
Chris@412 1111 QString(" verticalScale=\"%1\" plotStyle=\"%2\"")
Chris@412 1112 .arg(m_verticalScale)
Chris@412 1113 .arg(m_plotStyle));
Chris@411 1114 }
Chris@411 1115
Chris@411 1116 void
Chris@411 1117 RegionLayer::setProperties(const QXmlAttributes &attributes)
Chris@411 1118 {
Chris@411 1119 SingleColourLayer::setProperties(attributes);
Chris@411 1120
Chris@411 1121 bool ok;
Chris@411 1122 VerticalScale scale = (VerticalScale)
Chris@411 1123 attributes.value("verticalScale").toInt(&ok);
Chris@411 1124 if (ok) setVerticalScale(scale);
Chris@412 1125 PlotStyle style = (PlotStyle)
Chris@412 1126 attributes.value("plotStyle").toInt(&ok);
Chris@412 1127 if (ok) setPlotStyle(style);
Chris@411 1128 }
Chris@411 1129
Chris@411 1130