annotate layer/TimeInstantLayer.cpp @ 77:fd348f36c0d3

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