annotate layer/TimeInstantLayer.cpp @ 312:6de6f78b13a1

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