annotate layer/TimeInstantLayer.cpp @ 302:e9549ea3f825

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