annotate layer/TimeInstantLayer.cpp @ 308:cda569dfbdfe

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