annotate layer/TimeInstantLayer.cpp @ 326:4f4f38a11cd2

* Factor out uses of "Sonic Visualiser" in "common" code to applicationName() * Add ability to show work title + artist in top-left of pane (thinking of Vect but may be useful in SV in future) * A few other generalisations useful for Vect
author Chris Cannam
date Fri, 09 Nov 2007 17:46:58 +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