annotate layer/RegionLayer.cpp @ 510:683c46d7500b

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