annotate layer/TimeValueLayer.cpp @ 607:5b72899d692b

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