annotate layer/TimeValueLayer.cpp @ 640:c6d705bf1672

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