annotate layer/NoteLayer.cpp @ 38:beb801473743

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