00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "NoteLayer.h"
00017
00018 #include "data/model/Model.h"
00019 #include "base/RealTime.h"
00020 #include "base/Profiler.h"
00021 #include "base/Pitch.h"
00022 #include "base/LogRange.h"
00023 #include "base/ColourDatabase.h"
00024 #include "view/View.h"
00025
00026 #include "data/model/NoteModel.h"
00027
00028 #include "widgets/ItemEditDialog.h"
00029
00030 #include "SpectrogramLayer.h"
00031
00032 #include <QPainter>
00033 #include <QPainterPath>
00034 #include <QMouseEvent>
00035 #include <QTextStream>
00036 #include <QMessageBox>
00037
00038 #include <iostream>
00039 #include <cmath>
00040
00041 NoteLayer::NoteLayer() :
00042 SingleColourLayer(),
00043 m_model(0),
00044 m_editing(false),
00045 m_originalPoint(0, 0.0, 0, 1.f, tr("New Point")),
00046 m_editingPoint(0, 0.0, 0, 1.f, tr("New Point")),
00047 m_editingCommand(0),
00048 m_verticalScale(AutoAlignScale)
00049 {
00050
00051 }
00052
00053 void
00054 NoteLayer::setModel(NoteModel *model)
00055 {
00056 if (m_model == model) return;
00057 m_model = model;
00058
00059 connectSignals(m_model);
00060
00061
00062
00063 emit modelReplaced();
00064 }
00065
00066 Layer::PropertyList
00067 NoteLayer::getProperties() const
00068 {
00069 PropertyList list = SingleColourLayer::getProperties();
00070 list.push_back("Vertical Scale");
00071 list.push_back("Scale Units");
00072 return list;
00073 }
00074
00075 QString
00076 NoteLayer::getPropertyLabel(const PropertyName &name) const
00077 {
00078 if (name == "Vertical Scale") return tr("Vertical Scale");
00079 if (name == "Scale Units") return tr("Scale Units");
00080 return SingleColourLayer::getPropertyLabel(name);
00081 }
00082
00083 Layer::PropertyType
00084 NoteLayer::getPropertyType(const PropertyName &name) const
00085 {
00086 if (name == "Scale Units") return UnitsProperty;
00087 if (name == "Vertical Scale") return ValueProperty;
00088 return SingleColourLayer::getPropertyType(name);
00089 }
00090
00091 QString
00092 NoteLayer::getPropertyGroupName(const PropertyName &name) const
00093 {
00094 if (name == "Vertical Scale" || name == "Scale Units") {
00095 return tr("Scale");
00096 }
00097 return SingleColourLayer::getPropertyGroupName(name);
00098 }
00099
00100 int
00101 NoteLayer::getPropertyRangeAndValue(const PropertyName &name,
00102 int *min, int *max, int *deflt) const
00103 {
00104 int val = 0;
00105
00106 if (name == "Vertical Scale") {
00107
00108 if (min) *min = 0;
00109 if (max) *max = 3;
00110 if (deflt) *deflt = int(AutoAlignScale);
00111
00112 val = int(m_verticalScale);
00113
00114 } else if (name == "Scale Units") {
00115
00116 if (deflt) *deflt = 0;
00117 if (m_model) {
00118 val = UnitDatabase::getInstance()->getUnitId
00119 (m_model->getScaleUnits());
00120 }
00121
00122 } else {
00123
00124 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
00125 }
00126
00127 return val;
00128 }
00129
00130 QString
00131 NoteLayer::getPropertyValueLabel(const PropertyName &name,
00132 int value) const
00133 {
00134 if (name == "Vertical Scale") {
00135 switch (value) {
00136 default:
00137 case 0: return tr("Auto-Align");
00138 case 1: return tr("Linear");
00139 case 2: return tr("Log");
00140 case 3: return tr("MIDI Notes");
00141 }
00142 }
00143 return SingleColourLayer::getPropertyValueLabel(name, value);
00144 }
00145
00146 void
00147 NoteLayer::setProperty(const PropertyName &name, int value)
00148 {
00149 if (name == "Vertical Scale") {
00150 setVerticalScale(VerticalScale(value));
00151 } else if (name == "Scale Units") {
00152 if (m_model) {
00153 m_model->setScaleUnits
00154 (UnitDatabase::getInstance()->getUnitById(value));
00155 emit modelChanged();
00156 }
00157 } else {
00158 return SingleColourLayer::setProperty(name, value);
00159 }
00160 }
00161
00162 void
00163 NoteLayer::setVerticalScale(VerticalScale scale)
00164 {
00165 if (m_verticalScale == scale) return;
00166 m_verticalScale = scale;
00167 emit layerParametersChanged();
00168 }
00169
00170 bool
00171 NoteLayer::isLayerScrollable(const View *v) const
00172 {
00173 QPoint discard;
00174 return !v->shouldIlluminateLocalFeatures(this, discard);
00175 }
00176
00177 bool
00178 NoteLayer::shouldConvertMIDIToHz() const
00179 {
00180 QString unit = m_model->getScaleUnits();
00181 return (unit != "Hz");
00182
00183
00184
00185
00186 }
00187
00188 bool
00189 NoteLayer::getValueExtents(float &min, float &max,
00190 bool &logarithmic, QString &unit) const
00191 {
00192 if (!m_model) return false;
00193 min = m_model->getValueMinimum();
00194 max = m_model->getValueMaximum();
00195
00196 if (shouldConvertMIDIToHz()) {
00197 unit = "Hz";
00198 min = Pitch::getFrequencyForPitch(lrintf(min));
00199 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
00200 } else unit = m_model->getScaleUnits();
00201
00202 if (m_verticalScale == MIDIRangeScale ||
00203 m_verticalScale == LogScale) logarithmic = true;
00204
00205 return true;
00206 }
00207
00208 bool
00209 NoteLayer::getDisplayExtents(float &min, float &max) const
00210 {
00211 if (!m_model || m_verticalScale == AutoAlignScale) return false;
00212
00213 if (m_verticalScale == MIDIRangeScale) {
00214 min = Pitch::getFrequencyForPitch(0);
00215 max = Pitch::getFrequencyForPitch(127);
00216 return true;
00217 }
00218
00219 min = m_model->getValueMinimum();
00220 max = m_model->getValueMaximum();
00221
00222 if (shouldConvertMIDIToHz()) {
00223 min = Pitch::getFrequencyForPitch(lrintf(min));
00224 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
00225 }
00226
00227 return true;
00228 }
00229
00230 NoteModel::PointList
00231 NoteLayer::getLocalPoints(View *v, int x) const
00232 {
00233 if (!m_model) return NoteModel::PointList();
00234
00235 long frame = v->getFrameForX(x);
00236
00237 NoteModel::PointList onPoints =
00238 m_model->getPoints(frame);
00239
00240 if (!onPoints.empty()) {
00241 return onPoints;
00242 }
00243
00244 NoteModel::PointList prevPoints =
00245 m_model->getPreviousPoints(frame);
00246 NoteModel::PointList nextPoints =
00247 m_model->getNextPoints(frame);
00248
00249 NoteModel::PointList usePoints = prevPoints;
00250
00251 if (prevPoints.empty()) {
00252 usePoints = nextPoints;
00253 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
00254 !(nextPoints.begin()->frame > v->getEndFrame())) {
00255 usePoints = nextPoints;
00256 } else if (long(nextPoints.begin()->frame) - frame <
00257 frame - long(prevPoints.begin()->frame)) {
00258 usePoints = nextPoints;
00259 }
00260
00261 if (!usePoints.empty()) {
00262 int fuzz = 2;
00263 int px = v->getXForFrame(usePoints.begin()->frame);
00264 if ((px > x && px - x > fuzz) ||
00265 (px < x && x - px > fuzz + 1)) {
00266 usePoints.clear();
00267 }
00268 }
00269
00270 return usePoints;
00271 }
00272
00273 QString
00274 NoteLayer::getFeatureDescription(View *v, QPoint &pos) const
00275 {
00276 int x = pos.x();
00277
00278 if (!m_model || !m_model->getSampleRate()) return "";
00279
00280 NoteModel::PointList points = getLocalPoints(v, x);
00281
00282 if (points.empty()) {
00283 if (!m_model->isReady()) {
00284 return tr("In progress");
00285 } else {
00286 return tr("No local points");
00287 }
00288 }
00289
00290 Note note(0);
00291 NoteModel::PointList::iterator i;
00292
00293 for (i = points.begin(); i != points.end(); ++i) {
00294
00295 int y = getYForValue(v, i->value);
00296 int h = 3;
00297
00298 if (m_model->getValueQuantization() != 0.0) {
00299 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
00300 if (h < 3) h = 3;
00301 }
00302
00303 if (pos.y() >= y - h && pos.y() <= y) {
00304 note = *i;
00305 break;
00306 }
00307 }
00308
00309 if (i == points.end()) return tr("No local points");
00310
00311 RealTime rt = RealTime::frame2RealTime(note.frame,
00312 m_model->getSampleRate());
00313 RealTime rd = RealTime::frame2RealTime(note.duration,
00314 m_model->getSampleRate());
00315
00316 QString pitchText;
00317
00318 if (shouldConvertMIDIToHz()) {
00319
00320 int mnote = lrintf(note.value);
00321 int cents = lrintf((note.value - mnote) * 100);
00322 float freq = Pitch::getFrequencyForPitch(mnote, cents);
00323 pitchText = tr("%1 (%2 Hz)")
00324 .arg(Pitch::getPitchLabel(mnote, cents)).arg(freq);
00325
00326 } else if (m_model->getScaleUnits() == "Hz") {
00327
00328 pitchText = tr("%1 Hz (%2)")
00329 .arg(note.value)
00330 .arg(Pitch::getPitchLabelForFrequency(note.value));
00331
00332 } else {
00333 pitchText = tr("%1 %2")
00334 .arg(note.value).arg(m_model->getScaleUnits());
00335 }
00336
00337 QString text;
00338
00339 if (note.label == "") {
00340 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nNo label"))
00341 .arg(rt.toText(true).c_str())
00342 .arg(pitchText)
00343 .arg(rd.toText(true).c_str());
00344 } else {
00345 text = QString(tr("Time:\t%1\nPitch:\t%2\nDuration:\t%3\nLabel:\t%4"))
00346 .arg(rt.toText(true).c_str())
00347 .arg(pitchText)
00348 .arg(rd.toText(true).c_str())
00349 .arg(note.label);
00350 }
00351
00352 pos = QPoint(v->getXForFrame(note.frame),
00353 getYForValue(v, note.value));
00354 return text;
00355 }
00356
00357 bool
00358 NoteLayer::snapToFeatureFrame(View *v, int &frame,
00359 size_t &resolution,
00360 SnapType snap) const
00361 {
00362 if (!m_model) {
00363 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
00364 }
00365
00366 resolution = m_model->getResolution();
00367 NoteModel::PointList points;
00368
00369 if (snap == SnapNeighbouring) {
00370
00371 points = getLocalPoints(v, v->getXForFrame(frame));
00372 if (points.empty()) return false;
00373 frame = points.begin()->frame;
00374 return true;
00375 }
00376
00377 points = m_model->getPoints(frame, frame);
00378 int snapped = frame;
00379 bool found = false;
00380
00381 for (NoteModel::PointList::const_iterator i = points.begin();
00382 i != points.end(); ++i) {
00383
00384 if (snap == SnapRight) {
00385
00386 if (i->frame > frame) {
00387 snapped = i->frame;
00388 found = true;
00389 break;
00390 }
00391
00392 } else if (snap == SnapLeft) {
00393
00394 if (i->frame <= frame) {
00395 snapped = i->frame;
00396 found = true;
00397 } else {
00398 break;
00399 }
00400
00401 } else {
00402
00403 NoteModel::PointList::const_iterator j = i;
00404 ++j;
00405
00406 if (j == points.end()) {
00407
00408 snapped = i->frame;
00409 found = true;
00410 break;
00411
00412 } else if (j->frame >= frame) {
00413
00414 if (j->frame - frame < frame - i->frame) {
00415 snapped = j->frame;
00416 } else {
00417 snapped = i->frame;
00418 }
00419 found = true;
00420 break;
00421 }
00422 }
00423 }
00424
00425 frame = snapped;
00426 return found;
00427 }
00428
00429 void
00430 NoteLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
00431 {
00432 min = 0.0;
00433 max = 0.0;
00434 log = false;
00435
00436 QString queryUnits;
00437 if (shouldConvertMIDIToHz()) queryUnits = "Hz";
00438 else queryUnits = m_model->getScaleUnits();
00439
00440 if (m_verticalScale == AutoAlignScale) {
00441
00442 if (!v->getValueExtents(queryUnits, min, max, log)) {
00443
00444 min = m_model->getValueMinimum();
00445 max = m_model->getValueMaximum();
00446
00447 if (shouldConvertMIDIToHz()) {
00448 min = Pitch::getFrequencyForPitch(lrintf(min));
00449 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
00450 }
00451
00452 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
00453
00454 } else if (log) {
00455
00456 LogRange::mapRange(min, max);
00457
00458 std::cerr << "NoteLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
00459
00460 }
00461
00462 } else {
00463
00464 min = m_model->getValueMinimum();
00465 max = m_model->getValueMaximum();
00466
00467 if (m_verticalScale == MIDIRangeScale) {
00468 min = Pitch::getFrequencyForPitch(0);
00469 max = Pitch::getFrequencyForPitch(127);
00470 } else if (shouldConvertMIDIToHz()) {
00471 min = Pitch::getFrequencyForPitch(lrintf(min));
00472 max = Pitch::getFrequencyForPitch(lrintf(max + 1));
00473 }
00474
00475 if (m_verticalScale == LogScale || m_verticalScale == MIDIRangeScale) {
00476 LogRange::mapRange(min, max);
00477 log = true;
00478 }
00479 }
00480
00481 if (max == min) max = min + 1.0;
00482 }
00483
00484 int
00485 NoteLayer::getYForValue(View *v, float val) const
00486 {
00487 float min = 0.0, max = 0.0;
00488 bool logarithmic = false;
00489 int h = v->height();
00490
00491 getScaleExtents(v, min, max, logarithmic);
00492
00493
00494
00495 if (shouldConvertMIDIToHz()) {
00496 val = Pitch::getFrequencyForPitch(lrintf(val),
00497 lrintf((val - lrintf(val)) * 100));
00498
00499 }
00500
00501 if (logarithmic) {
00502 val = LogRange::map(val);
00503
00504 }
00505
00506 int y = int(h - ((val - min) * h) / (max - min)) - 1;
00507
00508 return y;
00509 }
00510
00511 float
00512 NoteLayer::getValueForY(View *v, int y) const
00513 {
00514 float min = 0.0, max = 0.0;
00515 bool logarithmic = false;
00516 int h = v->height();
00517
00518 getScaleExtents(v, min, max, logarithmic);
00519
00520 float val = min + (float(h - y) * float(max - min)) / h;
00521
00522 if (logarithmic) {
00523 val = powf(10.f, val);
00524 }
00525
00526 if (shouldConvertMIDIToHz()) {
00527 val = Pitch::getPitchForFrequency(val);
00528 }
00529
00530 return val;
00531 }
00532
00533 void
00534 NoteLayer::paint(View *v, QPainter &paint, QRect rect) const
00535 {
00536 if (!m_model || !m_model->isOK()) return;
00537
00538 int sampleRate = m_model->getSampleRate();
00539 if (!sampleRate) return;
00540
00541
00542
00543 int x0 = rect.left(), x1 = rect.right();
00544 long frame0 = v->getFrameForX(x0);
00545 long frame1 = v->getFrameForX(x1);
00546
00547 NoteModel::PointList points(m_model->getPoints(frame0, frame1));
00548 if (points.empty()) return;
00549
00550 paint.setPen(getBaseQColor());
00551
00552 QColor brushColour(getBaseQColor());
00553 brushColour.setAlpha(80);
00554
00555
00556
00557
00558 float min = m_model->getValueMinimum();
00559 float max = m_model->getValueMaximum();
00560 if (max == min) max = min + 1.0;
00561
00562 QPoint localPos;
00563 long illuminateFrame = -1;
00564
00565 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
00566 NoteModel::PointList localPoints =
00567 getLocalPoints(v, localPos.x());
00568 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
00569 }
00570
00571 paint.save();
00572 paint.setRenderHint(QPainter::Antialiasing, false);
00573
00574 for (NoteModel::PointList::const_iterator i = points.begin();
00575 i != points.end(); ++i) {
00576
00577 const NoteModel::Point &p(*i);
00578
00579 int x = v->getXForFrame(p.frame);
00580 int y = getYForValue(v, p.value);
00581 int w = v->getXForFrame(p.frame + p.duration) - x;
00582 int h = 3;
00583
00584 if (m_model->getValueQuantization() != 0.0) {
00585 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
00586 if (h < 3) h = 3;
00587 }
00588
00589 if (w < 1) w = 1;
00590 paint.setPen(getBaseQColor());
00591 paint.setBrush(brushColour);
00592
00593 if (illuminateFrame == p.frame) {
00594 if (localPos.y() >= y - h && localPos.y() < y) {
00595 paint.setPen(v->getForeground());
00596 paint.setBrush(v->getForeground());
00597 }
00598 }
00599
00600 paint.drawRect(x, y - h/2, w, h);
00601
00605 }
00606
00607 paint.restore();
00608 }
00609
00610 void
00611 NoteLayer::drawStart(View *v, QMouseEvent *e)
00612 {
00613
00614
00615 if (!m_model) return;
00616
00617 long frame = v->getFrameForX(e->x());
00618 if (frame < 0) frame = 0;
00619 frame = frame / m_model->getResolution() * m_model->getResolution();
00620
00621 float value = getValueForY(v, e->y());
00622
00623 m_editingPoint = NoteModel::Point(frame, value, 0, 0.8, tr("New Point"));
00624 m_originalPoint = m_editingPoint;
00625
00626 if (m_editingCommand) m_editingCommand->finish();
00627 m_editingCommand = new NoteModel::EditCommand(m_model,
00628 tr("Draw Point"));
00629 m_editingCommand->addPoint(m_editingPoint);
00630
00631 m_editing = true;
00632 }
00633
00634 void
00635 NoteLayer::drawDrag(View *v, QMouseEvent *e)
00636 {
00637
00638
00639 if (!m_model || !m_editing) return;
00640
00641 long frame = v->getFrameForX(e->x());
00642 if (frame < 0) frame = 0;
00643 frame = frame / m_model->getResolution() * m_model->getResolution();
00644
00645 float newValue = getValueForY(v, e->y());
00646
00647 long newFrame = m_editingPoint.frame;
00648 long newDuration = frame - newFrame;
00649 if (newDuration < 0) {
00650 newFrame = frame;
00651 newDuration = -newDuration;
00652 } else if (newDuration == 0) {
00653 newDuration = 1;
00654 }
00655
00656 m_editingCommand->deletePoint(m_editingPoint);
00657 m_editingPoint.frame = newFrame;
00658 m_editingPoint.value = newValue;
00659 m_editingPoint.duration = newDuration;
00660 m_editingCommand->addPoint(m_editingPoint);
00661 }
00662
00663 void
00664 NoteLayer::drawEnd(View *, QMouseEvent *)
00665 {
00666
00667 if (!m_model || !m_editing) return;
00668 m_editingCommand->finish();
00669 m_editingCommand = 0;
00670 m_editing = false;
00671 }
00672
00673 void
00674 NoteLayer::eraseStart(View *v, QMouseEvent *e)
00675 {
00676 if (!m_model) return;
00677
00678 NoteModel::PointList points = getLocalPoints(v, e->x());
00679 if (points.empty()) return;
00680
00681 m_editingPoint = *points.begin();
00682
00683 if (m_editingCommand) {
00684 m_editingCommand->finish();
00685 m_editingCommand = 0;
00686 }
00687
00688 m_editing = true;
00689 }
00690
00691 void
00692 NoteLayer::eraseDrag(View *v, QMouseEvent *e)
00693 {
00694 }
00695
00696 void
00697 NoteLayer::eraseEnd(View *v, QMouseEvent *e)
00698 {
00699 if (!m_model || !m_editing) return;
00700
00701 m_editing = false;
00702
00703 NoteModel::PointList points = getLocalPoints(v, e->x());
00704 if (points.empty()) return;
00705 if (points.begin()->frame != m_editingPoint.frame ||
00706 points.begin()->value != m_editingPoint.value) return;
00707
00708 m_editingCommand = new NoteModel::EditCommand
00709 (m_model, tr("Erase Point"));
00710
00711 m_editingCommand->deletePoint(m_editingPoint);
00712
00713 m_editingCommand->finish();
00714 m_editingCommand = 0;
00715 m_editing = false;
00716 }
00717
00718 void
00719 NoteLayer::editStart(View *v, QMouseEvent *e)
00720 {
00721
00722
00723 if (!m_model) return;
00724
00725 NoteModel::PointList points = getLocalPoints(v, e->x());
00726 if (points.empty()) return;
00727
00728 m_editingPoint = *points.begin();
00729 m_originalPoint = m_editingPoint;
00730
00731 if (m_editingCommand) {
00732 m_editingCommand->finish();
00733 m_editingCommand = 0;
00734 }
00735
00736 m_editing = true;
00737 }
00738
00739 void
00740 NoteLayer::editDrag(View *v, QMouseEvent *e)
00741 {
00742
00743
00744 if (!m_model || !m_editing) return;
00745
00746 long frame = v->getFrameForX(e->x());
00747 if (frame < 0) frame = 0;
00748 frame = frame / m_model->getResolution() * m_model->getResolution();
00749
00750 float value = getValueForY(v, e->y());
00751
00752 if (!m_editingCommand) {
00753 m_editingCommand = new NoteModel::EditCommand(m_model,
00754 tr("Drag Point"));
00755 }
00756
00757 m_editingCommand->deletePoint(m_editingPoint);
00758 m_editingPoint.frame = frame;
00759 m_editingPoint.value = value;
00760 m_editingCommand->addPoint(m_editingPoint);
00761 }
00762
00763 void
00764 NoteLayer::editEnd(View *, QMouseEvent *)
00765 {
00766
00767 if (!m_model || !m_editing) return;
00768
00769 if (m_editingCommand) {
00770
00771 QString newName = m_editingCommand->getName();
00772
00773 if (m_editingPoint.frame != m_originalPoint.frame) {
00774 if (m_editingPoint.value != m_originalPoint.value) {
00775 newName = tr("Edit Point");
00776 } else {
00777 newName = tr("Relocate Point");
00778 }
00779 } else {
00780 newName = tr("Change Point Value");
00781 }
00782
00783 m_editingCommand->setName(newName);
00784 m_editingCommand->finish();
00785 }
00786
00787 m_editingCommand = 0;
00788 m_editing = false;
00789 }
00790
00791 bool
00792 NoteLayer::editOpen(View *v, QMouseEvent *e)
00793 {
00794 if (!m_model) return false;
00795
00796 NoteModel::PointList points = getLocalPoints(v, e->x());
00797 if (points.empty()) return false;
00798
00799 NoteModel::Point note = *points.begin();
00800
00801 ItemEditDialog *dialog = new ItemEditDialog
00802 (m_model->getSampleRate(),
00803 ItemEditDialog::ShowTime |
00804 ItemEditDialog::ShowDuration |
00805 ItemEditDialog::ShowValue |
00806 ItemEditDialog::ShowText,
00807 m_model->getScaleUnits());
00808
00809 dialog->setFrameTime(note.frame);
00810 dialog->setValue(note.value);
00811 dialog->setFrameDuration(note.duration);
00812 dialog->setText(note.label);
00813
00814 if (dialog->exec() == QDialog::Accepted) {
00815
00816 NoteModel::Point newNote = note;
00817 newNote.frame = dialog->getFrameTime();
00818 newNote.value = dialog->getValue();
00819 newNote.duration = dialog->getFrameDuration();
00820 newNote.label = dialog->getText();
00821
00822 NoteModel::EditCommand *command = new NoteModel::EditCommand
00823 (m_model, tr("Edit Point"));
00824 command->deletePoint(note);
00825 command->addPoint(newNote);
00826 command->finish();
00827 }
00828
00829 delete dialog;
00830 return true;
00831 }
00832
00833 void
00834 NoteLayer::moveSelection(Selection s, size_t newStartFrame)
00835 {
00836 if (!m_model) return;
00837
00838 NoteModel::EditCommand *command =
00839 new NoteModel::EditCommand(m_model, tr("Drag Selection"));
00840
00841 NoteModel::PointList points =
00842 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00843
00844 for (NoteModel::PointList::iterator i = points.begin();
00845 i != points.end(); ++i) {
00846
00847 if (s.contains(i->frame)) {
00848 NoteModel::Point newPoint(*i);
00849 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
00850 command->deletePoint(*i);
00851 command->addPoint(newPoint);
00852 }
00853 }
00854
00855 command->finish();
00856 }
00857
00858 void
00859 NoteLayer::resizeSelection(Selection s, Selection newSize)
00860 {
00861 if (!m_model) return;
00862
00863 NoteModel::EditCommand *command =
00864 new NoteModel::EditCommand(m_model, tr("Resize Selection"));
00865
00866 NoteModel::PointList points =
00867 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00868
00869 double ratio =
00870 double(newSize.getEndFrame() - newSize.getStartFrame()) /
00871 double(s.getEndFrame() - s.getStartFrame());
00872
00873 for (NoteModel::PointList::iterator i = points.begin();
00874 i != points.end(); ++i) {
00875
00876 if (s.contains(i->frame)) {
00877
00878 double targetStart = i->frame;
00879 targetStart = newSize.getStartFrame() +
00880 double(targetStart - s.getStartFrame()) * ratio;
00881
00882 double targetEnd = i->frame + i->duration;
00883 targetEnd = newSize.getStartFrame() +
00884 double(targetEnd - s.getStartFrame()) * ratio;
00885
00886 NoteModel::Point newPoint(*i);
00887 newPoint.frame = lrint(targetStart);
00888 newPoint.duration = lrint(targetEnd - targetStart);
00889 command->deletePoint(*i);
00890 command->addPoint(newPoint);
00891 }
00892 }
00893
00894 command->finish();
00895 }
00896
00897 void
00898 NoteLayer::deleteSelection(Selection s)
00899 {
00900 if (!m_model) return;
00901
00902 NoteModel::EditCommand *command =
00903 new NoteModel::EditCommand(m_model, tr("Delete Selected Points"));
00904
00905 NoteModel::PointList points =
00906 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00907
00908 for (NoteModel::PointList::iterator i = points.begin();
00909 i != points.end(); ++i) {
00910
00911 if (s.contains(i->frame)) {
00912 command->deletePoint(*i);
00913 }
00914 }
00915
00916 command->finish();
00917 }
00918
00919 void
00920 NoteLayer::copy(View *v, Selection s, Clipboard &to)
00921 {
00922 if (!m_model) return;
00923
00924 NoteModel::PointList points =
00925 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
00926
00927 for (NoteModel::PointList::iterator i = points.begin();
00928 i != points.end(); ++i) {
00929 if (s.contains(i->frame)) {
00930 Clipboard::Point point(i->frame, i->value, i->duration, i->level, i->label);
00931 point.setReferenceFrame(alignToReference(v, i->frame));
00932 to.addPoint(point);
00933 }
00934 }
00935 }
00936
00937 bool
00938 NoteLayer::paste(View *v, const Clipboard &from, int frameOffset, bool )
00939 {
00940 if (!m_model) return false;
00941
00942 const Clipboard::PointList &points = from.getPoints();
00943
00944 bool realign = false;
00945
00946 if (clipboardHasDifferentAlignment(v, from)) {
00947
00948 QMessageBox::StandardButton button =
00949 QMessageBox::question(v, tr("Re-align pasted items?"),
00950 tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"),
00951 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
00952 QMessageBox::Yes);
00953
00954 if (button == QMessageBox::Cancel) {
00955 return false;
00956 }
00957
00958 if (button == QMessageBox::Yes) {
00959 realign = true;
00960 }
00961 }
00962
00963 NoteModel::EditCommand *command =
00964 new NoteModel::EditCommand(m_model, tr("Paste"));
00965
00966 for (Clipboard::PointList::const_iterator i = points.begin();
00967 i != points.end(); ++i) {
00968
00969 if (!i->haveFrame()) continue;
00970 size_t frame = 0;
00971
00972 if (!realign) {
00973
00974 frame = i->getFrame();
00975
00976 } else {
00977
00978 if (i->haveReferenceFrame()) {
00979 frame = i->getReferenceFrame();
00980 frame = alignFromReference(v, frame);
00981 } else {
00982 frame = i->getFrame();
00983 }
00984 }
00985
00986 NoteModel::Point newPoint(frame);
00987
00988 if (i->haveLabel()) newPoint.label = i->getLabel();
00989 if (i->haveValue()) newPoint.value = i->getValue();
00990 else newPoint.value = (m_model->getValueMinimum() +
00991 m_model->getValueMaximum()) / 2;
00992 if (i->haveLevel()) newPoint.level = i->getLevel();
00993 if (i->haveDuration()) newPoint.duration = i->getDuration();
00994 else {
00995 size_t nextFrame = frame;
00996 Clipboard::PointList::const_iterator j = i;
00997 for (; j != points.end(); ++j) {
00998 if (!j->haveFrame()) continue;
00999 if (j != i) break;
01000 }
01001 if (j != points.end()) {
01002 nextFrame = j->getFrame();
01003 }
01004 if (nextFrame == frame) {
01005 newPoint.duration = m_model->getResolution();
01006 } else {
01007 newPoint.duration = nextFrame - frame;
01008 }
01009 }
01010
01011 command->addPoint(newPoint);
01012 }
01013
01014 command->finish();
01015 return true;
01016 }
01017
01018 int
01019 NoteLayer::getDefaultColourHint(bool darkbg, bool &impose)
01020 {
01021 impose = false;
01022 return ColourDatabase::getInstance()->getColourIndex
01023 (QString(darkbg ? "White" : "Black"));
01024 }
01025
01026 void
01027 NoteLayer::toXml(QTextStream &stream,
01028 QString indent, QString extraAttributes) const
01029 {
01030 SingleColourLayer::toXml(stream, indent, extraAttributes +
01031 QString(" verticalScale=\"%1\"")
01032 .arg(m_verticalScale));
01033 }
01034
01035 void
01036 NoteLayer::setProperties(const QXmlAttributes &attributes)
01037 {
01038 SingleColourLayer::setProperties(attributes);
01039
01040 bool ok;
01041 VerticalScale scale = (VerticalScale)
01042 attributes.value("verticalScale").toInt(&ok);
01043 if (ok) setVerticalScale(scale);
01044 }
01045
01046