annotate layer/TimeInstantLayer.cpp @ 316:c0b9eec70639

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