annotate layer/TimeInstantLayer.cpp @ 162:f32212631b9c

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