annotate layer/TimeValueLayer.cpp @ 37:21d061e66177

* Make the frequency estimation mode in the spectrogram layer actually useful, and make sure it gets mostly the right results... Still some tidying to do in here.
author Chris Cannam
date Wed, 22 Feb 2006 17:45:18 +0000
parents c43f2c4f66f2
children 1bdf285c4eac
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 A waveform viewer and audio annotation editor.
Chris@3 5 Chris Cannam, Queen Mary University of London, 2005-2006
Chris@0 6
Chris@0 7 This is experimental software. Not for distribution.
Chris@0 8 */
Chris@0 9
Chris@0 10 #include "TimeValueLayer.h"
Chris@0 11
Chris@0 12 #include "base/Model.h"
Chris@0 13 #include "base/RealTime.h"
Chris@0 14 #include "base/Profiler.h"
Chris@0 15 #include "base/View.h"
Chris@0 16
Chris@0 17 #include "model/SparseTimeValueModel.h"
Chris@0 18
Chris@0 19 #include <QPainter>
Chris@6 20 #include <QPainterPath>
Chris@21 21 #include <QMouseEvent>
Chris@0 22
Chris@0 23 #include <iostream>
Chris@0 24 #include <cmath>
Chris@0 25
Chris@0 26 TimeValueLayer::TimeValueLayer(View *w) :
Chris@0 27 Layer(w),
Chris@0 28 m_model(0),
Chris@21 29 m_editing(false),
Chris@23 30 m_originalPoint(0, 0.0, tr("New Point")),
Chris@21 31 m_editingPoint(0, 0.0, tr("New Point")),
Chris@22 32 m_editingCommand(0),
Chris@0 33 m_colour(Qt::black),
Chris@6 34 m_plotStyle(PlotConnectedPoints)
Chris@0 35 {
Chris@0 36 m_view->addLayer(this);
Chris@0 37 }
Chris@0 38
Chris@0 39 void
Chris@0 40 TimeValueLayer::setModel(SparseTimeValueModel *model)
Chris@0 41 {
Chris@0 42 if (m_model == model) return;
Chris@0 43 m_model = model;
Chris@0 44
Chris@0 45 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
Chris@0 46 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
Chris@0 47 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@0 48
Chris@0 49 connect(m_model, SIGNAL(completionChanged()),
Chris@0 50 this, SIGNAL(modelCompletionChanged()));
Chris@0 51
Chris@0 52 std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl;
Chris@0 53
Chris@0 54 emit modelReplaced();
Chris@0 55 }
Chris@0 56
Chris@0 57 Layer::PropertyList
Chris@0 58 TimeValueLayer::getProperties() const
Chris@0 59 {
Chris@0 60 PropertyList list;
Chris@0 61 list.push_back(tr("Colour"));
Chris@0 62 list.push_back(tr("Plot Type"));
Chris@0 63 return list;
Chris@0 64 }
Chris@0 65
Chris@0 66 Layer::PropertyType
Chris@0 67 TimeValueLayer::getPropertyType(const PropertyName &name) const
Chris@0 68 {
Chris@0 69 return ValueProperty;
Chris@0 70 }
Chris@0 71
Chris@0 72 int
Chris@0 73 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
Chris@0 74 int *min, int *max) const
Chris@0 75 {
Chris@0 76 //!!! factor this colour handling stuff out into a colour manager class
Chris@0 77
Chris@0 78 int deft = 0;
Chris@0 79
Chris@0 80 if (name == tr("Colour")) {
Chris@0 81
Chris@10 82 if (min) *min = 0;
Chris@10 83 if (max) *max = 5;
Chris@0 84
Chris@0 85 if (m_colour == Qt::black) deft = 0;
Chris@0 86 else if (m_colour == Qt::darkRed) deft = 1;
Chris@0 87 else if (m_colour == Qt::darkBlue) deft = 2;
Chris@0 88 else if (m_colour == Qt::darkGreen) deft = 3;
Chris@0 89 else if (m_colour == QColor(200, 50, 255)) deft = 4;
Chris@0 90 else if (m_colour == QColor(255, 150, 50)) deft = 5;
Chris@0 91
Chris@0 92 } else if (name == tr("Plot Type")) {
Chris@0 93
Chris@10 94 if (min) *min = 0;
Chris@26 95 if (max) *max = 5;
Chris@0 96
Chris@0 97 deft = int(m_plotStyle);
Chris@0 98
Chris@0 99 } else {
Chris@0 100
Chris@0 101 deft = Layer::getPropertyRangeAndValue(name, min, max);
Chris@0 102 }
Chris@0 103
Chris@0 104 return deft;
Chris@0 105 }
Chris@0 106
Chris@0 107 QString
Chris@0 108 TimeValueLayer::getPropertyValueLabel(const PropertyName &name,
Chris@0 109 int value) const
Chris@0 110 {
Chris@0 111 if (name == tr("Colour")) {
Chris@0 112 switch (value) {
Chris@0 113 default:
Chris@0 114 case 0: return tr("Black");
Chris@0 115 case 1: return tr("Red");
Chris@0 116 case 2: return tr("Blue");
Chris@0 117 case 3: return tr("Green");
Chris@0 118 case 4: return tr("Purple");
Chris@0 119 case 5: return tr("Orange");
Chris@0 120 }
Chris@0 121 } else if (name == tr("Plot Type")) {
Chris@0 122 switch (value) {
Chris@0 123 default:
Chris@0 124 case 0: return tr("Points");
Chris@0 125 case 1: return tr("Stems");
Chris@6 126 case 2: return tr("Connected Points");
Chris@6 127 case 3: return tr("Lines");
Chris@6 128 case 4: return tr("Curve");
Chris@26 129 case 5: return tr("Segmentation");
Chris@0 130 }
Chris@0 131 }
Chris@0 132 return tr("<unknown>");
Chris@0 133 }
Chris@0 134
Chris@0 135 void
Chris@0 136 TimeValueLayer::setProperty(const PropertyName &name, int value)
Chris@0 137 {
Chris@0 138 if (name == tr("Colour")) {
Chris@0 139 switch (value) {
Chris@0 140 default:
Chris@0 141 case 0: setBaseColour(Qt::black); break;
Chris@0 142 case 1: setBaseColour(Qt::darkRed); break;
Chris@0 143 case 2: setBaseColour(Qt::darkBlue); break;
Chris@0 144 case 3: setBaseColour(Qt::darkGreen); break;
Chris@0 145 case 4: setBaseColour(QColor(200, 50, 255)); break;
Chris@0 146 case 5: setBaseColour(QColor(255, 150, 50)); break;
Chris@0 147 }
Chris@0 148 } else if (name == tr("Plot Type")) {
Chris@0 149 setPlotStyle(PlotStyle(value));
Chris@0 150 }
Chris@0 151 }
Chris@0 152
Chris@0 153 void
Chris@0 154 TimeValueLayer::setBaseColour(QColor colour)
Chris@0 155 {
Chris@0 156 if (m_colour == colour) return;
Chris@0 157 m_colour = colour;
Chris@0 158 emit layerParametersChanged();
Chris@0 159 }
Chris@0 160
Chris@0 161 void
Chris@0 162 TimeValueLayer::setPlotStyle(PlotStyle style)
Chris@0 163 {
Chris@0 164 if (m_plotStyle == style) return;
Chris@0 165 m_plotStyle = style;
Chris@0 166 emit layerParametersChanged();
Chris@0 167 }
Chris@0 168
Chris@0 169 bool
Chris@0 170 TimeValueLayer::isLayerScrollable() const
Chris@0 171 {
Chris@6 172 // We don't illuminate sections in the line or curve modes, so
Chris@6 173 // they're always scrollable
Chris@6 174
Chris@6 175 if (m_plotStyle == PlotLines ||
Chris@6 176 m_plotStyle == PlotCurve) return true;
Chris@6 177
Chris@0 178 QPoint discard;
Chris@0 179 return !m_view->shouldIlluminateLocalFeatures(this, discard);
Chris@0 180 }
Chris@0 181
Chris@0 182 SparseTimeValueModel::PointList
Chris@0 183 TimeValueLayer::getLocalPoints(int x) const
Chris@0 184 {
Chris@0 185 if (!m_model) return SparseTimeValueModel::PointList();
Chris@0 186
Chris@20 187 long frame = getFrameForX(x);
Chris@0 188
Chris@0 189 SparseTimeValueModel::PointList onPoints =
Chris@0 190 m_model->getPoints(frame);
Chris@0 191
Chris@0 192 if (!onPoints.empty()) {
Chris@0 193 return onPoints;
Chris@0 194 }
Chris@0 195
Chris@0 196 SparseTimeValueModel::PointList prevPoints =
Chris@0 197 m_model->getPreviousPoints(frame);
Chris@0 198 SparseTimeValueModel::PointList nextPoints =
Chris@0 199 m_model->getNextPoints(frame);
Chris@0 200
Chris@0 201 SparseTimeValueModel::PointList usePoints = prevPoints;
Chris@0 202
Chris@0 203 if (prevPoints.empty()) {
Chris@0 204 usePoints = nextPoints;
Chris@20 205 } else if (prevPoints.begin()->frame < m_view->getStartFrame() &&
Chris@20 206 !(nextPoints.begin()->frame > m_view->getEndFrame())) {
Chris@0 207 usePoints = nextPoints;
Chris@0 208 } else if (nextPoints.begin()->frame - frame <
Chris@0 209 frame - prevPoints.begin()->frame) {
Chris@0 210 usePoints = nextPoints;
Chris@0 211 }
Chris@0 212
Chris@28 213 if (!usePoints.empty()) {
Chris@28 214 int fuzz = 2;
Chris@28 215 int px = getXForFrame(usePoints.begin()->frame);
Chris@28 216 if ((px > x && px - x > fuzz) ||
Chris@28 217 (px < x && x - px > fuzz + 1)) {
Chris@28 218 usePoints.clear();
Chris@28 219 }
Chris@28 220 }
Chris@28 221
Chris@0 222 return usePoints;
Chris@0 223 }
Chris@0 224
Chris@25 225 QString
Chris@25 226 TimeValueLayer::getFeatureDescription(QPoint &pos) const
Chris@0 227 {
Chris@25 228 int x = pos.x();
Chris@0 229
Chris@25 230 if (!m_model || !m_model->getSampleRate()) return "";
Chris@0 231
Chris@0 232 SparseTimeValueModel::PointList points = getLocalPoints(x);
Chris@0 233
Chris@0 234 if (points.empty()) {
Chris@0 235 if (!m_model->isReady()) {
Chris@25 236 return tr("In progress");
Chris@25 237 } else {
Chris@25 238 return tr("No local points");
Chris@0 239 }
Chris@0 240 }
Chris@0 241
Chris@0 242 long useFrame = points.begin()->frame;
Chris@0 243
Chris@0 244 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
Chris@25 245
Chris@25 246 QString text;
Chris@0 247
Chris@25 248 if (points.begin()->label == "") {
Chris@25 249 text = QString(tr("Time:\t%1\nValue:\t%2\nNo label"))
Chris@25 250 .arg(rt.toText(true).c_str())
Chris@25 251 .arg(points.begin()->value);
Chris@25 252 } else {
Chris@25 253 text = QString(tr("Time:\t%1\nValue:\t%2\nLabel:\t%3"))
Chris@25 254 .arg(rt.toText(true).c_str())
Chris@25 255 .arg(points.begin()->value)
Chris@25 256 .arg(points.begin()->label);
Chris@25 257 }
Chris@0 258
Chris@25 259 pos = QPoint(getXForFrame(useFrame), getYForValue(points.begin()->value));
Chris@25 260 return text;
Chris@0 261 }
Chris@0 262
Chris@28 263 bool
Chris@28 264 TimeValueLayer::snapToFeatureFrame(int &frame,
Chris@28 265 size_t &resolution,
Chris@28 266 SnapType snap) const
Chris@13 267 {
Chris@13 268 if (!m_model) {
Chris@28 269 return Layer::snapToFeatureFrame(frame, resolution, snap);
Chris@13 270 }
Chris@13 271
Chris@13 272 resolution = m_model->getResolution();
Chris@28 273 SparseTimeValueModel::PointList points;
Chris@13 274
Chris@28 275 if (snap == SnapNeighbouring) {
Chris@28 276
Chris@28 277 points = getLocalPoints(getXForFrame(frame));
Chris@28 278 if (points.empty()) return false;
Chris@28 279 frame = points.begin()->frame;
Chris@28 280 return true;
Chris@28 281 }
Chris@28 282
Chris@28 283 points = m_model->getPoints(frame, frame);
Chris@28 284 int snapped = frame;
Chris@28 285 bool found = false;
Chris@13 286
Chris@13 287 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@13 288 i != points.end(); ++i) {
Chris@13 289
Chris@28 290 if (snap == SnapRight) {
Chris@28 291
Chris@13 292 if (i->frame > frame) {
Chris@28 293 snapped = i->frame;
Chris@28 294 found = true;
Chris@13 295 break;
Chris@13 296 }
Chris@28 297
Chris@28 298 } else if (snap == SnapLeft) {
Chris@28 299
Chris@13 300 if (i->frame <= frame) {
Chris@28 301 snapped = i->frame;
Chris@28 302 found = true; // don't break, as the next may be better
Chris@28 303 } else {
Chris@28 304 break;
Chris@28 305 }
Chris@28 306
Chris@28 307 } else { // nearest
Chris@28 308
Chris@28 309 SparseTimeValueModel::PointList::const_iterator j = i;
Chris@28 310 ++j;
Chris@28 311
Chris@28 312 if (j == points.end()) {
Chris@28 313
Chris@28 314 snapped = i->frame;
Chris@28 315 found = true;
Chris@28 316 break;
Chris@28 317
Chris@28 318 } else if (j->frame >= frame) {
Chris@28 319
Chris@28 320 if (j->frame - frame < frame - i->frame) {
Chris@28 321 snapped = j->frame;
Chris@28 322 } else {
Chris@28 323 snapped = i->frame;
Chris@28 324 }
Chris@28 325 found = true;
Chris@28 326 break;
Chris@13 327 }
Chris@13 328 }
Chris@13 329 }
Chris@13 330
Chris@28 331 frame = snapped;
Chris@28 332 return found;
Chris@13 333 }
Chris@13 334
Chris@21 335 int
Chris@21 336 TimeValueLayer::getYForValue(float value) const
Chris@21 337 {
Chris@21 338 float min = m_model->getValueMinimum();
Chris@21 339 float max = m_model->getValueMaximum();
Chris@21 340 if (max == min) max = min + 1.0;
Chris@21 341
Chris@21 342 int h = m_view->height();
Chris@21 343
Chris@21 344 return int(h - ((value - min) * h) / (max - min));
Chris@21 345 }
Chris@21 346
Chris@21 347 float
Chris@21 348 TimeValueLayer::getValueForY(int y) const
Chris@21 349 {
Chris@21 350 float min = m_model->getValueMinimum();
Chris@21 351 float max = m_model->getValueMaximum();
Chris@21 352 if (max == min) max = min + 1.0;
Chris@21 353
Chris@21 354 int h = m_view->height();
Chris@21 355
Chris@21 356 return min + (float(h - y) * float(max - min)) / h;
Chris@21 357 }
Chris@21 358
Chris@0 359 void
Chris@0 360 TimeValueLayer::paint(QPainter &paint, QRect rect) const
Chris@0 361 {
Chris@0 362 if (!m_model || !m_model->isOK()) return;
Chris@0 363
Chris@0 364 int sampleRate = m_model->getSampleRate();
Chris@0 365 if (!sampleRate) return;
Chris@0 366
Chris@0 367 // Profiler profiler("TimeValueLayer::paint", true);
Chris@0 368
Chris@0 369 int x0 = rect.left(), x1 = rect.right();
Chris@20 370 long frame0 = getFrameForX(x0);
Chris@20 371 long frame1 = getFrameForX(x1);
Chris@0 372
Chris@0 373 SparseTimeValueModel::PointList points(m_model->getPoints
Chris@0 374 (frame0, frame1));
Chris@11 375 if (points.empty()) return;
Chris@0 376
Chris@0 377 paint.setPen(m_colour);
Chris@0 378
Chris@0 379 QColor brushColour(m_colour);
Chris@0 380 brushColour.setAlpha(80);
Chris@0 381 paint.setBrush(brushColour);
Chris@0 382
Chris@0 383 // std::cerr << "TimeValueLayer::paint: resolution is "
Chris@0 384 // << m_model->getResolution() << " frames" << std::endl;
Chris@0 385
Chris@0 386 float min = m_model->getValueMinimum();
Chris@0 387 float max = m_model->getValueMaximum();
Chris@0 388 if (max == min) max = min + 1.0;
Chris@0 389
Chris@0 390 int origin = int(nearbyint(m_view->height() -
Chris@0 391 (-min * m_view->height()) / (max - min)));
Chris@0 392
Chris@0 393 QPoint localPos;
Chris@0 394 long illuminateFrame = -1;
Chris@0 395
Chris@0 396 if (m_view->shouldIlluminateLocalFeatures(this, localPos)) {
Chris@0 397 SparseTimeValueModel::PointList localPoints =
Chris@0 398 getLocalPoints(localPos.x());
Chris@0 399 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
Chris@0 400 }
Chris@6 401
Chris@20 402 int w =
Chris@20 403 getXForFrame(frame0 + m_model->getResolution()) -
Chris@20 404 getXForFrame(frame0);
Chris@7 405
Chris@6 406 paint.save();
Chris@6 407
Chris@7 408 if (w > 1 &&
Chris@7 409 (m_plotStyle == PlotLines ||
Chris@7 410 m_plotStyle == PlotCurve)) {
Chris@6 411 paint.setRenderHint(QPainter::Antialiasing, true);
Chris@6 412 }
Chris@6 413 QPainterPath path;
Chris@6 414
Chris@0 415 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
Chris@0 416 i != points.end(); ++i) {
Chris@0 417
Chris@0 418 const SparseTimeValueModel::Point &p(*i);
Chris@0 419
Chris@20 420 int x = getXForFrame(p.frame);
Chris@21 421 int y = getYForValue(p.value);
Chris@0 422
Chris@34 423 bool haveNext = false;
Chris@34 424 int nx = getXForFrame(m_model->getEndFrame());
Chris@34 425 int ny = y;
Chris@34 426
Chris@34 427 SparseTimeValueModel::PointList::const_iterator j = i;
Chris@34 428 ++j;
Chris@34 429
Chris@34 430 if (j != points.end()) {
Chris@34 431 const SparseTimeValueModel::Point &q(*j);
Chris@34 432 nx = getXForFrame(q.frame);
Chris@34 433 ny = getYForValue(q.value);
Chris@34 434 haveNext = true;
Chris@34 435 }
Chris@34 436
Chris@34 437 int labelY = y;
Chris@34 438
Chris@0 439 if (w < 1) w = 1;
Chris@26 440 paint.setPen(m_colour);
Chris@0 441
Chris@26 442 if (m_plotStyle == PlotSegmentation) {
Chris@26 443 int value = ((p.value - min) / (max - min)) * 255.999;
Chris@26 444 QColor colour = QColor::fromHsv(256 - value, value / 2 + 128, value);
Chris@26 445 paint.setBrush(QColor(colour.red(), colour.green(), colour.blue(),
Chris@26 446 120));
Chris@34 447 labelY = m_view->height();
Chris@26 448 } else if (m_plotStyle == PlotLines ||
Chris@26 449 m_plotStyle == PlotCurve) {
Chris@6 450 paint.setBrush(Qt::NoBrush);
Chris@3 451 } else {
Chris@6 452 paint.setBrush(brushColour);
Chris@3 453 }
Chris@0 454
Chris@0 455 if (m_plotStyle == PlotStems) {
Chris@0 456 paint.setPen(brushColour);
Chris@0 457 if (y < origin - 1) {
Chris@0 458 paint.drawRect(x + w/2, y + 1, 1, origin - y);
Chris@0 459 } else if (y > origin + 1) {
Chris@0 460 paint.drawRect(x + w/2, origin, 1, y - origin - 1);
Chris@0 461 }
Chris@0 462 paint.setPen(m_colour);
Chris@0 463 }
Chris@0 464
Chris@0 465 if (illuminateFrame == p.frame) {
Chris@6 466
Chris@0 467 //!!! aside from the problem of choosing a colour, it'd be
Chris@0 468 //better to save the highlighted rects and draw them at
Chris@0 469 //the end perhaps
Chris@6 470
Chris@6 471 //!!! not equipped to illuminate the right section in line
Chris@6 472 //or curve mode
Chris@6 473
Chris@6 474 if (m_plotStyle != PlotCurve &&
Chris@6 475 m_plotStyle != PlotLines) {
Chris@6 476 paint.setPen(Qt::black);//!!!
Chris@26 477 if (m_plotStyle != PlotSegmentation) {
Chris@26 478 paint.setBrush(Qt::black);//!!!
Chris@26 479 }
Chris@6 480 }
Chris@0 481 }
Chris@0 482
Chris@6 483 if (m_plotStyle != PlotLines &&
Chris@26 484 m_plotStyle != PlotCurve &&
Chris@26 485 m_plotStyle != PlotSegmentation) {
Chris@3 486 paint.drawRect(x, y - 1, w, 2);
Chris@3 487 }
Chris@0 488
Chris@6 489 if (m_plotStyle == PlotConnectedPoints ||
Chris@6 490 m_plotStyle == PlotLines ||
Chris@6 491 m_plotStyle == PlotCurve) {
Chris@0 492
Chris@34 493 if (haveNext) {
Chris@3 494
Chris@6 495 if (m_plotStyle == PlotConnectedPoints) {
Chris@34 496
Chris@3 497 paint.setPen(brushColour);
Chris@3 498 paint.drawLine(x + w, y, nx, ny);
Chris@6 499
Chris@6 500 } else if (m_plotStyle == PlotLines) {
Chris@6 501
Chris@6 502 paint.drawLine(x + w/2, y, nx + w/2, ny);
Chris@6 503
Chris@3 504 } else {
Chris@6 505
Chris@6 506 if (path.isEmpty()) {
Chris@6 507 path.moveTo(x + w/2, y);
Chris@6 508 }
Chris@6 509
Chris@6 510 if (nx - x > 5) {
Chris@6 511 path.cubicTo(x + w, y, nx, ny, nx + w/2, ny);
Chris@6 512 } else {
Chris@6 513 path.lineTo(nx + w/2, ny);
Chris@6 514 }
Chris@3 515 }
Chris@0 516 }
Chris@0 517 }
Chris@0 518
Chris@26 519 if (m_plotStyle == PlotSegmentation) {
Chris@26 520
Chris@27 521 if (nx <= x) continue;
Chris@26 522
Chris@28 523 if (illuminateFrame != p.frame &&
Chris@28 524 (nx < x + 5 || x >= m_view->width() - 1)) {
Chris@27 525 paint.setPen(Qt::NoPen);
Chris@27 526 }
Chris@26 527
Chris@27 528 paint.drawRect(x, -1, nx - x, m_view->height() + 1);
Chris@26 529 }
Chris@26 530
Chris@0 531 /// if (p.label != "") {
Chris@0 532 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
Chris@0 533 /// }
Chris@0 534 }
Chris@6 535
Chris@6 536 if (m_plotStyle == PlotCurve && !path.isEmpty()) {
Chris@6 537 paint.drawPath(path);
Chris@6 538 }
Chris@6 539
Chris@6 540 paint.restore();
Chris@6 541
Chris@6 542 // looks like save/restore doesn't deal with this:
Chris@6 543 paint.setRenderHint(QPainter::Antialiasing, false);
Chris@6 544 }
Chris@6 545
Chris@21 546 void
Chris@21 547 TimeValueLayer::drawStart(QMouseEvent *e)
Chris@21 548 {
Chris@21 549 std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 550
Chris@21 551 if (!m_model) return;
Chris@21 552
Chris@21 553 long frame = getFrameForX(e->x());
Chris@21 554 if (frame < 0) frame = 0;
Chris@21 555 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@21 556
Chris@21 557 float value = getValueForY(e->y());
Chris@21 558
Chris@21 559 m_editingPoint = SparseTimeValueModel::Point(frame, value, tr("New Point"));
Chris@23 560 m_originalPoint = m_editingPoint;
Chris@22 561
Chris@22 562 if (m_editingCommand) m_editingCommand->finish();
Chris@22 563 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
Chris@22 564 tr("Draw Point"));
Chris@22 565 m_editingCommand->addPoint(m_editingPoint);
Chris@22 566
Chris@21 567 m_editing = true;
Chris@21 568 }
Chris@21 569
Chris@21 570 void
Chris@21 571 TimeValueLayer::drawDrag(QMouseEvent *e)
Chris@21 572 {
Chris@21 573 std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 574
Chris@21 575 if (!m_model || !m_editing) return;
Chris@21 576
Chris@21 577 long frame = getFrameForX(e->x());
Chris@21 578 if (frame < 0) frame = 0;
Chris@21 579 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@21 580
Chris@21 581 float value = getValueForY(e->y());
Chris@21 582
Chris@22 583 m_editingCommand->deletePoint(m_editingPoint);
Chris@21 584 m_editingPoint.frame = frame;
Chris@21 585 m_editingPoint.value = value;
Chris@22 586 m_editingCommand->addPoint(m_editingPoint);
Chris@21 587 }
Chris@21 588
Chris@21 589 void
Chris@21 590 TimeValueLayer::drawEnd(QMouseEvent *e)
Chris@21 591 {
Chris@21 592 std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 593 if (!m_model || !m_editing) return;
Chris@22 594 m_editingCommand->finish();
Chris@22 595 m_editingCommand = 0;
Chris@21 596 m_editing = false;
Chris@21 597 }
Chris@21 598
Chris@21 599 void
Chris@21 600 TimeValueLayer::editStart(QMouseEvent *e)
Chris@21 601 {
Chris@21 602 std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 603
Chris@21 604 if (!m_model) return;
Chris@21 605
Chris@21 606 SparseTimeValueModel::PointList points = getLocalPoints(e->x());
Chris@21 607 if (points.empty()) return;
Chris@21 608
Chris@21 609 m_editingPoint = *points.begin();
Chris@23 610 m_originalPoint = m_editingPoint;
Chris@22 611
Chris@22 612 if (m_editingCommand) {
Chris@22 613 m_editingCommand->finish();
Chris@22 614 m_editingCommand = 0;
Chris@22 615 }
Chris@22 616
Chris@21 617 m_editing = true;
Chris@21 618 }
Chris@21 619
Chris@21 620 void
Chris@21 621 TimeValueLayer::editDrag(QMouseEvent *e)
Chris@21 622 {
Chris@21 623 std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 624
Chris@21 625 if (!m_model || !m_editing) return;
Chris@21 626
Chris@21 627 long frame = getFrameForX(e->x());
Chris@21 628 if (frame < 0) frame = 0;
Chris@21 629 frame = frame / m_model->getResolution() * m_model->getResolution();
Chris@21 630
Chris@21 631 float value = getValueForY(e->y());
Chris@21 632
Chris@22 633 if (!m_editingCommand) {
Chris@22 634 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
Chris@22 635 tr("Drag Point"));
Chris@22 636 }
Chris@22 637
Chris@22 638 m_editingCommand->deletePoint(m_editingPoint);
Chris@21 639 m_editingPoint.frame = frame;
Chris@21 640 m_editingPoint.value = value;
Chris@22 641 m_editingCommand->addPoint(m_editingPoint);
Chris@21 642 }
Chris@21 643
Chris@21 644 void
Chris@21 645 TimeValueLayer::editEnd(QMouseEvent *e)
Chris@21 646 {
Chris@21 647 std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
Chris@21 648 if (!m_model || !m_editing) return;
Chris@23 649
Chris@23 650 if (m_editingCommand) {
Chris@23 651
Chris@23 652 QString newName = m_editingCommand->getName();
Chris@23 653
Chris@23 654 if (m_editingPoint.frame != m_originalPoint.frame) {
Chris@23 655 if (m_editingPoint.value != m_originalPoint.value) {
Chris@23 656 newName = tr("Edit Point");
Chris@23 657 } else {
Chris@23 658 newName = tr("Relocate Point");
Chris@23 659 }
Chris@23 660 } else {
Chris@23 661 newName = tr("Change Point Value");
Chris@23 662 }
Chris@23 663
Chris@23 664 m_editingCommand->setName(newName);
Chris@23 665 m_editingCommand->finish();
Chris@23 666 }
Chris@23 667
Chris@22 668 m_editingCommand = 0;
Chris@21 669 m_editing = false;
Chris@21 670 }
Chris@21 671
Chris@6 672 QString
Chris@6 673 TimeValueLayer::toXmlString(QString indent, QString extraAttributes) const
Chris@6 674 {
Chris@6 675 return Layer::toXmlString(indent, extraAttributes +
Chris@6 676 QString(" colour=\"%1\" plotStyle=\"%2\"")
Chris@6 677 .arg(encodeColour(m_colour)).arg(m_plotStyle));
Chris@0 678 }
Chris@0 679
Chris@11 680 void
Chris@11 681 TimeValueLayer::setProperties(const QXmlAttributes &attributes)
Chris@11 682 {
Chris@11 683 QString colourSpec = attributes.value("colour");
Chris@11 684 if (colourSpec != "") {
Chris@11 685 QColor colour(colourSpec);
Chris@11 686 if (colour.isValid()) {
Chris@11 687 setBaseColour(QColor(colourSpec));
Chris@11 688 }
Chris@11 689 }
Chris@11 690
Chris@11 691 bool ok;
Chris@11 692 PlotStyle style = (PlotStyle)
Chris@11 693 attributes.value("plotStyle").toInt(&ok);
Chris@11 694 if (ok) setPlotStyle(style);
Chris@11 695 }
Chris@11 696
Chris@0 697
Chris@0 698 #ifdef INCLUDE_MOCFILES
Chris@0 699 #include "TimeValueLayer.moc.cpp"
Chris@0 700 #endif
Chris@0 701