annotate layer/TimeInstantLayer.cpp @ 333:e74b56f07c73

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