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