annotate layer/TimeValueLayer.cpp @ 494:b3140e9e0665

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