comparison layer/RegionLayer.cpp @ 411:96e4d7b9e165

* Add region model and layer; improve assignment of model types to feature extraction transforms with duration
author Chris Cannam
date Thu, 18 Sep 2008 16:08:14 +0000
parents
children d332ad1ca66b
comparison
equal deleted inserted replaced
410:33b7f5e54d60 411:96e4d7b9e165
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006-2008 Chris Cannam and QMUL.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #include "RegionLayer.h"
17
18 #include "data/model/Model.h"
19 #include "base/RealTime.h"
20 #include "base/Profiler.h"
21 #include "base/LogRange.h"
22 #include "ColourDatabase.h"
23 #include "view/View.h"
24
25 #include "data/model/RegionModel.h"
26
27 #include "widgets/ItemEditDialog.h"
28
29 #include "SpectrogramLayer.h" // for optional frequency alignment
30
31 #include <QPainter>
32 #include <QPainterPath>
33 #include <QMouseEvent>
34 #include <QTextStream>
35 #include <QMessageBox>
36
37 #include <iostream>
38 #include <cmath>
39
40 RegionLayer::RegionLayer() :
41 SingleColourLayer(),
42 m_model(0),
43 m_editing(false),
44 m_originalPoint(0, 0.0, 0, tr("New Point")),
45 m_editingPoint(0, 0.0, 0, tr("New Point")),
46 m_editingCommand(0),
47 m_verticalScale(AutoAlignScale)
48 {
49
50 }
51
52 void
53 RegionLayer::setModel(RegionModel *model)
54 {
55 if (m_model == model) return;
56 m_model = model;
57
58 connectSignals(m_model);
59
60 // std::cerr << "RegionLayer::setModel(" << model << ")" << std::endl;
61
62 emit modelReplaced();
63 }
64
65 Layer::PropertyList
66 RegionLayer::getProperties() const
67 {
68 PropertyList list = SingleColourLayer::getProperties();
69 list.push_back("Vertical Scale");
70 list.push_back("Scale Units");
71 return list;
72 }
73
74 QString
75 RegionLayer::getPropertyLabel(const PropertyName &name) const
76 {
77 if (name == "Vertical Scale") return tr("Vertical Scale");
78 if (name == "Scale Units") return tr("Scale Units");
79 return SingleColourLayer::getPropertyLabel(name);
80 }
81
82 Layer::PropertyType
83 RegionLayer::getPropertyType(const PropertyName &name) const
84 {
85 if (name == "Scale Units") return UnitsProperty;
86 if (name == "Vertical Scale") return ValueProperty;
87 return SingleColourLayer::getPropertyType(name);
88 }
89
90 QString
91 RegionLayer::getPropertyGroupName(const PropertyName &name) const
92 {
93 if (name == "Vertical Scale" || name == "Scale Units") {
94 return tr("Scale");
95 }
96 return SingleColourLayer::getPropertyGroupName(name);
97 }
98
99 int
100 RegionLayer::getPropertyRangeAndValue(const PropertyName &name,
101 int *min, int *max, int *deflt) const
102 {
103 int val = 0;
104
105 if (name == "Vertical Scale") {
106
107 if (min) *min = 0;
108 if (max) *max = 3;
109 if (deflt) *deflt = int(AutoAlignScale);
110
111 val = int(m_verticalScale);
112
113 } else if (name == "Scale Units") {
114
115 if (deflt) *deflt = 0;
116 if (m_model) {
117 val = UnitDatabase::getInstance()->getUnitId
118 (m_model->getScaleUnits());
119 }
120
121 } else {
122
123 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
124 }
125
126 return val;
127 }
128
129 QString
130 RegionLayer::getPropertyValueLabel(const PropertyName &name,
131 int value) const
132 {
133 if (name == "Vertical Scale") {
134 switch (value) {
135 default:
136 case 0: return tr("Auto-Align");
137 case 1: return tr("Linear");
138 case 2: return tr("Log");
139 }
140 }
141 return SingleColourLayer::getPropertyValueLabel(name, value);
142 }
143
144 void
145 RegionLayer::setProperty(const PropertyName &name, int value)
146 {
147 if (name == "Vertical Scale") {
148 setVerticalScale(VerticalScale(value));
149 } else if (name == "Scale Units") {
150 if (m_model) {
151 m_model->setScaleUnits
152 (UnitDatabase::getInstance()->getUnitById(value));
153 emit modelChanged();
154 }
155 } else {
156 return SingleColourLayer::setProperty(name, value);
157 }
158 }
159
160 void
161 RegionLayer::setVerticalScale(VerticalScale scale)
162 {
163 if (m_verticalScale == scale) return;
164 m_verticalScale = scale;
165 emit layerParametersChanged();
166 }
167
168 bool
169 RegionLayer::isLayerScrollable(const View *v) const
170 {
171 QPoint discard;
172 return !v->shouldIlluminateLocalFeatures(this, discard);
173 }
174
175 bool
176 RegionLayer::getValueExtents(float &min, float &max,
177 bool &logarithmic, QString &unit) const
178 {
179 if (!m_model) return false;
180 min = m_model->getValueMinimum();
181 max = m_model->getValueMaximum();
182 unit = m_model->getScaleUnits();
183
184 if (m_verticalScale == LogScale) logarithmic = true;
185
186 return true;
187 }
188
189 bool
190 RegionLayer::getDisplayExtents(float &min, float &max) const
191 {
192 if (!m_model || m_verticalScale == AutoAlignScale) return false;
193
194 min = m_model->getValueMinimum();
195 max = m_model->getValueMaximum();
196
197 return true;
198 }
199
200 RegionModel::PointList
201 RegionLayer::getLocalPoints(View *v, int x) const
202 {
203 if (!m_model) return RegionModel::PointList();
204
205 long frame = v->getFrameForX(x);
206
207 RegionModel::PointList onPoints =
208 m_model->getPoints(frame);
209
210 if (!onPoints.empty()) {
211 return onPoints;
212 }
213
214 RegionModel::PointList prevPoints =
215 m_model->getPreviousPoints(frame);
216 RegionModel::PointList nextPoints =
217 m_model->getNextPoints(frame);
218
219 RegionModel::PointList usePoints = prevPoints;
220
221 if (prevPoints.empty()) {
222 usePoints = nextPoints;
223 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
224 !(nextPoints.begin()->frame > v->getEndFrame())) {
225 usePoints = nextPoints;
226 } else if (long(nextPoints.begin()->frame) - frame <
227 frame - long(prevPoints.begin()->frame)) {
228 usePoints = nextPoints;
229 }
230
231 if (!usePoints.empty()) {
232 int fuzz = 2;
233 int px = v->getXForFrame(usePoints.begin()->frame);
234 if ((px > x && px - x > fuzz) ||
235 (px < x && x - px > fuzz + 1)) {
236 usePoints.clear();
237 }
238 }
239
240 return usePoints;
241 }
242
243 QString
244 RegionLayer::getFeatureDescription(View *v, QPoint &pos) const
245 {
246 int x = pos.x();
247
248 if (!m_model || !m_model->getSampleRate()) return "";
249
250 RegionModel::PointList points = getLocalPoints(v, x);
251
252 if (points.empty()) {
253 if (!m_model->isReady()) {
254 return tr("In progress");
255 } else {
256 return tr("No local points");
257 }
258 }
259
260 RegionRec region(0);
261 RegionModel::PointList::iterator i;
262
263 for (i = points.begin(); i != points.end(); ++i) {
264
265 int y = getYForValue(v, i->value);
266 int h = 3;
267
268 if (m_model->getValueQuantization() != 0.0) {
269 h = y - getYForValue(v, i->value + m_model->getValueQuantization());
270 if (h < 3) h = 3;
271 }
272
273 if (pos.y() >= y - h && pos.y() <= y) {
274 region = *i;
275 break;
276 }
277 }
278
279 if (i == points.end()) return tr("No local points");
280
281 RealTime rt = RealTime::frame2RealTime(region.frame,
282 m_model->getSampleRate());
283 RealTime rd = RealTime::frame2RealTime(region.duration,
284 m_model->getSampleRate());
285
286 QString valueText;
287
288 valueText = tr("%1 %2").arg(region.value).arg(m_model->getScaleUnits());
289
290 QString text;
291
292 if (region.label == "") {
293 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label"))
294 .arg(rt.toText(true).c_str())
295 .arg(valueText)
296 .arg(rd.toText(true).c_str());
297 } else {
298 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4"))
299 .arg(rt.toText(true).c_str())
300 .arg(valueText)
301 .arg(rd.toText(true).c_str())
302 .arg(region.label);
303 }
304
305 pos = QPoint(v->getXForFrame(region.frame),
306 getYForValue(v, region.value));
307 return text;
308 }
309
310 bool
311 RegionLayer::snapToFeatureFrame(View *v, int &frame,
312 size_t &resolution,
313 SnapType snap) const
314 {
315 if (!m_model) {
316 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
317 }
318
319 resolution = m_model->getResolution();
320 RegionModel::PointList points;
321
322 if (snap == SnapNeighbouring) {
323
324 points = getLocalPoints(v, v->getXForFrame(frame));
325 if (points.empty()) return false;
326 frame = points.begin()->frame;
327 return true;
328 }
329
330 points = m_model->getPoints(frame, frame);
331 int snapped = frame;
332 bool found = false;
333
334 for (RegionModel::PointList::const_iterator i = points.begin();
335 i != points.end(); ++i) {
336
337 if (snap == SnapRight) {
338
339 if (i->frame > frame) {
340 snapped = i->frame;
341 found = true;
342 break;
343 }
344
345 } else if (snap == SnapLeft) {
346
347 if (i->frame <= frame) {
348 snapped = i->frame;
349 found = true; // don't break, as the next may be better
350 } else {
351 break;
352 }
353
354 } else { // nearest
355
356 RegionModel::PointList::const_iterator j = i;
357 ++j;
358
359 if (j == points.end()) {
360
361 snapped = i->frame;
362 found = true;
363 break;
364
365 } else if (j->frame >= frame) {
366
367 if (j->frame - frame < frame - i->frame) {
368 snapped = j->frame;
369 } else {
370 snapped = i->frame;
371 }
372 found = true;
373 break;
374 }
375 }
376 }
377
378 frame = snapped;
379 return found;
380 }
381
382 void
383 RegionLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
384 {
385 min = 0.0;
386 max = 0.0;
387 log = false;
388
389 QString queryUnits;
390 queryUnits = m_model->getScaleUnits();
391
392 if (m_verticalScale == AutoAlignScale) {
393
394 if (!v->getValueExtents(queryUnits, min, max, log)) {
395
396 min = m_model->getValueMinimum();
397 max = m_model->getValueMaximum();
398
399 std::cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
400
401 } else if (log) {
402
403 LogRange::mapRange(min, max);
404
405 std::cerr << "RegionLayer[" << this << "]::getScaleExtents: min = " << min << ", max = " << max << ", log = " << log << std::endl;
406
407 }
408
409 } else {
410
411 min = m_model->getValueMinimum();
412 max = m_model->getValueMaximum();
413
414 if (m_verticalScale == LogScale) {
415 LogRange::mapRange(min, max);
416 log = true;
417 }
418 }
419
420 if (max == min) max = min + 1.0;
421 }
422
423 int
424 RegionLayer::getYForValue(View *v, float val) const
425 {
426 float min = 0.0, max = 0.0;
427 bool logarithmic = false;
428 int h = v->height();
429
430 getScaleExtents(v, min, max, logarithmic);
431
432 // std::cerr << "RegionLayer[" << this << "]::getYForValue(" << val << "): min = " << min << ", max = " << max << ", log = " << logarithmic << std::endl;
433
434 if (logarithmic) {
435 val = LogRange::map(val);
436 // std::cerr << "logarithmic true, val now = " << val << std::endl;
437 }
438
439 int y = int(h - ((val - min) * h) / (max - min)) - 1;
440 // std::cerr << "y = " << y << std::endl;
441 return y;
442 }
443
444 float
445 RegionLayer::getValueForY(View *v, int y) const
446 {
447 float min = 0.0, max = 0.0;
448 bool logarithmic = false;
449 int h = v->height();
450
451 getScaleExtents(v, min, max, logarithmic);
452
453 float val = min + (float(h - y) * float(max - min)) / h;
454
455 if (logarithmic) {
456 val = powf(10.f, val);
457 }
458
459 return val;
460 }
461
462 void
463 RegionLayer::paint(View *v, QPainter &paint, QRect rect) const
464 {
465 if (!m_model || !m_model->isOK()) return;
466
467 int sampleRate = m_model->getSampleRate();
468 if (!sampleRate) return;
469
470 // Profiler profiler("RegionLayer::paint", true);
471
472 int x0 = rect.left(), x1 = rect.right();
473 long frame0 = v->getFrameForX(x0);
474 long frame1 = v->getFrameForX(x1);
475
476 RegionModel::PointList points(m_model->getPoints(frame0, frame1));
477 if (points.empty()) return;
478
479 paint.setPen(getBaseQColor());
480
481 QColor brushColour(getBaseQColor());
482 brushColour.setAlpha(80);
483
484 // std::cerr << "RegionLayer::paint: resolution is "
485 // << m_model->getResolution() << " frames" << std::endl;
486
487 float min = m_model->getValueMinimum();
488 float max = m_model->getValueMaximum();
489 if (max == min) max = min + 1.0;
490
491 QPoint localPos;
492 long illuminateFrame = -1;
493
494 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
495 RegionModel::PointList localPoints =
496 getLocalPoints(v, localPos.x());
497 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
498 }
499
500 paint.save();
501 paint.setRenderHint(QPainter::Antialiasing, false);
502
503 for (RegionModel::PointList::const_iterator i = points.begin();
504 i != points.end(); ++i) {
505
506 const RegionModel::Point &p(*i);
507
508 int x = v->getXForFrame(p.frame);
509 int y = getYForValue(v, p.value);
510 int w = v->getXForFrame(p.frame + p.duration) - x;
511 int h = 3;
512
513 if (m_model->getValueQuantization() != 0.0) {
514 h = y - getYForValue(v, p.value + m_model->getValueQuantization());
515 if (h < 3) h = 3;
516 }
517
518 if (w < 1) w = 1;
519 paint.setPen(getBaseQColor());
520 paint.setBrush(brushColour);
521
522 if (illuminateFrame == p.frame) {
523 if (localPos.y() >= y - h && localPos.y() < y) {
524 paint.setPen(v->getForeground());
525 paint.setBrush(v->getForeground());
526 }
527 }
528
529 paint.drawLine(x, y, x + w, y);
530 paint.drawLine(x, y - h/2, x, y + h/2);
531 paint.drawLine(x + w, y - h/2, x + w, y + h/2);
532
533 /// if (p.label != "") {
534 /// paint.drawText(x + 5, y - paint.fontMetrics().height() + paint.fontMetrics().ascent(), p.label);
535 /// }
536 }
537
538 paint.restore();
539 }
540
541 void
542 RegionLayer::drawStart(View *v, QMouseEvent *e)
543 {
544 // std::cerr << "RegionLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
545
546 if (!m_model) return;
547
548 long frame = v->getFrameForX(e->x());
549 if (frame < 0) frame = 0;
550 frame = frame / m_model->getResolution() * m_model->getResolution();
551
552 float value = getValueForY(v, e->y());
553
554 m_editingPoint = RegionModel::Point(frame, value, 0, tr("New Point"));
555 m_originalPoint = m_editingPoint;
556
557 if (m_editingCommand) finish(m_editingCommand);
558 m_editingCommand = new RegionModel::EditCommand(m_model,
559 tr("Draw Point"));
560 m_editingCommand->addPoint(m_editingPoint);
561
562 m_editing = true;
563 }
564
565 void
566 RegionLayer::drawDrag(View *v, QMouseEvent *e)
567 {
568 // std::cerr << "RegionLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
569
570 if (!m_model || !m_editing) return;
571
572 long frame = v->getFrameForX(e->x());
573 if (frame < 0) frame = 0;
574 frame = frame / m_model->getResolution() * m_model->getResolution();
575
576 float newValue = getValueForY(v, e->y());
577
578 long newFrame = m_editingPoint.frame;
579 long newDuration = frame - newFrame;
580 if (newDuration < 0) {
581 newFrame = frame;
582 newDuration = -newDuration;
583 } else if (newDuration == 0) {
584 newDuration = 1;
585 }
586
587 m_editingCommand->deletePoint(m_editingPoint);
588 m_editingPoint.frame = newFrame;
589 m_editingPoint.value = newValue;
590 m_editingPoint.duration = newDuration;
591 m_editingCommand->addPoint(m_editingPoint);
592 }
593
594 void
595 RegionLayer::drawEnd(View *, QMouseEvent *)
596 {
597 // std::cerr << "RegionLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
598 if (!m_model || !m_editing) return;
599 finish(m_editingCommand);
600 m_editingCommand = 0;
601 m_editing = false;
602 }
603
604 void
605 RegionLayer::eraseStart(View *v, QMouseEvent *e)
606 {
607 if (!m_model) return;
608
609 RegionModel::PointList points = getLocalPoints(v, e->x());
610 if (points.empty()) return;
611
612 m_editingPoint = *points.begin();
613
614 if (m_editingCommand) {
615 finish(m_editingCommand);
616 m_editingCommand = 0;
617 }
618
619 m_editing = true;
620 }
621
622 void
623 RegionLayer::eraseDrag(View *v, QMouseEvent *e)
624 {
625 }
626
627 void
628 RegionLayer::eraseEnd(View *v, QMouseEvent *e)
629 {
630 if (!m_model || !m_editing) return;
631
632 m_editing = false;
633
634 RegionModel::PointList points = getLocalPoints(v, e->x());
635 if (points.empty()) return;
636 if (points.begin()->frame != m_editingPoint.frame ||
637 points.begin()->value != m_editingPoint.value) return;
638
639 m_editingCommand = new RegionModel::EditCommand
640 (m_model, tr("Erase Point"));
641
642 m_editingCommand->deletePoint(m_editingPoint);
643
644 finish(m_editingCommand);
645 m_editingCommand = 0;
646 m_editing = false;
647 }
648
649 void
650 RegionLayer::editStart(View *v, QMouseEvent *e)
651 {
652 // std::cerr << "RegionLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
653
654 if (!m_model) return;
655
656 RegionModel::PointList points = getLocalPoints(v, e->x());
657 if (points.empty()) return;
658
659 m_editingPoint = *points.begin();
660 m_originalPoint = m_editingPoint;
661
662 if (m_editingCommand) {
663 finish(m_editingCommand);
664 m_editingCommand = 0;
665 }
666
667 m_editing = true;
668 }
669
670 void
671 RegionLayer::editDrag(View *v, QMouseEvent *e)
672 {
673 // std::cerr << "RegionLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
674
675 if (!m_model || !m_editing) return;
676
677 long frame = v->getFrameForX(e->x());
678 if (frame < 0) frame = 0;
679 frame = frame / m_model->getResolution() * m_model->getResolution();
680
681 float value = getValueForY(v, e->y());
682
683 if (!m_editingCommand) {
684 m_editingCommand = new RegionModel::EditCommand(m_model,
685 tr("Drag Point"));
686 }
687
688 m_editingCommand->deletePoint(m_editingPoint);
689 m_editingPoint.frame = frame;
690 m_editingPoint.value = value;
691 m_editingCommand->addPoint(m_editingPoint);
692 }
693
694 void
695 RegionLayer::editEnd(View *, QMouseEvent *)
696 {
697 // std::cerr << "RegionLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
698 if (!m_model || !m_editing) return;
699
700 if (m_editingCommand) {
701
702 QString newName = m_editingCommand->getName();
703
704 if (m_editingPoint.frame != m_originalPoint.frame) {
705 if (m_editingPoint.value != m_originalPoint.value) {
706 newName = tr("Edit Point");
707 } else {
708 newName = tr("Relocate Point");
709 }
710 } else {
711 newName = tr("Change Point Value");
712 }
713
714 m_editingCommand->setName(newName);
715 finish(m_editingCommand);
716 }
717
718 m_editingCommand = 0;
719 m_editing = false;
720 }
721
722 bool
723 RegionLayer::editOpen(View *v, QMouseEvent *e)
724 {
725 if (!m_model) return false;
726
727 RegionModel::PointList points = getLocalPoints(v, e->x());
728 if (points.empty()) return false;
729
730 RegionModel::Point region = *points.begin();
731
732 ItemEditDialog *dialog = new ItemEditDialog
733 (m_model->getSampleRate(),
734 ItemEditDialog::ShowTime |
735 ItemEditDialog::ShowDuration |
736 ItemEditDialog::ShowValue |
737 ItemEditDialog::ShowText,
738 m_model->getScaleUnits());
739
740 dialog->setFrameTime(region.frame);
741 dialog->setValue(region.value);
742 dialog->setFrameDuration(region.duration);
743 dialog->setText(region.label);
744
745 if (dialog->exec() == QDialog::Accepted) {
746
747 RegionModel::Point newRegion = region;
748 newRegion.frame = dialog->getFrameTime();
749 newRegion.value = dialog->getValue();
750 newRegion.duration = dialog->getFrameDuration();
751 newRegion.label = dialog->getText();
752
753 RegionModel::EditCommand *command = new RegionModel::EditCommand
754 (m_model, tr("Edit Point"));
755 command->deletePoint(region);
756 command->addPoint(newRegion);
757 finish(command);
758 }
759
760 delete dialog;
761 return true;
762 }
763
764 void
765 RegionLayer::moveSelection(Selection s, size_t newStartFrame)
766 {
767 if (!m_model) return;
768
769 RegionModel::EditCommand *command =
770 new RegionModel::EditCommand(m_model, tr("Drag Selection"));
771
772 RegionModel::PointList points =
773 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
774
775 for (RegionModel::PointList::iterator i = points.begin();
776 i != points.end(); ++i) {
777
778 if (s.contains(i->frame)) {
779 RegionModel::Point newPoint(*i);
780 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
781 command->deletePoint(*i);
782 command->addPoint(newPoint);
783 }
784 }
785
786 finish(command);
787 }
788
789 void
790 RegionLayer::resizeSelection(Selection s, Selection newSize)
791 {
792 if (!m_model) return;
793
794 RegionModel::EditCommand *command =
795 new RegionModel::EditCommand(m_model, tr("Resize Selection"));
796
797 RegionModel::PointList points =
798 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
799
800 double ratio =
801 double(newSize.getEndFrame() - newSize.getStartFrame()) /
802 double(s.getEndFrame() - s.getStartFrame());
803
804 for (RegionModel::PointList::iterator i = points.begin();
805 i != points.end(); ++i) {
806
807 if (s.contains(i->frame)) {
808
809 double targetStart = i->frame;
810 targetStart = newSize.getStartFrame() +
811 double(targetStart - s.getStartFrame()) * ratio;
812
813 double targetEnd = i->frame + i->duration;
814 targetEnd = newSize.getStartFrame() +
815 double(targetEnd - s.getStartFrame()) * ratio;
816
817 RegionModel::Point newPoint(*i);
818 newPoint.frame = lrint(targetStart);
819 newPoint.duration = lrint(targetEnd - targetStart);
820 command->deletePoint(*i);
821 command->addPoint(newPoint);
822 }
823 }
824
825 finish(command);
826 }
827
828 void
829 RegionLayer::deleteSelection(Selection s)
830 {
831 if (!m_model) return;
832
833 RegionModel::EditCommand *command =
834 new RegionModel::EditCommand(m_model, tr("Delete Selected Points"));
835
836 RegionModel::PointList points =
837 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
838
839 for (RegionModel::PointList::iterator i = points.begin();
840 i != points.end(); ++i) {
841
842 if (s.contains(i->frame)) {
843 command->deletePoint(*i);
844 }
845 }
846
847 finish(command);
848 }
849
850 void
851 RegionLayer::copy(View *v, Selection s, Clipboard &to)
852 {
853 if (!m_model) return;
854
855 RegionModel::PointList points =
856 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
857
858 for (RegionModel::PointList::iterator i = points.begin();
859 i != points.end(); ++i) {
860 if (s.contains(i->frame)) {
861 Clipboard::Point point(i->frame, i->value, i->duration, i->label);
862 point.setReferenceFrame(alignToReference(v, i->frame));
863 to.addPoint(point);
864 }
865 }
866 }
867
868 bool
869 RegionLayer::paste(View *v, const Clipboard &from, int frameOffset, bool /* interactive */)
870 {
871 if (!m_model) return false;
872
873 const Clipboard::PointList &points = from.getPoints();
874
875 bool realign = false;
876
877 if (clipboardHasDifferentAlignment(v, from)) {
878
879 QMessageBox::StandardButton button =
880 QMessageBox::question(v, tr("Re-align pasted items?"),
881 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?"),
882 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
883 QMessageBox::Yes);
884
885 if (button == QMessageBox::Cancel) {
886 return false;
887 }
888
889 if (button == QMessageBox::Yes) {
890 realign = true;
891 }
892 }
893
894 RegionModel::EditCommand *command =
895 new RegionModel::EditCommand(m_model, tr("Paste"));
896
897 for (Clipboard::PointList::const_iterator i = points.begin();
898 i != points.end(); ++i) {
899
900 if (!i->haveFrame()) continue;
901 size_t frame = 0;
902
903 if (!realign) {
904
905 frame = i->getFrame();
906
907 } else {
908
909 if (i->haveReferenceFrame()) {
910 frame = i->getReferenceFrame();
911 frame = alignFromReference(v, frame);
912 } else {
913 frame = i->getFrame();
914 }
915 }
916
917 RegionModel::Point newPoint(frame);
918
919 if (i->haveLabel()) newPoint.label = i->getLabel();
920 if (i->haveValue()) newPoint.value = i->getValue();
921 else newPoint.value = (m_model->getValueMinimum() +
922 m_model->getValueMaximum()) / 2;
923 if (i->haveDuration()) newPoint.duration = i->getDuration();
924 else {
925 size_t nextFrame = frame;
926 Clipboard::PointList::const_iterator j = i;
927 for (; j != points.end(); ++j) {
928 if (!j->haveFrame()) continue;
929 if (j != i) break;
930 }
931 if (j != points.end()) {
932 nextFrame = j->getFrame();
933 }
934 if (nextFrame == frame) {
935 newPoint.duration = m_model->getResolution();
936 } else {
937 newPoint.duration = nextFrame - frame;
938 }
939 }
940
941 command->addPoint(newPoint);
942 }
943
944 finish(command);
945 return true;
946 }
947
948 int
949 RegionLayer::getDefaultColourHint(bool darkbg, bool &impose)
950 {
951 impose = false;
952 return ColourDatabase::getInstance()->getColourIndex
953 (QString(darkbg ? "White" : "Black"));
954 }
955
956 void
957 RegionLayer::toXml(QTextStream &stream,
958 QString indent, QString extraAttributes) const
959 {
960 SingleColourLayer::toXml(stream, indent, extraAttributes +
961 QString(" verticalScale=\"%1\"")
962 .arg(m_verticalScale));
963 }
964
965 void
966 RegionLayer::setProperties(const QXmlAttributes &attributes)
967 {
968 SingleColourLayer::setProperties(attributes);
969
970 bool ok;
971 VerticalScale scale = (VerticalScale)
972 attributes.value("verticalScale").toInt(&ok);
973 if (ok) setVerticalScale(scale);
974 }
975
976