annotate layer/TimeInstantLayer.cpp @ 299:5c59c433b358

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