annotate layer/RegionLayer.cpp @ 427:1304dbe4542e

* Support importing features from RDF whose times are intervals rather than only instants; import them into region or note models. Sadly this makes RDF import much, much slower, because we need to work around Rasqal's single-OPTIONAL limitation by repeatedly querying each feature for time and range. * Add segmentation view to region layer, and display label texts
author Chris Cannam
date Tue, 07 Oct 2008 12:42:17 +0000
parents 31f222929319
children 8b2b497d302c
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@413 504 std::cerr << "RegionLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << std::endl;
Chris@413 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@413 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