annotate layer/TimeInstantLayer.cpp @ 564:7fb9b939722f

* Add basic build files
author Chris Cannam
date Wed, 22 Sep 2010 11:11:40 +0100
parents 2e8194a30f40
children a4ba6c96b66d
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 "TimeInstantLayer.h"
Chris@0 17
Chris@128 18 #include "data/model/Model.h"
Chris@0 19 #include "base/RealTime.h"
Chris@128 20 #include "view/View.h"
Chris@0 21 #include "base/Profiler.h"
Chris@76 22 #include "base/Clipboard.h"
Chris@376 23 #include "ColourDatabase.h"
Chris@0 24
Chris@128 25 #include "data/model/SparseOneDimensionalModel.h"
Chris@0 26
Chris@70 27 #include "widgets/ItemEditDialog.h"
Chris@358 28 #include "widgets/ListInputDialog.h"
Chris@70 29
Chris@0 30 #include <QPainter>
Chris@17 31 #include <QMouseEvent>
Chris@316 32 #include <QTextStream>
Chris@360 33 #include <QMessageBox>
Chris@0 34
Chris@0 35 #include <iostream>
Martin@46 36 #include <cmath>
Chris@0 37
Chris@429 38 //#define DEBUG_TIME_INSTANT_LAYER 1
Chris@387 39
Chris@44 40 TimeInstantLayer::TimeInstantLayer() :
Chris@287 41 SingleColourLayer(),
Chris@0 42 m_model(0),
Chris@18 43 m_editing(false),
Chris@17 44 m_editingPoint(0, tr("New Point")),
Chris@22 45 m_editingCommand(0),
Chris@28 46 m_plotStyle(PlotInstants)
Chris@0 47 {
Chris@308 48 }
Chris@308 49
Chris@308 50 TimeInstantLayer::~TimeInstantLayer()
Chris@308 51 {
Chris@0 52 }
Chris@0 53
Chris@0 54 void
Chris@0 55 TimeInstantLayer::setModel(SparseOneDimensionalModel *model)
Chris@0 56 {
Chris@0 57 if (m_model == model) return;
Chris@0 58 m_model = model;
Chris@0 59
Chris@320 60 connectSignals(m_model);
Chris@0 61
Chris@387 62 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@0 63 std::cerr << "TimeInstantLayer::setModel(" << model << ")" << std::endl;
Chris@387 64 #endif
Chris@0 65
Chris@494 66 if (m_model && m_model->getRDFTypeURI().endsWith("Segment")) {
Chris@494 67 setPlotStyle(PlotSegmentation);
Chris@494 68 }
Chris@494 69
Chris@0 70 emit modelReplaced();
Chris@0 71 }
Chris@0 72
Chris@0 73 Layer::PropertyList
Chris@0 74 TimeInstantLayer::getProperties() const
Chris@0 75 {
Chris@287 76 PropertyList list = SingleColourLayer::getProperties();
Chris@87 77 list.push_back("Plot Type");
Chris@0 78 return list;
Chris@0 79 }
Chris@0 80
Chris@87 81 QString
Chris@87 82 TimeInstantLayer::getPropertyLabel(const PropertyName &name) const
Chris@87 83 {
Chris@87 84 if (name == "Plot Type") return tr("Plot Type");
Chris@287 85 return SingleColourLayer::getPropertyLabel(name);
Chris@87 86 }
Chris@87 87
Chris@0 88 Layer::PropertyType
Chris@287 89 TimeInstantLayer::getPropertyType(const PropertyName &name) const
Chris@0 90 {
Chris@287 91 if (name == "Plot Type") return ValueProperty;
Chris@287 92 return SingleColourLayer::getPropertyType(name);
Chris@0 93 }
Chris@0 94
Chris@0 95 int
Chris@0 96 TimeInstantLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@216 97 int *min, int *max, int *deflt) const
Chris@0 98 {
Chris@216 99 int val = 0;
Chris@0 100
Chris@287 101 if (name == "Plot Type") {
Chris@28 102
Chris@28 103 if (min) *min = 0;
Chris@28 104 if (max) *max = 1;
Chris@216 105 if (deflt) *deflt = 0;
Chris@28 106
Chris@216 107 val = int(m_plotStyle);
Chris@28 108
Chris@0 109 } else {
Chris@0 110
Chris@287 111 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
Chris@0 112 }
Chris@0 113
Chris@216 114 return val;
Chris@0 115 }
Chris@0 116
Chris@0 117 QString
Chris@0 118 TimeInstantLayer::getPropertyValueLabel(const PropertyName &name,
Chris@287 119 int value) const
Chris@0 120 {
Chris@287 121 if (name == "Plot Type") {
Chris@28 122 switch (value) {
Chris@28 123 default:
Chris@28 124 case 0: return tr("Instants");
Chris@28 125 case 1: return tr("Segmentation");
Chris@28 126 }
Chris@0 127 }
Chris@287 128 return SingleColourLayer::getPropertyValueLabel(name, value);
Chris@0 129 }
Chris@0 130
Chris@0 131 void
Chris@0 132 TimeInstantLayer::setProperty(const PropertyName &name, int value)
Chris@0 133 {
Chris@287 134 if (name == "Plot Type") {
Chris@28 135 setPlotStyle(PlotStyle(value));
Chris@287 136 } else {
Chris@287 137 SingleColourLayer::setProperty(name, value);
Chris@0 138 }
Chris@0 139 }
Chris@0 140
Chris@0 141 void
Chris@28 142 TimeInstantLayer::setPlotStyle(PlotStyle style)
Chris@28 143 {
Chris@28 144 if (m_plotStyle == style) return;
Chris@28 145 m_plotStyle = style;
Chris@28 146 emit layerParametersChanged();
Chris@28 147 }
Chris@28 148
Chris@0 149 bool
Chris@44 150 TimeInstantLayer::isLayerScrollable(const View *v) const
Chris@0 151 {
Chris@0 152 QPoint discard;
Chris@44 153 return !v->shouldIlluminateLocalFeatures(this, discard);
Chris@0 154 }
Chris@0 155
Chris@0 156 SparseOneDimensionalModel::PointList
Chris@44 157 TimeInstantLayer::getLocalPoints(View *v, int x) const
Chris@0 158 {
Chris@28 159 // Return a set of points that all have the same frame number, the
Chris@28 160 // nearest to the given x coordinate, and that are within a
Chris@28 161 // certain fuzz distance of that x coordinate.
Chris@28 162
Chris@0 163 if (!m_model) return SparseOneDimensionalModel::PointList();
Chris@0 164
Chris@44 165 long frame = v->getFrameForX(x);
Chris@0 166
Chris@0 167 SparseOneDimensionalModel::PointList onPoints =
Chris@0 168 m_model->getPoints(frame);
Chris@0 169
Chris@0 170 if (!onPoints.empty()) {
Chris@0 171 return onPoints;
Chris@0 172 }
Chris@0 173
Chris@0 174 SparseOneDimensionalModel::PointList prevPoints =
Chris@0 175 m_model->getPreviousPoints(frame);
Chris@0 176 SparseOneDimensionalModel::PointList nextPoints =
Chris@0 177 m_model->getNextPoints(frame);
Chris@0 178
Chris@0 179 SparseOneDimensionalModel::PointList usePoints = prevPoints;
Chris@0 180
Chris@0 181 if (prevPoints.empty()) {
Chris@0 182 usePoints = nextPoints;
Chris@248 183 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
Chris@44 184 !(nextPoints.begin()->frame > v->getEndFrame())) {
Chris@0 185 usePoints = nextPoints;
Chris@0 186 } else if (nextPoints.begin()->frame - frame <
Chris@0 187 frame - prevPoints.begin()->frame) {
Chris@0 188 usePoints = nextPoints;
Chris@0 189 }
Chris@0 190
Chris@28 191 if (!usePoints.empty()) {
Chris@28 192 int fuzz = 2;
Chris@44 193 int px = v->getXForFrame(usePoints.begin()->frame);
Chris@28 194 if ((px > x && px - x > fuzz) ||
Chris@28 195 (px < x && x - px > fuzz + 1)) {
Chris@28 196 usePoints.clear();
Chris@28 197 }
Chris@28 198 }
Chris@28 199
Chris@0 200 return usePoints;
Chris@0 201 }
Chris@0 202
Chris@25 203 QString
Chris@552 204 TimeInstantLayer::getLabelPreceding(size_t frame) const
Chris@552 205 {
Chris@552 206 if (!m_model) return "";
Chris@552 207 SparseOneDimensionalModel::PointList points = m_model->getPreviousPoints(frame);
Chris@552 208 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin();
Chris@552 209 i != points.end(); ++i) {
Chris@552 210 if (i->label != "") return i->label;
Chris@552 211 }
Chris@552 212 return "";
Chris@552 213 }
Chris@552 214
Chris@552 215 QString
Chris@44 216 TimeInstantLayer::getFeatureDescription(View *v, QPoint &pos) const
Chris@0 217 {
Chris@25 218 int x = pos.x();
Chris@0 219
Chris@25 220 if (!m_model || !m_model->getSampleRate()) return "";
Chris@0 221
Chris@44 222 SparseOneDimensionalModel::PointList points = getLocalPoints(v, x);
Chris@0 223
Chris@0 224 if (points.empty()) {
Chris@0 225 if (!m_model->isReady()) {
Chris@25 226 return tr("In progress");
Chris@25 227 } else {
Chris@25 228 return tr("No local points");
Chris@0 229 }
Chris@0 230 }
Chris@0 231
Chris@0 232 long useFrame = points.begin()->frame;
Chris@0 233
Chris@0 234 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
Chris@25 235
Chris@25 236 QString text;
Chris@0 237
Chris@25 238 if (points.begin()->label == "") {
Chris@25 239 text = QString(tr("Time:\t%1\nNo label"))
Chris@25 240 .arg(rt.toText(true).c_str());
Chris@25 241 } else {
Chris@25 242 text = QString(tr("Time:\t%1\nLabel:\t%2"))
Chris@25 243 .arg(rt.toText(true).c_str())
Chris@25 244 .arg(points.begin()->label);
Chris@25 245 }
Chris@0 246
Chris@44 247 pos = QPoint(v->getXForFrame(useFrame), pos.y());
Chris@25 248 return text;
Chris@0 249 }
Chris@0 250
Chris@28 251 bool
Chris@44 252 TimeInstantLayer::snapToFeatureFrame(View *v, int &frame,
Chris@28 253 size_t &resolution,
Chris@28 254 SnapType snap) const
Chris@13 255 {
Chris@13 256 if (!m_model) {
Chris@44 257 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
Chris@13 258 }
Chris@13 259
Chris@13 260 resolution = m_model->getResolution();
Chris@28 261 SparseOneDimensionalModel::PointList points;
Chris@13 262
Chris@28 263 if (snap == SnapNeighbouring) {
Chris@28 264
Chris@44 265 points = getLocalPoints(v, v->getXForFrame(frame));
Chris@28 266 if (points.empty()) return false;
Chris@28 267 frame = points.begin()->frame;
Chris@28 268 return true;
Chris@28 269 }
Chris@28 270
Chris@28 271 points = m_model->getPoints(frame, frame);
Chris@28 272 int snapped = frame;
Chris@28 273 bool found = false;
Chris@13 274
Chris@13 275 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin();
Chris@13 276 i != points.end(); ++i) {
Chris@13 277
Chris@28 278 if (snap == SnapRight) {
Chris@28 279
Chris@28 280 if (i->frame >= frame) {
Chris@28 281 snapped = i->frame;
Chris@28 282 found = true;
Chris@13 283 break;
Chris@13 284 }
Chris@28 285
Chris@28 286 } else if (snap == SnapLeft) {
Chris@28 287
Chris@13 288 if (i->frame <= frame) {
Chris@28 289 snapped = i->frame;
Chris@28 290 found = true; // don't break, as the next may be better
Chris@28 291 } else {
Chris@28 292 break;
Chris@28 293 }
Chris@28 294
Chris@28 295 } else { // nearest
Chris@28 296
Chris@28 297 SparseOneDimensionalModel::PointList::const_iterator j = i;
Chris@28 298 ++j;
Chris@28 299
Chris@28 300 if (j == points.end()) {
Chris@28 301
Chris@28 302 snapped = i->frame;
Chris@28 303 found = true;
Chris@28 304 break;
Chris@28 305
Chris@28 306 } else if (j->frame >= frame) {
Chris@28 307
Chris@28 308 if (j->frame - frame < frame - i->frame) {
Chris@28 309 snapped = j->frame;
Chris@28 310 } else {
Chris@28 311 snapped = i->frame;
Chris@28 312 }
Chris@28 313 found = true;
Chris@28 314 break;
Chris@13 315 }
Chris@13 316 }
Chris@13 317 }
Chris@13 318
Chris@28 319 frame = snapped;
Chris@28 320 return found;
Chris@13 321 }
Chris@13 322
Chris@0 323 void
Chris@44 324 TimeInstantLayer::paint(View *v, QPainter &paint, QRect rect) const
Chris@0 325 {
Chris@0 326 if (!m_model || !m_model->isOK()) return;
Chris@0 327
Chris@0 328 // Profiler profiler("TimeInstantLayer::paint", true);
Chris@0 329
Chris@20 330 int x0 = rect.left(), x1 = rect.right();
Chris@0 331
Chris@44 332 long frame0 = v->getFrameForX(x0);
Chris@44 333 long frame1 = v->getFrameForX(x1);
Chris@0 334
Chris@0 335 SparseOneDimensionalModel::PointList points(m_model->getPoints
Chris@0 336 (frame0, frame1));
Chris@0 337
Chris@28 338 bool odd = false;
Chris@28 339 if (m_plotStyle == PlotSegmentation && !points.empty()) {
Chris@28 340 int index = m_model->getIndexOf(*points.begin());
Chris@28 341 odd = ((index % 2) == 1);
Chris@28 342 }
Chris@28 343
Chris@287 344 paint.setPen(getBaseQColor());
Chris@0 345
Chris@287 346 QColor brushColour(getBaseQColor());
Chris@0 347 brushColour.setAlpha(100);
Chris@0 348 paint.setBrush(brushColour);
Chris@0 349
Chris@28 350 QColor oddBrushColour(brushColour);
Chris@28 351 if (m_plotStyle == PlotSegmentation) {
Chris@287 352 if (getBaseQColor() == Qt::black) {
Chris@28 353 oddBrushColour = Qt::gray;
Chris@287 354 } else if (getBaseQColor() == Qt::darkRed) {
Chris@28 355 oddBrushColour = Qt::red;
Chris@287 356 } else if (getBaseQColor() == Qt::darkBlue) {
Chris@28 357 oddBrushColour = Qt::blue;
Chris@287 358 } else if (getBaseQColor() == Qt::darkGreen) {
Chris@28 359 oddBrushColour = Qt::green;
Chris@28 360 } else {
Chris@28 361 oddBrushColour = oddBrushColour.light(150);
Chris@28 362 }
Chris@28 363 oddBrushColour.setAlpha(100);
Chris@28 364 }
Chris@28 365
Chris@0 366 // std::cerr << "TimeInstantLayer::paint: resolution is "
Chris@0 367 // << m_model->getResolution() << " frames" << std::endl;
Chris@0 368
Chris@0 369 QPoint localPos;
Chris@0 370 long illuminateFrame = -1;
Chris@0 371
Chris@44 372 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@0 373 SparseOneDimensionalModel::PointList localPoints =
Chris@44 374 getLocalPoints(v, localPos.x());
Chris@0 375 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
Chris@0 376 }
Chris@0 377
Chris@23 378 int prevX = -1;
Chris@79 379 int textY = v->getTextLabelHeight(this, paint);
Chris@79 380
Chris@0 381 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin();
Chris@0 382 i != points.end(); ++i) {
Chris@0 383
Chris@0 384 const SparseOneDimensionalModel::Point &p(*i);
Chris@17 385 SparseOneDimensionalModel::PointList::const_iterator j = i;
Chris@17 386 ++j;
Chris@0 387
Chris@44 388 int x = v->getXForFrame(p.frame);
Chris@23 389 if (x == prevX && p.frame != illuminateFrame) continue;
Chris@23 390
Chris@44 391 int iw = v->getXForFrame(p.frame + m_model->getResolution()) - x;
Chris@16 392 if (iw < 2) {
Chris@17 393 if (iw < 1) {
Chris@17 394 iw = 2;
Chris@17 395 if (j != points.end()) {
Chris@44 396 int nx = v->getXForFrame(j->frame);
Chris@17 397 if (nx < x + 3) iw = 1;
Chris@17 398 }
Chris@17 399 } else {
Chris@17 400 iw = 2;
Chris@17 401 }
Chris@16 402 }
Chris@20 403
Chris@0 404 if (p.frame == illuminateFrame) {
Chris@287 405 paint.setPen(getForegroundQColor(v));
Chris@0 406 } else {
Chris@0 407 paint.setPen(brushColour);
Chris@0 408 }
Chris@23 409
Chris@28 410 if (m_plotStyle == PlotInstants) {
Chris@28 411 if (iw > 1) {
Chris@44 412 paint.drawRect(x, 0, iw - 1, v->height() - 1);
Chris@28 413 } else {
Chris@44 414 paint.drawLine(x, 0, x, v->height() - 1);
Chris@28 415 }
Chris@23 416 } else {
Chris@28 417
Chris@28 418 if (odd) paint.setBrush(oddBrushColour);
Chris@28 419 else paint.setBrush(brushColour);
Chris@28 420
Chris@28 421 int nx;
Chris@28 422
Chris@28 423 if (j != points.end()) {
Chris@28 424 const SparseOneDimensionalModel::Point &q(*j);
Chris@44 425 nx = v->getXForFrame(q.frame);
Chris@28 426 } else {
Chris@44 427 nx = v->getXForFrame(m_model->getEndFrame());
Chris@28 428 }
Chris@28 429
Chris@28 430 if (nx >= x) {
Chris@28 431
Chris@28 432 if (illuminateFrame != p.frame &&
Chris@44 433 (nx < x + 5 || x >= v->width() - 1)) {
Chris@28 434 paint.setPen(Qt::NoPen);
Chris@28 435 }
Chris@28 436
Chris@44 437 paint.drawRect(x, -1, nx - x, v->height() + 1);
Chris@28 438 }
Chris@28 439
Chris@28 440 odd = !odd;
Chris@23 441 }
Chris@28 442
Chris@287 443 paint.setPen(getBaseQColor());
Chris@0 444
Chris@0 445 if (p.label != "") {
Chris@0 446
Chris@0 447 // only draw if there's enough room from here to the next point
Chris@0 448
Chris@0 449 int lw = paint.fontMetrics().width(p.label);
Chris@0 450 bool good = true;
Chris@0 451
Chris@17 452 if (j != points.end()) {
Chris@44 453 int nx = v->getXForFrame(j->frame);
Chris@20 454 if (nx >= x && nx - x - iw - 3 <= lw) good = false;
Chris@0 455 }
Chris@0 456
Chris@0 457 if (good) {
Chris@79 458 paint.drawText(x + iw + 2, textY, p.label);
Chris@0 459 }
Chris@0 460 }
Chris@23 461
Chris@23 462 prevX = x;
Chris@0 463 }
Chris@0 464 }
Chris@0 465
Chris@17 466 void
Chris@44 467 TimeInstantLayer::drawStart(View *v, QMouseEvent *e)
Chris@17 468 {
Chris@387 469 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@17 470 std::cerr << "TimeInstantLayer::drawStart(" << e->x() << ")" << std::endl;
Chris@387 471 #endif
Chris@17 472
Chris@17 473 if (!m_model) return;
Chris@17 474
Chris@44 475 long frame = v->getFrameForX(e->x());
Chris@17 476 if (frame < 0) frame = 0;
Chris@21 477 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@22 478
Chris@17 479 m_editingPoint = SparseOneDimensionalModel::Point(frame, tr("New Point"));
Chris@22 480
Chris@376 481 if (m_editingCommand) finish(m_editingCommand);
Chris@22 482 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model,
Chris@22 483 tr("Draw Point"));
Chris@22 484 m_editingCommand->addPoint(m_editingPoint);
Chris@22 485
Chris@18 486 m_editing = true;
Chris@17 487 }
Chris@17 488
Chris@17 489 void
Chris@44 490 TimeInstantLayer::drawDrag(View *v, QMouseEvent *e)
Chris@17 491 {
Chris@387 492 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@17 493 std::cerr << "TimeInstantLayer::drawDrag(" << e->x() << ")" << std::endl;
Chris@387 494 #endif
Chris@17 495
Chris@18 496 if (!m_model || !m_editing) return;
Chris@17 497
Chris@44 498 long frame = v->getFrameForX(e->x());
Chris@17 499 if (frame < 0) frame = 0;
Chris@21 500 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@22 501 m_editingCommand->deletePoint(m_editingPoint);
Chris@17 502 m_editingPoint.frame = frame;
Chris@22 503 m_editingCommand->addPoint(m_editingPoint);
Chris@17 504 }
Chris@17 505
Chris@17 506 void
Chris@248 507 TimeInstantLayer::drawEnd(View *, QMouseEvent *e)
Chris@17 508 {
Chris@387 509 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@17 510 std::cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << std::endl;
Chris@387 511 #endif
Chris@18 512 if (!m_model || !m_editing) return;
Chris@23 513 QString newName = tr("Add Point at %1 s")
Chris@23 514 .arg(RealTime::frame2RealTime(m_editingPoint.frame,
Chris@23 515 m_model->getSampleRate())
Chris@23 516 .toText(false).c_str());
Chris@23 517 m_editingCommand->setName(newName);
Chris@376 518 finish(m_editingCommand);
Chris@22 519 m_editingCommand = 0;
Chris@18 520 m_editing = false;
Chris@18 521 }
Chris@18 522
Chris@18 523 void
Chris@335 524 TimeInstantLayer::eraseStart(View *v, QMouseEvent *e)
Chris@335 525 {
Chris@335 526 if (!m_model) return;
Chris@335 527
Chris@335 528 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
Chris@335 529 if (points.empty()) return;
Chris@335 530
Chris@335 531 m_editingPoint = *points.begin();
Chris@335 532
Chris@335 533 if (m_editingCommand) {
Chris@376 534 finish(m_editingCommand);
Chris@335 535 m_editingCommand = 0;
Chris@335 536 }
Chris@335 537
Chris@335 538 m_editing = true;
Chris@335 539 }
Chris@335 540
Chris@335 541 void
Chris@335 542 TimeInstantLayer::eraseDrag(View *v, QMouseEvent *e)
Chris@335 543 {
Chris@335 544 }
Chris@335 545
Chris@335 546 void
Chris@335 547 TimeInstantLayer::eraseEnd(View *v, QMouseEvent *e)
Chris@335 548 {
Chris@335 549 if (!m_model || !m_editing) return;
Chris@335 550
Chris@335 551 m_editing = false;
Chris@335 552
Chris@335 553 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
Chris@335 554 if (points.empty()) return;
Chris@335 555 if (points.begin()->frame != m_editingPoint.frame) return;
Chris@335 556
Chris@335 557 m_editingCommand = new SparseOneDimensionalModel::EditCommand
Chris@335 558 (m_model, tr("Erase Point"));
Chris@335 559
Chris@335 560 m_editingCommand->deletePoint(m_editingPoint);
Chris@335 561
Chris@376 562 finish(m_editingCommand);
Chris@335 563 m_editingCommand = 0;
Chris@335 564 m_editing = false;
Chris@335 565 }
Chris@335 566
Chris@335 567 void
Chris@44 568 TimeInstantLayer::editStart(View *v, QMouseEvent *e)
Chris@18 569 {
Chris@387 570 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@18 571 std::cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << std::endl;
Chris@387 572 #endif
Chris@18 573
Chris@17 574 if (!m_model) return;
Chris@18 575
Chris@44 576 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
Chris@18 577 if (points.empty()) return;
Chris@18 578
Chris@18 579 m_editingPoint = *points.begin();
Chris@22 580
Chris@22 581 if (m_editingCommand) {
Chris@376 582 finish(m_editingCommand);
Chris@22 583 m_editingCommand = 0;
Chris@22 584 }
Chris@22 585
Chris@18 586 m_editing = true;
Chris@18 587 }
Chris@18 588
Chris@18 589 void
Chris@44 590 TimeInstantLayer::editDrag(View *v, QMouseEvent *e)
Chris@18 591 {
Chris@387 592 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@18 593 std::cerr << "TimeInstantLayer::editDrag(" << e->x() << ")" << std::endl;
Chris@387 594 #endif
Chris@18 595
Chris@18 596 if (!m_model || !m_editing) return;
Chris@18 597
Chris@44 598 long frame = v->getFrameForX(e->x());
Chris@18 599 if (frame < 0) frame = 0;
Chris@21 600 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@22 601
Chris@22 602 if (!m_editingCommand) {
Chris@22 603 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model,
Chris@22 604 tr("Drag Point"));
Chris@22 605 }
Chris@22 606
Chris@22 607 m_editingCommand->deletePoint(m_editingPoint);
Chris@18 608 m_editingPoint.frame = frame;
Chris@22 609 m_editingCommand->addPoint(m_editingPoint);
Chris@18 610 }
Chris@18 611
Chris@18 612 void
Chris@248 613 TimeInstantLayer::editEnd(View *, QMouseEvent *e)
Chris@18 614 {
Chris@387 615 #ifdef DEBUG_TIME_INSTANT_LAYER
Chris@18 616 std::cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << std::endl;
Chris@387 617 #endif
Chris@18 618 if (!m_model || !m_editing) return;
Chris@23 619 if (m_editingCommand) {
Chris@23 620 QString newName = tr("Move Point to %1 s")
Chris@23 621 .arg(RealTime::frame2RealTime(m_editingPoint.frame,
Chris@23 622 m_model->getSampleRate())
Chris@23 623 .toText(false).c_str());
Chris@23 624 m_editingCommand->setName(newName);
Chris@376 625 finish(m_editingCommand);
Chris@23 626 }
Chris@22 627 m_editingCommand = 0;
Chris@18 628 m_editing = false;
Chris@17 629 }
Chris@17 630
Chris@255 631 bool
Chris@70 632 TimeInstantLayer::editOpen(View *v, QMouseEvent *e)
Chris@70 633 {
Chris@255 634 if (!m_model) return false;
Chris@70 635
Chris@70 636 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x());
Chris@255 637 if (points.empty()) return false;
Chris@70 638
Chris@70 639 SparseOneDimensionalModel::Point point = *points.begin();
Chris@70 640
Chris@70 641 ItemEditDialog *dialog = new ItemEditDialog
Chris@70 642 (m_model->getSampleRate(),
Chris@70 643 ItemEditDialog::ShowTime |
Chris@70 644 ItemEditDialog::ShowText);
Chris@70 645
Chris@70 646 dialog->setFrameTime(point.frame);
Chris@70 647 dialog->setText(point.label);
Chris@70 648
Chris@70 649 if (dialog->exec() == QDialog::Accepted) {
Chris@70 650
Chris@70 651 SparseOneDimensionalModel::Point newPoint = point;
Chris@70 652 newPoint.frame = dialog->getFrameTime();
Chris@70 653 newPoint.label = dialog->getText();
Chris@70 654
Chris@70 655 SparseOneDimensionalModel::EditCommand *command =
Chris@70 656 new SparseOneDimensionalModel::EditCommand(m_model, tr("Edit Point"));
Chris@70 657 command->deletePoint(point);
Chris@70 658 command->addPoint(newPoint);
Chris@376 659 finish(command);
Chris@70 660 }
Chris@70 661
Chris@70 662 delete dialog;
Chris@255 663 return true;
Chris@70 664 }
Chris@70 665
Chris@70 666 void
Chris@43 667 TimeInstantLayer::moveSelection(Selection s, size_t newStartFrame)
Chris@43 668 {
Chris@99 669 if (!m_model) return;
Chris@99 670
Chris@43 671 SparseOneDimensionalModel::EditCommand *command =
Chris@43 672 new SparseOneDimensionalModel::EditCommand(m_model,
Chris@43 673 tr("Drag Selection"));
Chris@43 674
Chris@43 675 SparseOneDimensionalModel::PointList points =
Chris@43 676 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 677
Chris@43 678 for (SparseOneDimensionalModel::PointList::iterator i = points.begin();
Chris@43 679 i != points.end(); ++i) {
Chris@43 680
Chris@43 681 if (s.contains(i->frame)) {
Chris@43 682 SparseOneDimensionalModel::Point newPoint(*i);
Chris@43 683 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
Chris@43 684 command->deletePoint(*i);
Chris@43 685 command->addPoint(newPoint);
Chris@43 686 }
Chris@43 687 }
Chris@43 688
Chris@376 689 finish(command);
Chris@43 690 }
Chris@43 691
Chris@43 692 void
Chris@43 693 TimeInstantLayer::resizeSelection(Selection s, Selection newSize)
Chris@43 694 {
Chris@99 695 if (!m_model) return;
Chris@99 696
Chris@43 697 SparseOneDimensionalModel::EditCommand *command =
Chris@43 698 new SparseOneDimensionalModel::EditCommand(m_model,
Chris@43 699 tr("Resize Selection"));
Chris@43 700
Chris@43 701 SparseOneDimensionalModel::PointList points =
Chris@43 702 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 703
Chris@43 704 double ratio =
Chris@43 705 double(newSize.getEndFrame() - newSize.getStartFrame()) /
Chris@43 706 double(s.getEndFrame() - s.getStartFrame());
Chris@43 707
Chris@43 708 for (SparseOneDimensionalModel::PointList::iterator i = points.begin();
Chris@43 709 i != points.end(); ++i) {
Chris@43 710
Chris@43 711 if (s.contains(i->frame)) {
Chris@43 712
Chris@43 713 double target = i->frame;
Chris@43 714 target = newSize.getStartFrame() +
Chris@43 715 double(target - s.getStartFrame()) * ratio;
Chris@43 716
Chris@43 717 SparseOneDimensionalModel::Point newPoint(*i);
Chris@43 718 newPoint.frame = lrint(target);
Chris@43 719 command->deletePoint(*i);
Chris@43 720 command->addPoint(newPoint);
Chris@43 721 }
Chris@43 722 }
Chris@43 723
Chris@376 724 finish(command);
Chris@43 725 }
Chris@43 726
Chris@43 727 void
Chris@43 728 TimeInstantLayer::deleteSelection(Selection s)
Chris@43 729 {
Chris@99 730 if (!m_model) return;
Chris@99 731
Chris@43 732 SparseOneDimensionalModel::EditCommand *command =
Chris@43 733 new SparseOneDimensionalModel::EditCommand(m_model,
Chris@43 734 tr("Delete Selection"));
Chris@43 735
Chris@43 736 SparseOneDimensionalModel::PointList points =
Chris@43 737 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@43 738
Chris@43 739 for (SparseOneDimensionalModel::PointList::iterator i = points.begin();
Chris@43 740 i != points.end(); ++i) {
Chris@43 741 if (s.contains(i->frame)) command->deletePoint(*i);
Chris@43 742 }
Chris@43 743
Chris@376 744 finish(command);
Chris@43 745 }
Chris@76 746
Chris@76 747 void
Chris@359 748 TimeInstantLayer::copy(View *v, Selection s, Clipboard &to)
Chris@76 749 {
Chris@99 750 if (!m_model) return;
Chris@99 751
Chris@76 752 SparseOneDimensionalModel::PointList points =
Chris@76 753 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
Chris@76 754
Chris@76 755 for (SparseOneDimensionalModel::PointList::iterator i = points.begin();
Chris@76 756 i != points.end(); ++i) {
Chris@76 757 if (s.contains(i->frame)) {
Chris@76 758 Clipboard::Point point(i->frame, i->label);
Chris@359 759 point.setReferenceFrame(alignToReference(v, i->frame));
Chris@76 760 to.addPoint(point);
Chris@76 761 }
Chris@76 762 }
Chris@76 763 }
Chris@76 764
Chris@125 765 bool
Chris@359 766 TimeInstantLayer::paste(View *v, const Clipboard &from, int frameOffset, bool)
Chris@76 767 {
Chris@125 768 if (!m_model) return false;
Chris@99 769
Chris@76 770 const Clipboard::PointList &points = from.getPoints();
Chris@76 771
Chris@358 772 bool realign = false;
Chris@358 773
Chris@360 774 if (clipboardHasDifferentAlignment(v, from)) {
Chris@358 775
Chris@360 776 QMessageBox::StandardButton button =
Chris@360 777 QMessageBox::question(v, tr("Re-align pasted instants?"),
Chris@360 778 tr("The instants 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 779 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@360 780 QMessageBox::Yes);
Chris@358 781
Chris@360 782 if (button == QMessageBox::Cancel) {
Chris@360 783 return false;
Chris@360 784 }
Chris@358 785
Chris@360 786 if (button == QMessageBox::Yes) {
Chris@360 787 realign = true;
Chris@360 788 }
Chris@358 789 }
Chris@358 790
Chris@358 791 SparseOneDimensionalModel::EditCommand *command =
Chris@358 792 new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste"));
Chris@358 793
Chris@76 794 for (Clipboard::PointList::const_iterator i = points.begin();
Chris@76 795 i != points.end(); ++i) {
Chris@76 796
Chris@76 797 if (!i->haveFrame()) continue;
Chris@359 798
Chris@76 799 size_t frame = 0;
Chris@359 800
Chris@359 801 if (!realign) {
Chris@359 802
Chris@359 803 frame = i->getFrame();
Chris@359 804
Chris@359 805 } else {
Chris@359 806
Chris@359 807 if (i->haveReferenceFrame()) {
Chris@359 808 frame = i->getReferenceFrame();
Chris@359 809 frame = alignFromReference(v, frame);
Chris@359 810 } else {
Chris@359 811 frame = i->getFrame();
Chris@359 812 }
Chris@76 813 }
Chris@359 814
Chris@359 815 if (frameOffset > 0) frame += frameOffset;
Chris@359 816 else if (frameOffset < 0) {
Chris@359 817 if (frame > -frameOffset) frame += frameOffset;
Chris@359 818 else frame = 0;
Chris@359 819 }
Chris@359 820
Chris@76 821 SparseOneDimensionalModel::Point newPoint(frame);
Chris@125 822 if (i->haveLabel()) {
Chris@125 823 newPoint.label = i->getLabel();
Chris@125 824 } else if (i->haveValue()) {
Chris@125 825 newPoint.label = QString("%1").arg(i->getValue());
Chris@125 826 }
Chris@76 827
Chris@76 828 command->addPoint(newPoint);
Chris@76 829 }
Chris@76 830
Chris@376 831 finish(command);
Chris@125 832 return true;
Chris@76 833 }
Chris@43 834
Chris@287 835 int
Chris@287 836 TimeInstantLayer::getDefaultColourHint(bool darkbg, bool &impose)
Chris@287 837 {
Chris@287 838 impose = false;
Chris@287 839 return ColourDatabase::getInstance()->getColourIndex
Chris@287 840 (QString(darkbg ? "Bright Purple" : "Purple"));
Chris@287 841 }
Chris@287 842
Chris@316 843 void
Chris@316 844 TimeInstantLayer::toXml(QTextStream &stream,
Chris@316 845 QString indent, QString extraAttributes) const
Chris@6 846 {
Chris@316 847 SingleColourLayer::toXml(stream, indent,
Chris@316 848 extraAttributes +
Chris@316 849 QString(" plotStyle=\"%1\"")
Chris@316 850 .arg(m_plotStyle));
Chris@6 851 }
Chris@0 852
Chris@11 853 void
Chris@11 854 TimeInstantLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 855 {
Chris@287 856 SingleColourLayer::setProperties(attributes);
Chris@28 857
Chris@28 858 bool ok;
Chris@28 859 PlotStyle style = (PlotStyle)
Chris@28 860 attributes.value("plotStyle").toInt(&ok);
Chris@28 861 if (ok) setPlotStyle(style);
Chris@11 862 }
Chris@11 863