annotate layer/TimeValueLayer.cpp @ 349:369a197737c7

* Various fixes to object lifetime management, particularly in the spectrum layer and for notification of main model deletion. The main purpose of this is to improve the behaviour of the spectrum, but I think it may also help with #1840922 Various crashes in Layer Summary window.
author Chris Cannam
date Wed, 23 Jan 2008 15:43:27 +0000
parents ffa448b0e1bc
children de4db9b5dcf1
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@59 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "TimeValueLayer.h"
Chris@0 17
Chris@128 18 #include "data/model/Model.h"
Chris@0 19 #include "base/RealTime.h"
Chris@0 20 #include "base/Profiler.h"
Chris@197 21 #include "base/LogRange.h"
Chris@287 22 #include "base/ColourDatabase.h"
Chris@128 23 #include "view/View.h"
Chris@0 24
Chris@128 25 #include "data/model/SparseTimeValueModel.h"
Chris@340 26 #include "data/model/Labeller.h"
Chris@0 27
Chris@70 28 #include "widgets/ItemEditDialog.h"
Chris@125 29 #include "widgets/ListInputDialog.h"
Chris@70 30
Chris@66 31 #include "SpectrogramLayer.h" // for optional frequency alignment
Chris@285 32 #include "base/ColourMapper.h"
Chris@66 33
Chris@0 34 #include <QPainter>
Chris@6 35 #include <QPainterPath>
Chris@21 36 #include <QMouseEvent>
Chris@125 37 #include <QRegExp>
Chris@316 38 #include <QTextStream>
Chris@340 39 #include <QInputDialog>
Chris@0 40
Chris@0 41 #include <iostream>
Chris@0 42 #include <cmath>
Chris@0 43
Chris@44 44 TimeValueLayer::TimeValueLayer() :
Chris@287 45 SingleColourLayer(),
Chris@0 46 m_model(0),
Chris@21 47 m_editing(false),
Chris@23 48 m_originalPoint(0, 0.0, tr("New Point")),
Chris@21 49 m_editingPoint(0, 0.0, tr("New Point")),
Chris@22 50 m_editingCommand(0),
Chris@197 51 m_colourMap(0),
Chris@66 52 m_plotStyle(PlotConnectedPoints),
Chris@101 53 m_verticalScale(AutoAlignScale)
Chris@0 54 {
Chris@44 55
Chris@0 56 }
Chris@0 57
Chris@0 58 void
Chris@0 59 TimeValueLayer::setModel(SparseTimeValueModel *model)
Chris@0 60 {
Chris@0 61 if (m_model == model) return;
Chris@0 62 m_model = model;
Chris@0 63
Chris@320 64 connectSignals(m_model);
Chris@0 65
Chris@101 66 // std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl;
Chris@0 67
Chris@0 68 emit modelReplaced();
Chris@0 69 }
Chris@0 70
Chris@0 71 Layer::PropertyList
Chris@0 72 TimeValueLayer::getProperties() const
Chris@0 73 {
Chris@287 74 PropertyList list = SingleColourLayer::getProperties();
Chris@87 75 list.push_back("Plot Type");
Chris@87 76 list.push_back("Vertical Scale");
Chris@100 77 list.push_back("Scale Units");
Chris@0 78 return list;
Chris@0 79 }
Chris@0 80
Chris@87 81 QString
Chris@87 82 TimeValueLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 83 {
Chris@87 84 if (name == "Plot Type") return tr("Plot Type");
Chris@87 85 if (name == "Vertical Scale") return tr("Vertical Scale");
Chris@100 86 if (name == "Scale Units") return tr("Scale Units");
Chris@287 87 return SingleColourLayer::getPropertyLabel(name);
Chris@87 88 }
Chris@87 89
Chris@0 90 Layer::PropertyType
Chris@0 91 TimeValueLayer::getPropertyType(const PropertyName &name) const
Chris@0 92 {
Chris@287 93 if (name == "Plot Type") return ValueProperty;
Chris@287 94 if (name == "Vertical Scale") return ValueProperty;
Chris@100 95 if (name == "Scale Units") return UnitsProperty;
Chris@287 96 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty;
Chris@287 97 return SingleColourLayer::getPropertyType(name);
Chris@0 98 }
Chris@0 99
Chris@198 100 QString
Chris@198 101 TimeValueLayer::getPropertyGroupName(const PropertyName &name) const
Chris@198 102 {
Chris@198 103 if (name == "Vertical Scale" || name == "Scale Units") {
Chris@198 104 return tr("Scale");
Chris@198 105 }
Chris@287 106 return SingleColourLayer::getPropertyGroupName(name);
Chris@198 107 }
Chris@198 108
Chris@0 109 int
Chris@0 110 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 111 int *min, int *max, int *deflt) const
Chris@0 112 {
Chris@216 113 int val = 0;
Chris@0 114
Chris@287 115 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@197 116
Chris@287 117 if (min) *min = 0;
Chris@287 118 if (max) *max = ColourMapper::getColourMapCount() - 1;
Chris@287 119 if (deflt) *deflt = 0;
Chris@197 120
Chris@287 121 val = m_colourMap;
Chris@0 122
Chris@87 123 } else if (name == "Plot Type") {
Chris@0 124
Chris@10 125 if (min) *min = 0;
Chris@26 126 if (max) *max = 5;
Chris@216 127 if (deflt) *deflt = int(PlotConnectedPoints);
Chris@0 128
Chris@216 129 val = int(m_plotStyle);
Chris@0 130
Chris@87 131 } else if (name == "Vertical Scale") {
Chris@66 132
Chris@66 133 if (min) *min = 0;
Chris@66 134 if (max) *max = 3;
Chris@216 135 if (deflt) *deflt = int(AutoAlignScale);
Chris@66 136
Chris@216 137 val = int(m_verticalScale);
Chris@66 138
Chris@100 139 } else if (name == "Scale Units") {
Chris@100 140
Chris@216 141 if (deflt) *deflt = 0;
Chris@100 142 if (m_model) {
Chris@216 143 val = UnitDatabase::getInstance()->getUnitId
Chris@100 144 (m_model->getScaleUnits());
Chris@100 145 }
Chris@100 146
Chris@0 147 } else {
Chris@0 148
Chris@287 149 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@0 150 }
Chris@0 151
Chris@216 152 return val;
Chris@0 153 }
Chris@0 154
Chris@0 155 QString
Chris@0 156 TimeValueLayer::getPropertyValueLabel(const PropertyName &name,
Chris@0 157 int value) const
Chris@0 158 {
Chris@287 159 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@287 160 return ColourMapper::getColourMapName(value);
Chris@87 161 } else if (name == "Plot Type") {
Chris@0 162 switch (value) {
Chris@0 163 default:
Chris@0 164 case 0: return tr("Points");
Chris@0 165 case 1: return tr("Stems");
Chris@6 166 case 2: return tr("Connected Points");
Chris@6 167 case 3: return tr("Lines");
Chris@6 168 case 4: return tr("Curve");
Chris@26 169 case 5: return tr("Segmentation");
Chris@0 170 }
Chris@87 171 } else if (name == "Vertical Scale") {
Chris@66 172 switch (value) {
Chris@66 173 default:
Chris@101 174 case 0: return tr("Auto-Align");
Chris@198 175 case 1: return tr("Linear");
Chris@198 176 case 2: return tr("Log");
Chris@198 177 case 3: return tr("+/-1");
Chris@66 178 }
Chris@0 179 }
Chris@287 180 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@0 181 }
Chris@0 182
Chris@0 183 void
Chris@0 184 TimeValueLayer::setProperty(const PropertyName &name, int value)
Chris@0 185 {
Chris@287 186 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
Chris@287 187 setFillColourMap(value);
Chris@87 188 } else if (name == "Plot Type") {
Chris@0 189 setPlotStyle(PlotStyle(value));
Chris@87 190 } else if (name == "Vertical Scale") {
Chris@66 191 setVerticalScale(VerticalScale(value));
Chris@100 192 } else if (name == "Scale Units") {
Chris@100 193 if (m_model) {
Chris@100 194 m_model->setScaleUnits
Chris@100 195 (UnitDatabase::getInstance()->getUnitById(value));
Chris@100 196 emit modelChanged();
Chris@100 197 }
Chris@287 198 } else {
Chris@287 199 SingleColourLayer::setProperty(name, value);
Chris@0 200 }
Chris@0 201 }
Chris@0 202
Chris@0 203 void
Chris@197 204 TimeValueLayer::setFillColourMap(int map)
Chris@197 205 {
Chris@197 206 if (m_colourMap == map) return;
Chris@197 207 m_colourMap = map;
Chris@197 208 emit layerParametersChanged();
Chris@197 209 }
Chris@197 210
Chris@197 211 void
Chris@0 212 TimeValueLayer::setPlotStyle(PlotStyle style)
Chris@0 213 {
Chris@0 214 if (m_plotStyle == style) return;
Chris@197 215 bool colourTypeChanged = (style == PlotSegmentation ||
Chris@197 216 m_plotStyle == PlotSegmentation);
Chris@0 217 m_plotStyle = style;
Chris@197 218 if (colourTypeChanged) {
Chris@197 219 emit layerParameterRangesChanged();
Chris@197 220 }
Chris@0 221 emit layerParametersChanged();
Chris@0 222 }
Chris@0 223
Chris@66 224 void
Chris@66 225 TimeValueLayer::setVerticalScale(VerticalScale scale)
Chris@66 226 {
Chris@66 227 if (m_verticalScale == scale) return;
Chris@66 228 m_verticalScale = scale;
Chris@66 229 emit layerParametersChanged();
Chris@66 230 }
Chris@66 231
Chris@0 232 bool
Chris@44 233 TimeValueLayer::isLayerScrollable(const View *v) const
Chris@0 234 {
Chris@6 235 // We don't illuminate sections in the line or curve modes, so
Chris@6 236 // they're always scrollable
Chris@6 237
Chris@6 238 if (m_plotStyle == PlotLines ||
Chris@6 239 m_plotStyle == PlotCurve) return true;
Chris@6 240
Chris@0 241 QPoint discard;
Chris@44 242 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@0 243 }
Chris@0 244
Chris@79 245 bool
Chris@101 246 TimeValueLayer::getValueExtents(float &min, float &max,
Chris@101 247 bool &logarithmic, QString &unit) const
Chris@79 248 {
Chris@101 249 if (!m_model) return false;
Chris@79 250 min = m_model->getValueMinimum();
Chris@79 251 max = m_model->getValueMaximum();
Chris@101 252 logarithmic = (m_verticalScale == LogScale);
Chris@79 253 unit = m_model->getScaleUnits();
Chris@79 254 return true;
Chris@79 255 }
Chris@79 256
Chris@101 257 bool
Chris@101 258 TimeValueLayer::getDisplayExtents(float &min, float &max) const
Chris@101 259 {
Chris@296 260 if (!m_model || shouldAutoAlign()) return false;
Chris@101 261
Chris@101 262 min = m_model->getValueMinimum();
Chris@101 263 max = m_model->getValueMaximum();
Chris@101 264 return true;
Chris@101 265 }
Chris@101 266
Chris@0 267 SparseTimeValueModel::PointList
Chris@44 268 TimeValueLayer::getLocalPoints(View *v, int x) const
Chris@0 269 {
Chris@0 270 if (!m_model) return SparseTimeValueModel::PointList();
Chris@0 271
Chris@44 272 long frame = v->getFrameForX(x);
Chris@0 273
Chris@0 274 SparseTimeValueModel::PointList onPoints =
Chris@0 275 m_model->getPoints(frame);
Chris@0 276
Chris@0 277 if (!onPoints.empty()) {
Chris@0 278 return onPoints;
Chris@0 279 }
Chris@0 280
Chris@0 281 SparseTimeValueModel::PointList prevPoints =
Chris@0 282 m_model->getPreviousPoints(frame);
Chris@0 283 SparseTimeValueModel::PointList nextPoints =
Chris@0 284 m_model->getNextPoints(frame);
Chris@0 285
Chris@0 286 SparseTimeValueModel::PointList usePoints = prevPoints;
Chris@0 287
Chris@0 288 if (prevPoints.empty()) {
Chris@0 289 usePoints = nextPoints;
Chris@248 290 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
Chris@44 291 !(nextPoints.begin()->frame > v->getEndFrame())) {
Chris@0 292 usePoints = nextPoints;
Chris@0 293 } else if (nextPoints.begin()->frame - frame <
Chris@0 294 frame - prevPoints.begin()->frame) {
Chris@0 295 usePoints = nextPoints;
Chris@0 296 }
Chris@0 297
Chris@28 298 if (!usePoints.empty()) {
Chris@28 299 int fuzz = 2;
Chris@44 300 int px = v->getXForFrame(usePoints.begin()->frame);
Chris@28 301 if ((px > x && px - x > fuzz) ||
Chris@28 302 (px < x && x - px > fuzz + 1)) {
Chris@28 303 usePoints.clear();
Chris@28 304 }
Chris@28 305 }
Chris@28 306
Chris@0 307 return usePoints;
Chris@0 308 }
Chris@0 309
Chris@25 310 QString
Chris@44 311 TimeValueLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@0 312 {
Chris@25 313 int x = pos.x();
Chris@0 314
Chris@25 315 if (!m_model || !m_model->getSampleRate()) return "";
Chris@0 316
Chris@44 317 SparseTimeValueModel::PointList points = getLocalPoints(v, x);
Chris@0 318
Chris@0 319 if (points.empty()) {
Chris@0 320 if (!m_model->isReady()) {
Chris@25 321 return tr("In progress");
Chris@25 322 } else {
Chris@25 323 return tr("No local points");
Chris@0 324 }
Chris@0 325 }
Chris@0 326
Chris@0 327 long useFrame = points.begin()->frame;
Chris@0 328
Chris@0 329 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
Chris@25 330
Chris@25 331 QString text;
Chris@101 332 QString unit = m_model->getScaleUnits();
Chris@101 333 if (unit != "") unit = " " + unit;
Chris@0 334
Chris@25 335 if (points.begin()->label == "") {
Chris@101 336 text = QString(tr("Time:\t%1\nValue:\t%2%3\nNo label"))
Chris@25 337 .arg(rt.toText(true).c_str())
Chris@25 338 .arg(points.begin()->value)
Chris@101 339 .arg(unit);
Chris@101 340 } else {
Chris@101 341 text = QString(tr("Time:\t%1\nValue:\t%2%3\nLabel:\t%4"))
Chris@101 342 .arg(rt.toText(true).c_str())
Chris@101 343 .arg(points.begin()->value)
Chris@101 344 .arg(unit)
Chris@25 345 .arg(points.begin()->label);
Chris@25 346 }
Chris@0 347
Chris@44 348 pos = QPoint(v->getXForFrame(useFrame),
Chris@44 349 getYForValue(v, points.begin()->value));
Chris@25 350 return text;
Chris@0 351 }
Chris@0 352
Chris@28 353 bool
Chris@44 354 TimeValueLayer::snapToFeatureFrame(View *v, int &frame,
Chris@28 355 size_t &resolution,
Chris@28 356 SnapType snap) const
Chris@13 357 {
Chris@13 358 if (!m_model) {
Chris@44 359 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@13 360 }
Chris@13 361
Chris@13 362 resolution = m_model->getResolution();
Chris@28 363 SparseTimeValueModel::PointList points;
Chris@13 364
Chris@28 365 if (snap == SnapNeighbouring) {
Chris@28 366
Chris@44 367 points = getLocalPoints(v, v->getXForFrame(frame));
Chris@28 368 if (points.empty()) return false;
Chris@28 369 frame = points.begin()->frame;
Chris@28 370 return true;
Chris@28 371 }
Chris@28 372
Chris@28 373 points = m_model->getPoints(frame, frame);
Chris@28 374 int snapped = frame;
Chris@28 375 bool found = false;
Chris@13 376
Chris@13 377 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@13 378 i != points.end(); ++i) {
Chris@13 379
Chris@28 380 if (snap == SnapRight) {
Chris@28 381
Chris@13 382 if (i->frame > frame) {
Chris@28 383 snapped = i->frame;
Chris@28 384 found = true;
Chris@13 385 break;
Chris@13 386 }
Chris@28 387
Chris@28 388 } else if (snap == SnapLeft) {
Chris@28 389
Chris@13 390 if (i->frame <= frame) {
Chris@28 391 snapped = i->frame;
Chris@28 392 found = true; // don't break, as the next may be better
Chris@28 393 } else {
Chris@28 394 break;
Chris@28 395 }
Chris@28 396
Chris@28 397 } else { // nearest
Chris@28 398
Chris@28 399 SparseTimeValueModel::PointList::const_iterator j = i;
Chris@28 400 ++j;
Chris@28 401
Chris@28 402 if (j == points.end()) {
Chris@28 403
Chris@28 404 snapped = i->frame;
Chris@28 405 found = true;
Chris@28 406 break;
Chris@28 407
Chris@28 408 } else if (j->frame >= frame) {
Chris@28 409
Chris@28 410 if (j->frame - frame < frame - i->frame) {
Chris@28 411 snapped = j->frame;
Chris@28 412 } else {
Chris@28 413 snapped = i->frame;
Chris@28 414 }
Chris@28 415 found = true;
Chris@28 416 break;
Chris@13 417 }
Chris@13 418 }
Chris@13 419 }
Chris@13 420
Chris@28 421 frame = snapped;
Chris@28 422 return found;
Chris@13 423 }
Chris@13 424
Chris@101 425 void
Chris@101 426 TimeValueLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
Chris@101 427 {
Chris@101 428 min = 0.0;
Chris@101 429 max = 0.0;
Chris@101 430 log = false;
Chris@101 431
Chris@296 432 if (shouldAutoAlign()) {
Chris@101 433
Chris@101 434 if (!v->getValueExtents(m_model->getScaleUnits(), min, max, log)) {
Chris@101 435 min = m_model->getValueMinimum();
Chris@101 436 max = m_model->getValueMaximum();
Chris@101 437 } else if (log) {
Chris@197 438 LogRange::mapRange(min, max);
Chris@101 439 }
Chris@101 440
Chris@101 441 } else if (m_verticalScale == PlusMinusOneScale) {
Chris@101 442
Chris@101 443 min = -1.0;
Chris@101 444 max = 1.0;
Chris@101 445
Chris@101 446 } else {
Chris@101 447
Chris@101 448 min = m_model->getValueMinimum();
Chris@101 449 max = m_model->getValueMaximum();
Chris@101 450
Chris@101 451 if (m_verticalScale == LogScale) {
Chris@197 452 LogRange::mapRange(min, max);
Chris@101 453 log = true;
Chris@101 454 }
Chris@101 455 }
Chris@101 456
Chris@101 457 if (max == min) max = min + 1.0;
Chris@101 458 }
Chris@101 459
Chris@21 460 int
Chris@66 461 TimeValueLayer::getYForValue(View *v, float val) const
Chris@21 462 {
Chris@79 463 float min = 0.0, max = 0.0;
Chris@101 464 bool logarithmic = false;
Chris@79 465 int h = v->height();
Chris@79 466
Chris@101 467 getScaleExtents(v, min, max, logarithmic);
Chris@101 468
Chris@101 469 // std::cerr << "getYForValue(" << val << "): min " << min << ", max "
Chris@101 470 // << max << ", log " << logarithmic << std::endl;
Chris@101 471
Chris@101 472 if (logarithmic) {
Chris@197 473 val = LogRange::map(val);
Chris@79 474 }
Chris@79 475
Chris@66 476 return int(h - ((val - min) * h) / (max - min));
Chris@21 477 }
Chris@21 478
Chris@21 479 float
Chris@44 480 TimeValueLayer::getValueForY(View *v, int y) const
Chris@21 481 {
Chris@101 482 float min = 0.0, max = 0.0;
Chris@101 483 bool logarithmic = false;
Chris@44 484 int h = v->height();
Chris@21 485
Chris@101 486 getScaleExtents(v, min, max, logarithmic);
Chris@101 487
Chris@101 488 float val = min + (float(h - y) * float(max - min)) / h;
Chris@101 489
Chris@101 490 if (logarithmic) {
Chris@197 491 val = powf(10.f, val);
Chris@101 492 }
Chris@101 493
Chris@101 494 return val;
Chris@21 495 }
Chris@21 496
Chris@296 497 bool
Chris@296 498 TimeValueLayer::shouldAutoAlign() const
Chris@296 499 {
Chris@296 500 if (!m_model) return false;
Chris@296 501 QString unit = m_model->getScaleUnits();
Chris@296 502 return (m_verticalScale == AutoAlignScale && unit != "");
Chris@296 503 }
Chris@296 504
Chris@68 505 QColor
Chris@101 506 TimeValueLayer::getColourForValue(View *v, float val) const
Chris@68 507 {
Chris@101 508 float min, max;
Chris@101 509 bool log;
Chris@101 510 getScaleExtents(v, min, max, log);
Chris@68 511
Chris@197 512 if (min > max) std::swap(min, max);
Chris@197 513 if (max == min) max = min + 1;
Chris@197 514
Chris@101 515 if (log) {
Chris@197 516 LogRange::mapRange(min, max);
Chris@197 517 val = LogRange::map(val);
Chris@68 518 }
Chris@68 519
Chris@197 520 // std::cerr << "TimeValueLayer::getColourForValue: min " << min << ", max "
Chris@197 521 // << max << ", log " << log << ", value " << val << std::endl;
Chris@68 522
Chris@197 523 QColor solid = ColourMapper(m_colourMap, min, max).map(val);
Chris@197 524 return QColor(solid.red(), solid.green(), solid.blue(), 120);
Chris@68 525 }
Chris@68 526
Chris@287 527 int
Chris@287 528 TimeValueLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@287 529 {
Chris@287 530 impose = false;
Chris@287 531 return ColourDatabase::getInstance()->getColourIndex
Chris@287 532 (QString(darkbg ? "Bright Green" : "Green"));
Chris@287 533 }
Chris@287 534
Chris@0 535 void
Chris@44 536 TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@0 537 {
Chris@0 538 if (!m_model || !m_model->isOK()) return;
Chris@0 539
Chris@0 540 int sampleRate = m_model->getSampleRate();
Chris@0 541 if (!sampleRate) return;
Chris@0 542
Chris@0 543 // Profiler profiler("TimeValueLayer::paint", true);
Chris@0 544
Chris@0 545 int x0 = rect.left(), x1 = rect.right();
Chris@44 546 long frame0 = v->getFrameForX(x0);
Chris@44 547 long frame1 = v->getFrameForX(x1);
Chris@0 548
Chris@0 549 SparseTimeValueModel::PointList points(m_model->getPoints
Chris@0 550 (frame0, frame1));
Chris@11 551 if (points.empty()) return;
Chris@0 552
Chris@287 553 paint.setPen(getBaseQColor());
Chris@0 554
Chris@287 555 QColor brushColour(getBaseQColor());
Chris@0 556 brushColour.setAlpha(80);
Chris@0 557 paint.setBrush(brushColour);
Chris@0 558
Chris@0 559 // std::cerr << "TimeValueLayer::paint: resolution is "
Chris@0 560 // << m_model->getResolution() << " frames" << std::endl;
Chris@0 561
Chris@0 562 float min = m_model->getValueMinimum();
Chris@0 563 float max = m_model->getValueMaximum();
Chris@0 564 if (max == min) max = min + 1.0;
Chris@0 565
Chris@44 566 int origin = int(nearbyint(v->height() -
Chris@44 567 (-min * v->height()) / (max - min)));
Chris@0 568
Chris@0 569 QPoint localPos;
Chris@0 570 long illuminateFrame = -1;
Chris@0 571
Chris@44 572 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@0 573 SparseTimeValueModel::PointList localPoints =
Chris@44 574 getLocalPoints(v, localPos.x());
Chris@296 575 // std::cerr << "TimeValueLayer: " << localPoints.size() << " local points" << std::endl;
Chris@0 576 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
Chris@0 577 }
Chris@6 578
Chris@20 579 int w =
Chris@44 580 v->getXForFrame(frame0 + m_model->getResolution()) -
Chris@44 581 v->getXForFrame(frame0);
Chris@7 582
Chris@6 583 paint.save();
Chris@6 584
Chris@6 585 QPainterPath path;
Chris@55 586 int pointCount = 0;
Chris@79 587
Chris@79 588 int textY = 0;
Chris@79 589 if (m_plotStyle == PlotSegmentation) {
Chris@79 590 textY = v->getTextLabelHeight(this, paint);
Chris@79 591 }
Chris@6 592
Chris@0 593 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@0 594 i != points.end(); ++i) {
Chris@0 595
Chris@0 596 const SparseTimeValueModel::Point &p(*i);
Chris@0 597
Chris@44 598 int x = v->getXForFrame(p.frame);
Chris@44 599 int y = getYForValue(v, p.value);
Chris@0 600
Chris@79 601 if (m_plotStyle != PlotSegmentation) {
Chris@79 602 textY = y - paint.fontMetrics().height()
Chris@79 603 + paint.fontMetrics().ascent();
Chris@79 604 }
Chris@79 605
Chris@34 606 bool haveNext = false;
Chris@76 607 int nx = v->getXForFrame(v->getModelsEndFrame());
Chris@76 608 // m_model->getEndFrame());
Chris@34 609 int ny = y;
Chris@34 610
Chris@34 611 SparseTimeValueModel::PointList::const_iterator j = i;
Chris@34 612 ++j;
Chris@34 613
Chris@34 614 if (j != points.end()) {
Chris@34 615 const SparseTimeValueModel::Point &q(*j);
Chris@44 616 nx = v->getXForFrame(q.frame);
Chris@44 617 ny = getYForValue(v, q.value);
Chris@34 618 haveNext = true;
Chris@76 619 }
Chris@76 620
Chris@76 621 // std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext
Chris@76 622 // << ", nx = " << nx << std::endl;
Chris@34 623
Chris@34 624 int labelY = y;
Chris@34 625
Chris@0 626 if (w < 1) w = 1;
Chris@287 627 paint.setPen(getBaseQColor());
Chris@0 628
Chris@26 629 if (m_plotStyle == PlotSegmentation) {
Chris@287 630 paint.setPen(getForegroundQColor(v));
Chris@101 631 paint.setBrush(getColourForValue(v, p.value));
Chris@44 632 labelY = v->height();
Chris@26 633 } else if (m_plotStyle == PlotLines ||
Chris@26 634 m_plotStyle == PlotCurve) {
Chris@6 635 paint.setBrush(Qt::NoBrush);
Chris@3 636 } else {
Chris@6 637 paint.setBrush(brushColour);
Chris@3 638 }
Chris@0 639
Chris@0 640 if (m_plotStyle == PlotStems) {
Chris@0 641 paint.setPen(brushColour);
Chris@0 642 if (y < origin - 1) {
Chris@0 643 paint.drawRect(x + w/2, y + 1, 1, origin - y);
Chris@0 644 } else if (y > origin + 1) {
Chris@0 645 paint.drawRect(x + w/2, origin, 1, y - origin - 1);
Chris@0 646 }
Chris@287 647 paint.setPen(getBaseQColor());
Chris@0 648 }
Chris@0 649
Chris@0 650 if (illuminateFrame == p.frame) {
Chris@6 651
Chris@0 652 //!!! aside from the problem of choosing a colour, it'd be
Chris@0 653 //better to save the highlighted rects and draw them at
Chris@0 654 //the end perhaps
Chris@6 655
Chris@6 656 //!!! not equipped to illuminate the right section in line
Chris@6 657 //or curve mode
Chris@6 658
Chris@6 659 if (m_plotStyle != PlotCurve &&
Chris@6 660 m_plotStyle != PlotLines) {
Chris@287 661 paint.setPen(getForegroundQColor(v));
Chris@6 662 }
Chris@0 663 }
Chris@0 664
Chris@6 665 if (m_plotStyle != PlotLines &&
Chris@26 666 m_plotStyle != PlotCurve &&
Chris@26 667 m_plotStyle != PlotSegmentation) {
Chris@326 668 if (m_plotStyle != PlotStems ||
Chris@326 669 w > 1) {
Chris@326 670 paint.drawRect(x, y - 1, w, 2);
Chris@326 671 }
Chris@3 672 }
Chris@0 673
Chris@6 674 if (m_plotStyle == PlotConnectedPoints ||
Chris@6 675 m_plotStyle == PlotLines ||
Chris@6 676 m_plotStyle == PlotCurve) {
Chris@0 677
Chris@34 678 if (haveNext) {
Chris@3 679
Chris@6 680 if (m_plotStyle == PlotConnectedPoints) {
Chris@34 681
Chris@79 682 paint.save();
Chris@3 683 paint.setPen(brushColour);
Chris@3 684 paint.drawLine(x + w, y, nx, ny);
Chris@79 685 paint.restore();
Chris@6 686
Chris@6 687 } else if (m_plotStyle == PlotLines) {
Chris@6 688
Chris@6 689 paint.drawLine(x + w/2, y, nx + w/2, ny);
Chris@6 690
Chris@3 691 } else {
Chris@6 692
Chris@55 693 float x0 = x + float(w)/2;
Chris@55 694 float x1 = nx + float(w)/2;
Chris@55 695
Chris@55 696 float y0 = y;
Chris@55 697 float y1 = ny;
Chris@55 698
Chris@55 699 if (pointCount == 0) {
Chris@55 700 path.moveTo((x0 + x1) / 2, (y0 + y1) / 2);
Chris@6 701 }
Chris@55 702 ++pointCount;
Chris@6 703
Chris@6 704 if (nx - x > 5) {
Chris@55 705 path.cubicTo(x0, y0,
Chris@55 706 x0, y0,
Chris@55 707 (x0 + x1) / 2, (y0 + y1) / 2);
Chris@55 708
Chris@55 709 // // or
Chris@55 710 // path.quadTo(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
Chris@55 711
Chris@6 712 } else {
Chris@55 713 path.lineTo((x0 + x1) / 2, (y0 + y1) / 2);
Chris@6 714 }
Chris@3 715 }
Chris@0 716 }
Chris@0 717 }
Chris@0 718
Chris@26 719 if (m_plotStyle == PlotSegmentation) {
Chris@76 720
Chris@76 721 // std::cerr << "drawing rect" << std::endl;
Chris@26 722
Chris@27 723 if (nx <= x) continue;
Chris@26 724
Chris@28 725 if (illuminateFrame != p.frame &&
Chris@44 726 (nx < x + 5 || x >= v->width() - 1)) {
Chris@27 727 paint.setPen(Qt::NoPen);
Chris@27 728 }
Chris@26 729
Chris@44 730 paint.drawRect(x, -1, nx - x, v->height() + 1);
Chris@26 731 }
Chris@26 732
Chris@55 733 if (p.label != "") {
Chris@79 734 if (!haveNext || nx > x + 6 + paint.fontMetrics().width(p.label)) {
Chris@79 735 paint.drawText(x + 5, textY, p.label);
Chris@79 736 }
Chris@55 737 }
Chris@0 738 }
Chris@6 739
Chris@6 740 if (m_plotStyle == PlotCurve && !path.isEmpty()) {
Chris@55 741 paint.setRenderHint(QPainter::Antialiasing, pointCount <= v->width());
Chris@6 742 paint.drawPath(path);
Chris@6 743 }
Chris@6 744
Chris@6 745 paint.restore();
Chris@6 746
Chris@6 747 // looks like save/restore doesn't deal with this:
Chris@6 748 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@6 749 }
Chris@6 750
Chris@42 751 int
Chris@248 752 TimeValueLayer::getVerticalScaleWidth(View *, QPainter &paint) const
Chris@42 753 {
Chris@68 754 int w = paint.fontMetrics().width("-000.000");
Chris@68 755 if (m_plotStyle == PlotSegmentation) return w + 20;
Chris@68 756 else return w + 10;
Chris@42 757 }
Chris@42 758
Chris@42 759 void
Chris@248 760 TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect) const
Chris@42 761 {
Chris@42 762 if (!m_model) return;
Chris@42 763
Chris@68 764 int h = v->height();
Chris@68 765
Chris@68 766 int n = 10;
Chris@68 767
Chris@68 768 float max = m_model->getValueMaximum();
Chris@68 769 float min = m_model->getValueMinimum();
Chris@68 770 float val = min;
Chris@68 771 float inc = (max - val) / n;
Chris@42 772
Chris@55 773 char buffer[40];
Chris@55 774
Chris@55 775 int w = getVerticalScaleWidth(v, paint);
Chris@55 776
Chris@68 777 int tx = 5;
Chris@68 778
Chris@68 779 int boxx = 5, boxy = 5;
Chris@68 780 if (m_model->getScaleUnits() != "") {
Chris@68 781 boxy += paint.fontMetrics().height();
Chris@68 782 }
Chris@68 783 int boxw = 10, boxh = h - boxy - 5;
Chris@68 784
Chris@68 785 if (m_plotStyle == PlotSegmentation) {
Chris@68 786 tx += boxx + boxw;
Chris@68 787 paint.drawRect(boxx, boxy, boxw, boxh);
Chris@68 788 }
Chris@68 789
Chris@68 790 if (m_plotStyle == PlotSegmentation) {
Chris@68 791 paint.save();
Chris@68 792 for (int y = 0; y < boxh; ++y) {
Chris@68 793 float val = ((boxh - y) * (max - min)) / boxh + min;
Chris@101 794 paint.setPen(getColourForValue(v, val));
Chris@68 795 paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1);
Chris@68 796 }
Chris@68 797 paint.restore();
Chris@68 798 }
Chris@68 799
Chris@68 800 for (int i = 0; i < n; ++i) {
Chris@68 801
Chris@68 802 int y, ty;
Chris@68 803 bool drawText = true;
Chris@68 804
Chris@68 805 if (m_plotStyle == PlotSegmentation) {
Chris@68 806 y = boxy + int(boxh - ((val - min) * boxh) / (max - min));
Chris@68 807 ty = y;
Chris@68 808 } else {
Chris@68 809 if (i == n-1) {
Chris@68 810 if (m_model->getScaleUnits() != "") drawText = false;
Chris@68 811 }
Chris@68 812 y = getYForValue(v, val);
Chris@68 813 ty = y - paint.fontMetrics().height() +
Chris@68 814 paint.fontMetrics().ascent();
Chris@68 815 }
Chris@68 816
Chris@68 817 sprintf(buffer, "%.3f", val);
Chris@55 818 QString label = QString(buffer);
Chris@68 819
Chris@68 820 if (m_plotStyle != PlotSegmentation) {
Chris@68 821 paint.drawLine(w - 5, y, w, y);
Chris@68 822 } else {
Chris@68 823 paint.drawLine(boxx + boxw - boxw/3, y, boxx + boxw, y);
Chris@68 824 }
Chris@68 825
Chris@68 826 if (drawText) paint.drawText(tx, ty, label);
Chris@44 827 val += inc;
Chris@42 828 }
Chris@68 829
Chris@67 830 if (m_model->getScaleUnits() != "") {
Chris@67 831 paint.drawText(5, 5 + paint.fontMetrics().ascent(),
Chris@67 832 m_model->getScaleUnits());
Chris@67 833 }
Chris@42 834 }
Chris@42 835
Chris@21 836 void
Chris@44 837 TimeValueLayer::drawStart(View *v, QMouseEvent *e)
Chris@21 838 {
Chris@101 839 // std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 840
Chris@21 841 if (!m_model) return;
Chris@21 842
Chris@44 843 long frame = v->getFrameForX(e->x());
Chris@76 844 long resolution = m_model->getResolution();
Chris@21 845 if (frame < 0) frame = 0;
Chris@76 846 frame = (frame / resolution) * resolution;
Chris@21 847
Chris@44 848 float value = getValueForY(v, e->y());
Chris@21 849
Chris@76 850 bool havePoint = false;
Chris@76 851
Chris@76 852 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@76 853 if (!points.empty()) {
Chris@76 854 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@76 855 i != points.end(); ++i) {
Chris@76 856 if (((i->frame / resolution) * resolution) != frame) {
Chris@101 857 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
Chris@76 858 continue;
Chris@76 859 }
Chris@76 860 m_editingPoint = *i;
Chris@76 861 havePoint = true;
Chris@76 862 }
Chris@76 863 }
Chris@76 864
Chris@76 865 if (!havePoint) {
Chris@76 866 m_editingPoint = SparseTimeValueModel::Point
Chris@76 867 (frame, value, tr("New Point"));
Chris@76 868 }
Chris@76 869
Chris@23 870 m_originalPoint = m_editingPoint;
Chris@22 871
Chris@22 872 if (m_editingCommand) m_editingCommand->finish();
Chris@22 873 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
Chris@22 874 tr("Draw Point"));
Chris@76 875 if (!havePoint) {
Chris@76 876 m_editingCommand->addPoint(m_editingPoint);
Chris@76 877 }
Chris@22 878
Chris@21 879 m_editing = true;
Chris@21 880 }
Chris@21 881
Chris@21 882 void
Chris@44 883 TimeValueLayer::drawDrag(View *v, QMouseEvent *e)
Chris@21 884 {
Chris@101 885 // std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 886
Chris@21 887 if (!m_model || !m_editing) return;
Chris@21 888
Chris@44 889 long frame = v->getFrameForX(e->x());
Chris@76 890 long resolution = m_model->getResolution();
Chris@21 891 if (frame < 0) frame = 0;
Chris@76 892 frame = (frame / resolution) * resolution;
Chris@21 893
Chris@44 894 float value = getValueForY(v, e->y());
Chris@21 895
Chris@76 896 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@76 897
Chris@101 898 // std::cerr << points.size() << " points" << std::endl;
Chris@76 899
Chris@76 900 bool havePoint = false;
Chris@76 901
Chris@76 902 if (!points.empty()) {
Chris@76 903 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@76 904 i != points.end(); ++i) {
Chris@76 905 if (i->frame == m_editingPoint.frame &&
Chris@76 906 i->value == m_editingPoint.value) {
Chris@101 907 // std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl;
Chris@76 908 continue;
Chris@76 909 }
Chris@76 910 if (((i->frame / resolution) * resolution) != frame) {
Chris@101 911 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
Chris@76 912 continue;
Chris@76 913 }
Chris@101 914 // std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl;
Chris@76 915 m_editingPoint = *i;
Chris@76 916 m_originalPoint = m_editingPoint;
Chris@76 917 m_editingCommand->deletePoint(m_editingPoint);
Chris@76 918 havePoint = true;
Chris@76 919 }
Chris@76 920 }
Chris@76 921
Chris@76 922 if (!havePoint) {
Chris@76 923 if (frame == m_editingPoint.frame) {
Chris@76 924 m_editingCommand->deletePoint(m_editingPoint);
Chris@76 925 }
Chris@76 926 }
Chris@76 927
Chris@76 928 // m_editingCommand->deletePoint(m_editingPoint);
Chris@21 929 m_editingPoint.frame = frame;
Chris@21 930 m_editingPoint.value = value;
Chris@22 931 m_editingCommand->addPoint(m_editingPoint);
Chris@21 932 }
Chris@21 933
Chris@21 934 void
Chris@248 935 TimeValueLayer::drawEnd(View *, QMouseEvent *)
Chris@21 936 {
Chris@101 937 // std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 938 if (!m_model || !m_editing) return;
Chris@22 939 m_editingCommand->finish();
Chris@22 940 m_editingCommand = 0;
Chris@21 941 m_editing = false;
Chris@21 942 }
Chris@21 943
Chris@21 944 void
Chris@335 945 TimeValueLayer::eraseStart(View *v, QMouseEvent *e)
Chris@335 946 {
Chris@335 947 if (!m_model) return;
Chris@335 948
Chris@335 949 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@335 950 if (points.empty()) return;
Chris@335 951
Chris@335 952 m_editingPoint = *points.begin();
Chris@335 953
Chris@335 954 if (m_editingCommand) {
Chris@335 955 m_editingCommand->finish();
Chris@335 956 m_editingCommand = 0;
Chris@335 957 }
Chris@335 958
Chris@335 959 m_editing = true;
Chris@335 960 }
Chris@335 961
Chris@335 962 void
Chris@335 963 TimeValueLayer::eraseDrag(View *v, QMouseEvent *e)
Chris@335 964 {
Chris@335 965 }
Chris@335 966
Chris@335 967 void
Chris@335 968 TimeValueLayer::eraseEnd(View *v, QMouseEvent *e)
Chris@335 969 {
Chris@335 970 if (!m_model || !m_editing) return;
Chris@335 971
Chris@335 972 m_editing = false;
Chris@335 973
Chris@335 974 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@335 975 if (points.empty()) return;
Chris@335 976 if (points.begin()->frame != m_editingPoint.frame ||
Chris@335 977 points.begin()->value != m_editingPoint.value) return;
Chris@335 978
Chris@335 979 m_editingCommand = new SparseTimeValueModel::EditCommand
Chris@335 980 (m_model, tr("Erase Point"));
Chris@335 981
Chris@335 982 m_editingCommand->deletePoint(m_editingPoint);
Chris@335 983
Chris@335 984 m_editingCommand->finish();
Chris@335 985 m_editingCommand = 0;
Chris@335 986 m_editing = false;
Chris@335 987 }
Chris@335 988
Chris@335 989 void
Chris@44 990 TimeValueLayer::editStart(View *v, QMouseEvent *e)
Chris@21 991 {
Chris@101 992 // std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 993
Chris@21 994 if (!m_model) return;
Chris@21 995
Chris@44 996 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@21 997 if (points.empty()) return;
Chris@21 998
Chris@21 999 m_editingPoint = *points.begin();
Chris@23 1000 m_originalPoint = m_editingPoint;
Chris@22 1001
Chris@22 1002 if (m_editingCommand) {
Chris@22 1003 m_editingCommand->finish();
Chris@22 1004 m_editingCommand = 0;
Chris@22 1005 }
Chris@22 1006
Chris@21 1007 m_editing = true;
Chris@21 1008 }
Chris@21 1009
Chris@21 1010 void
Chris@44 1011 TimeValueLayer::editDrag(View *v, QMouseEvent *e)
Chris@21 1012 {
Chris@101 1013 // std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 1014
Chris@21 1015 if (!m_model || !m_editing) return;
Chris@21 1016
Chris@44 1017 long frame = v->getFrameForX(e->x());
Chris@21 1018 if (frame < 0) frame = 0;
Chris@21 1019 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@21 1020
Chris@44 1021 float value = getValueForY(v, e->y());
Chris@21 1022
Chris@22 1023 if (!m_editingCommand) {
Chris@22 1024 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
Chris@22 1025 tr("Drag Point"));
Chris@22 1026 }
Chris@22 1027
Chris@22 1028 m_editingCommand->deletePoint(m_editingPoint);
Chris@21 1029 m_editingPoint.frame = frame;
Chris@21 1030 m_editingPoint.value = value;
Chris@22 1031 m_editingCommand->addPoint(m_editingPoint);
Chris@21 1032 }
Chris@21 1033
Chris@21 1034 void
Chris@248 1035 TimeValueLayer::editEnd(View *, QMouseEvent *)
Chris@21 1036 {
Chris@101 1037 // std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 1038 if (!m_model || !m_editing) return;
Chris@23 1039
Chris@23 1040 if (m_editingCommand) {
Chris@23 1041
Chris@23 1042 QString newName = m_editingCommand->getName();
Chris@23 1043
Chris@23 1044 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@23 1045 if (m_editingPoint.value != m_originalPoint.value) {
Chris@23 1046 newName = tr("Edit Point");
Chris@23 1047 } else {
Chris@23 1048 newName = tr("Relocate Point");
Chris@23 1049 }
Chris@23 1050 } else {
Chris@23 1051 newName = tr("Change Point Value");
Chris@23 1052 }
Chris@23 1053
Chris@23 1054 m_editingCommand->setName(newName);
Chris@23 1055 m_editingCommand->finish();
Chris@23 1056 }
Chris@23 1057
Chris@22 1058 m_editingCommand = 0;
Chris@21 1059 m_editing = false;
Chris@21 1060 }
Chris@21 1061
Chris@255 1062 bool
Chris@70 1063 TimeValueLayer::editOpen(View *v, QMouseEvent *e)
Chris@70 1064 {
Chris@255 1065 if (!m_model) return false;
Chris@70 1066
Chris@70 1067 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
Chris@255 1068 if (points.empty()) return false;
Chris@70 1069
Chris@70 1070 SparseTimeValueModel::Point point = *points.begin();
Chris@70 1071
Chris@70 1072 ItemEditDialog *dialog = new ItemEditDialog
Chris@70 1073 (m_model->getSampleRate(),
Chris@70 1074 ItemEditDialog::ShowTime |
Chris@70 1075 ItemEditDialog::ShowValue |
Chris@73 1076 ItemEditDialog::ShowText,
Chris@73 1077 m_model->getScaleUnits());
Chris@70 1078
Chris@70 1079 dialog->setFrameTime(point.frame);
Chris@70 1080 dialog->setValue(point.value);
Chris@70 1081 dialog->setText(point.label);
Chris@70 1082
Chris@70 1083 if (dialog->exec() == QDialog::Accepted) {
Chris@70 1084
Chris@70 1085 SparseTimeValueModel::Point newPoint = point;
Chris@70 1086 newPoint.frame = dialog->getFrameTime();
Chris@70 1087 newPoint.value = dialog->getValue();
Chris@70 1088 newPoint.label = dialog->getText();
Chris@70 1089
Chris@70 1090 SparseTimeValueModel::EditCommand *command =
Chris@70 1091 new SparseTimeValueModel::EditCommand(m_model, tr("Edit Point"));
Chris@70 1092 command->deletePoint(point);
Chris@70 1093 command->addPoint(newPoint);
Chris@70 1094 command->finish();
Chris@70 1095 }
Chris@70 1096
Chris@70 1097 delete dialog;
Chris@255 1098 return true;
Chris@70 1099 }
Chris@70 1100
Chris@70 1101 void
Chris@43 1102 TimeValueLayer::moveSelection(Selection s, size_t newStartFrame)
Chris@43 1103 {
Chris@99 1104 if (!m_model) return;
Chris@99 1105
Chris@43 1106 SparseTimeValueModel::EditCommand *command =
Chris@43 1107 new SparseTimeValueModel::EditCommand(m_model,
Chris@43 1108 tr("Drag Selection"));
Chris@43 1109
Chris@43 1110 SparseTimeValueModel::PointList points =
Chris@43 1111 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 1112
Chris@43 1113 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@43 1114 i != points.end(); ++i) {
Chris@43 1115
Chris@43 1116 if (s.contains(i->frame)) {
Chris@43 1117 SparseTimeValueModel::Point newPoint(*i);
Chris@43 1118 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@43 1119 command->deletePoint(*i);
Chris@43 1120 command->addPoint(newPoint);
Chris@43 1121 }
Chris@43 1122 }
Chris@43 1123
Chris@43 1124 command->finish();
Chris@43 1125 }
Chris@43 1126
Chris@43 1127 void
Chris@43 1128 TimeValueLayer::resizeSelection(Selection s, Selection newSize)
Chris@43 1129 {
Chris@99 1130 if (!m_model) return;
Chris@99 1131
Chris@43 1132 SparseTimeValueModel::EditCommand *command =
Chris@43 1133 new SparseTimeValueModel::EditCommand(m_model,
Chris@43 1134 tr("Resize Selection"));
Chris@43 1135
Chris@43 1136 SparseTimeValueModel::PointList points =
Chris@43 1137 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 1138
Chris@43 1139 double ratio =
Chris@43 1140 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@43 1141 double(s.getEndFrame() - s.getStartFrame());
Chris@43 1142
Chris@43 1143 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@43 1144 i != points.end(); ++i) {
Chris@43 1145
Chris@43 1146 if (s.contains(i->frame)) {
Chris@43 1147
Chris@43 1148 double target = i->frame;
Chris@43 1149 target = newSize.getStartFrame() +
Chris@43 1150 double(target - s.getStartFrame()) * ratio;
Chris@43 1151
Chris@43 1152 SparseTimeValueModel::Point newPoint(*i);
Chris@43 1153 newPoint.frame = lrint(target);
Chris@43 1154 command->deletePoint(*i);
Chris@43 1155 command->addPoint(newPoint);
Chris@43 1156 }
Chris@43 1157 }
Chris@43 1158
Chris@43 1159 command->finish();
Chris@43 1160 }
Chris@43 1161
Chris@76 1162 void
Chris@76 1163 TimeValueLayer::deleteSelection(Selection s)
Chris@76 1164 {
Chris@99 1165 if (!m_model) return;
Chris@99 1166
Chris@76 1167 SparseTimeValueModel::EditCommand *command =
Chris@76 1168 new SparseTimeValueModel::EditCommand(m_model,
Chris@76 1169 tr("Delete Selected Points"));
Chris@76 1170
Chris@76 1171 SparseTimeValueModel::PointList points =
Chris@76 1172 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 1173
Chris@76 1174 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@76 1175 i != points.end(); ++i) {
Chris@76 1176
Chris@76 1177 if (s.contains(i->frame)) {
Chris@76 1178 command->deletePoint(*i);
Chris@76 1179 }
Chris@76 1180 }
Chris@76 1181
Chris@76 1182 command->finish();
Chris@76 1183 }
Chris@76 1184
Chris@76 1185 void
Chris@76 1186 TimeValueLayer::copy(Selection s, Clipboard &to)
Chris@76 1187 {
Chris@99 1188 if (!m_model) return;
Chris@99 1189
Chris@76 1190 SparseTimeValueModel::PointList points =
Chris@76 1191 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 1192
Chris@76 1193 for (SparseTimeValueModel::PointList::iterator i = points.begin();
Chris@76 1194 i != points.end(); ++i) {
Chris@76 1195 if (s.contains(i->frame)) {
Chris@83 1196 Clipboard::Point point(i->frame, i->value, i->label);
Chris@335 1197 point.setReferenceFrame(m_model->alignToReference(i->frame));
Chris@76 1198 to.addPoint(point);
Chris@76 1199 }
Chris@76 1200 }
Chris@76 1201 }
Chris@76 1202
Chris@125 1203 bool
Chris@125 1204 TimeValueLayer::paste(const Clipboard &from, int frameOffset,
Chris@125 1205 bool interactive)
Chris@76 1206 {
Chris@125 1207 if (!m_model) return false;
Chris@99 1208
Chris@76 1209 const Clipboard::PointList &points = from.getPoints();
Chris@76 1210
Chris@76 1211 SparseTimeValueModel::EditCommand *command =
Chris@76 1212 new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
Chris@76 1213
Chris@125 1214 enum ValueAvailability {
Chris@125 1215 UnknownAvailability,
Chris@125 1216 NoValues,
Chris@125 1217 SomeValues,
Chris@125 1218 AllValues
Chris@125 1219 };
Chris@125 1220
Chris@340 1221 Labeller::ValueType generation = Labeller::ValueNone;
Chris@125 1222
Chris@125 1223 bool haveUsableLabels = false;
Chris@125 1224 bool haveExistingItems = !(m_model->isEmpty());
Chris@340 1225 Labeller labeller;
Chris@340 1226 labeller.setSampleRate(m_model->getSampleRate());
Chris@125 1227
Chris@125 1228 if (interactive) {
Chris@125 1229
Chris@125 1230 ValueAvailability availability = UnknownAvailability;
Chris@125 1231
Chris@125 1232 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@125 1233 i != points.end(); ++i) {
Chris@125 1234
Chris@125 1235 if (!i->haveFrame()) continue;
Chris@125 1236
Chris@125 1237 if (availability == UnknownAvailability) {
Chris@125 1238 if (i->haveValue()) availability = AllValues;
Chris@125 1239 else availability = NoValues;
Chris@125 1240 continue;
Chris@125 1241 }
Chris@125 1242
Chris@125 1243 if (i->haveValue()) {
Chris@125 1244 if (availability == NoValues) {
Chris@125 1245 availability = SomeValues;
Chris@125 1246 }
Chris@125 1247 } else {
Chris@125 1248 if (availability == AllValues) {
Chris@125 1249 availability = SomeValues;
Chris@125 1250 }
Chris@125 1251 }
Chris@125 1252
Chris@125 1253 if (!haveUsableLabels) {
Chris@125 1254 if (i->haveLabel()) {
Chris@125 1255 if (i->getLabel().contains(QRegExp("[0-9]"))) {
Chris@125 1256 haveUsableLabels = true;
Chris@125 1257 }
Chris@125 1258 }
Chris@125 1259 }
Chris@125 1260
Chris@125 1261 if (availability == SomeValues && haveUsableLabels) break;
Chris@125 1262 }
Chris@125 1263
Chris@125 1264 if (availability == NoValues || availability == SomeValues) {
Chris@125 1265
Chris@125 1266 QString text;
Chris@125 1267 if (availability == NoValues) {
Chris@125 1268 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
Chris@125 1269 } else {
Chris@125 1270 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
Chris@125 1271 }
Chris@125 1272
Chris@340 1273 Labeller::TypeNameMap names = labeller.getTypeNames();
Chris@340 1274
Chris@125 1275 QStringList options;
Chris@340 1276 std::vector<Labeller::ValueType> genopts;
Chris@125 1277
Chris@340 1278 for (Labeller::TypeNameMap::const_iterator i = names.begin();
Chris@340 1279 i != names.end(); ++i) {
Chris@340 1280 if (i->first == Labeller::ValueNone) options << tr("Zero for all items");
Chris@340 1281 else options << i->second;
Chris@340 1282 genopts.push_back(i->first);
Chris@125 1283 }
Chris@125 1284
Chris@125 1285 static int prevSelection = 0;
Chris@125 1286
Chris@125 1287 bool ok = false;
Chris@125 1288 QString selected = ListInputDialog::getItem
Chris@125 1289 (0, tr("Choose value calculation"),
Chris@125 1290 text, options, prevSelection, &ok);
Chris@125 1291
Chris@125 1292 if (!ok) return false;
Chris@125 1293 int selection = 0;
Chris@340 1294 generation = Labeller::ValueNone;
Chris@125 1295
Chris@125 1296 for (QStringList::const_iterator i = options.begin();
Chris@125 1297 i != options.end(); ++i) {
Chris@125 1298 if (selected == *i) {
Chris@340 1299 generation = genopts[selection];
Chris@125 1300 break;
Chris@125 1301 }
Chris@125 1302 ++selection;
Chris@125 1303 }
Chris@340 1304
Chris@340 1305 labeller.setType(generation);
Chris@340 1306
Chris@340 1307 if (generation == Labeller::ValueFromCyclicalCounter ||
Chris@340 1308 generation == Labeller::ValueFromTwoLevelCounter) {
Chris@340 1309 int cycleSize = QInputDialog::getInteger
Chris@340 1310 (0, tr("Select cycle size"),
Chris@340 1311 tr("Cycle size:"), 4, 2, 16, 1);
Chris@340 1312 labeller.setCounterCycleSize(cycleSize);
Chris@340 1313 }
Chris@125 1314
Chris@125 1315 prevSelection = selection;
Chris@125 1316 }
Chris@125 1317 }
Chris@125 1318
Chris@340 1319 static SparseTimeValueModel::Point prevPoint(0);
Chris@125 1320
Chris@76 1321 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@76 1322 i != points.end(); ++i) {
Chris@76 1323
Chris@76 1324 if (!i->haveFrame()) continue;
Chris@76 1325 size_t frame = 0;
Chris@76 1326 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
Chris@76 1327 frame = i->getFrame() + frameOffset;
Chris@76 1328 }
Chris@76 1329 SparseTimeValueModel::Point newPoint(frame);
Chris@76 1330
Chris@125 1331 if (i->haveLabel()) {
Chris@125 1332 newPoint.label = i->getLabel();
Chris@125 1333 } else if (i->haveValue()) {
Chris@125 1334 newPoint.label = QString("%1").arg(i->getValue());
Chris@125 1335 }
Chris@125 1336
Chris@125 1337 if (i->haveValue()) {
Chris@125 1338 newPoint.value = i->getValue();
Chris@125 1339 } else {
Chris@340 1340 labeller.setValue<SparseTimeValueModel::Point>
Chris@340 1341 (newPoint, i == points.begin() ? 0 : &prevPoint);
Chris@340 1342 }
Chris@125 1343
Chris@340 1344 prevPoint = newPoint;
Chris@76 1345 command->addPoint(newPoint);
Chris@76 1346 }
Chris@76 1347
Chris@76 1348 command->finish();
Chris@125 1349 return true;
Chris@340 1350 }
Chris@76 1351
Chris@316 1352 void
Chris@316 1353 TimeValueLayer::toXml(QTextStream &stream,
Chris@316 1354 QString indent, QString extraAttributes) const
Chris@6 1355 {
Chris@316 1356 SingleColourLayer::toXml(stream, indent,
Chris@316 1357 extraAttributes +
Chris@316 1358 QString(" colourMap=\"%1\" plotStyle=\"%2\" verticalScale=\"%3\"")
Chris@316 1359 .arg(m_colourMap)
Chris@316 1360 .arg(m_plotStyle)
Chris@316 1361 .arg(m_verticalScale));
Chris@0 1362 }
Chris@0 1363
Chris@11 1364 void
Chris@11 1365 TimeValueLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 1366 {
Chris@287 1367 SingleColourLayer::setProperties(attributes);
Chris@11 1368
Chris@11 1369 bool ok;
Chris@287 1370
Chris@287 1371 int cmap = attributes.value("colourMap").toInt(&ok);
Chris@287 1372 if (ok) setFillColourMap(cmap);
Chris@287 1373
Chris@11 1374 PlotStyle style = (PlotStyle)
Chris@11 1375 attributes.value("plotStyle").toInt(&ok);
Chris@11 1376 if (ok) setPlotStyle(style);
Chris@286 1377
Chris@286 1378 VerticalScale scale = (VerticalScale)
Chris@286 1379 attributes.value("verticalScale").toInt(&ok);
Chris@286 1380 if (ok) setVerticalScale(scale);
Chris@11 1381 }
Chris@11 1382