annotate layer/RegionLayer.cpp @ 454:e2a40fdadd8c

Various fixes: * Fix handling of HTTP redirects (avoiding crashes... I hope) * Fix failure to delete FFT models when a feature extraction model transformer was abandoned (also a cause of crashes in the past) * Fix deadlock when said transform was abandoned before its source model was ready because the session was being cleared (and so the source model would never be ready)
author Chris Cannam
date Fri, 28 Nov 2008 13:36:13 +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