Mercurial > hg > easaier-soundaccess
comparison layer/IntervalLayer.cpp @ 18:d8e6709e9075
add
- EasaierSessionManager
- Easaier menus
- Interval model
author | lbajardsilogic |
---|---|
date | Mon, 14 May 2007 13:13:14 +0000 |
parents | |
children | 66af7c1b10d9 |
comparison
equal
deleted
inserted
replaced
17:e59b19407b6d | 18:d8e6709e9075 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sound Access | |
5 EASAIER client application. | |
6 Silogic 2007. Luc Barthélémy. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 */ | |
14 | |
15 #include <QObject> | |
16 #include <QColor> | |
17 #include <QPainter> | |
18 #include <QMouseEvent> | |
19 #include <QInputDialog> | |
20 | |
21 #include "layer/IntervalLayer.h" | |
22 #include "view/View.h" | |
23 #include "system/System.h" | |
24 #include "widgets/ItemEditDialog.h" | |
25 | |
26 | |
27 const int gIntervalHeight = 30; | |
28 | |
29 //**************************************************************** | |
30 //* Function: Constructor | |
31 //* Description: declaration and initialisation of all private parameters | |
32 //**************************************************************** | |
33 IntervalLayer::IntervalLayer(): | |
34 Layer(), | |
35 m_model(0), | |
36 m_editing(false), | |
37 m_colour(Qt::darkRed), | |
38 m_editingCommand(0) | |
39 { | |
40 } | |
41 | |
42 IntervalLayer::~IntervalLayer() | |
43 {} | |
44 | |
45 void IntervalLayer::setModel(IntervalModel* model) | |
46 { | |
47 if (m_model == model) return; | |
48 m_model = model; | |
49 | |
50 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
51 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
52 this, SIGNAL(modelChanged(size_t, size_t))); | |
53 | |
54 connect(m_model, SIGNAL(completionChanged()), | |
55 this, SIGNAL(modelCompletionChanged())); | |
56 | |
57 emit modelReplaced(); | |
58 } | |
59 | |
60 Layer::PropertyList | |
61 IntervalLayer::getProperties() const | |
62 { | |
63 PropertyList list; | |
64 list.push_back("Colour"); | |
65 return list; | |
66 } | |
67 | |
68 Layer::PropertyType | |
69 IntervalLayer::getPropertyType(const PropertyName &name) const | |
70 { | |
71 return ValueProperty; | |
72 } | |
73 | |
74 int | |
75 IntervalLayer::getPropertyRangeAndValue(const PropertyName &name, | |
76 int *min, int *max, int *deflt) const | |
77 { | |
78 //!!! factor this colour handling stuff out into a colour manager class | |
79 int val = 0; | |
80 | |
81 if (name == "Colour") { | |
82 | |
83 if (min) *min = 0; | |
84 if (max) *max = 5; | |
85 if (deflt) *deflt = 0; | |
86 | |
87 if (m_colour == Qt::black) val = 0; | |
88 else if (m_colour == Qt::darkRed) val = 1; | |
89 else if (m_colour == Qt::darkBlue) val = 2; | |
90 else if (m_colour == Qt::darkGreen) val = 3; | |
91 else if (m_colour == QColor(200, 50, 255)) val = 4; | |
92 else if (m_colour == QColor(255, 150, 50)) val = 5; | |
93 } | |
94 | |
95 return val; | |
96 } | |
97 | |
98 QString | |
99 IntervalLayer::getPropertyValueLabel(const PropertyName &name, | |
100 int value) const | |
101 { | |
102 if (name == "Colour") { | |
103 switch (value) { | |
104 default: | |
105 case 0: return tr("Black"); | |
106 case 1: return tr("Red"); | |
107 case 2: return tr("Blue"); | |
108 case 3: return tr("Green"); | |
109 case 4: return tr("Purple"); | |
110 case 5: return tr("Orange"); | |
111 } | |
112 } | |
113 return tr("<unknown>"); | |
114 } | |
115 | |
116 | |
117 void IntervalLayer::setProperties(const QXmlAttributes &attributes) | |
118 { | |
119 QString colourSpec = attributes.value("colour"); | |
120 if (colourSpec != "") { | |
121 QColor colour(colourSpec); | |
122 if (colour.isValid()) { | |
123 setBaseColour(QColor(colourSpec)); | |
124 } | |
125 } | |
126 | |
127 } | |
128 | |
129 void | |
130 IntervalLayer::setProperty(const PropertyName &name, int value) | |
131 { | |
132 if (name == "Colour") { | |
133 switch (value) { | |
134 default: | |
135 case 0: setBaseColour(Qt::black); break; | |
136 case 1: setBaseColour(Qt::darkRed); break; | |
137 case 2: setBaseColour(Qt::darkBlue); break; | |
138 case 3: setBaseColour(Qt::darkGreen); break; | |
139 case 4: setBaseColour(QColor(200, 50, 255)); break; | |
140 case 5: setBaseColour(QColor(255, 150, 50)); break; | |
141 } | |
142 } | |
143 } | |
144 | |
145 void | |
146 IntervalLayer::setBaseColour(QColor colour) | |
147 { | |
148 if (m_colour == colour) return; | |
149 m_colour = colour; | |
150 emit layerParametersChanged(); | |
151 } | |
152 | |
153 QString | |
154 IntervalLayer::toXmlString(QString indent, QString extraAttributes) const | |
155 { | |
156 return Layer::toXmlString(indent, extraAttributes + | |
157 QString(" colour=\"%1\"") | |
158 .arg(encodeColour(m_colour))); | |
159 } | |
160 | |
161 QString | |
162 IntervalLayer::toEasaierXmlString(QString indent, QString extraAttributes) const | |
163 { | |
164 return Layer::toEasaierXmlString(indent, extraAttributes + | |
165 QString(" colour=\"%1\"") | |
166 .arg(encodeColour(m_colour))); | |
167 } | |
168 | |
169 QString | |
170 IntervalLayer::getPropertyLabel(const PropertyName &name) const | |
171 { | |
172 if (name == "Colour") return tr("Colour"); | |
173 return ""; | |
174 } | |
175 | |
176 int | |
177 IntervalLayer::getYForHeight(View *v, float height) const | |
178 { | |
179 int h = v->height(); | |
180 return h - int(height * h); | |
181 } | |
182 | |
183 float | |
184 IntervalLayer::getHeightForY(View *v, int y) const | |
185 { | |
186 int h = v->height(); | |
187 return float(h - y) / h; | |
188 } | |
189 | |
190 | |
191 void | |
192 IntervalLayer::paint(View *v, QPainter &paint, QRect rect) const | |
193 { | |
194 if (!m_model || !m_model->isOK()) return; | |
195 | |
196 int sampleRate = m_model->getSampleRate(); | |
197 if (!sampleRate) return; | |
198 | |
199 int x0 = rect.left(), x1 = rect.right(); | |
200 long frame0 = v->getFrameForX(x0); | |
201 long frame1 = v->getFrameForX(x1); | |
202 | |
203 paint.save(); | |
204 | |
205 QColor brushColour(m_colour); | |
206 brushColour.setAlpha(100); | |
207 QColor penColour = Qt::black; | |
208 | |
209 paint.setPen(m_colour); | |
210 | |
211 IntervalList& intervals = m_model->intervals(); | |
212 | |
213 int xS,xE,y; | |
214 bool draw, drawText, drawStart, drawEnd; | |
215 | |
216 QPoint localPos; | |
217 long illuminateX = -1; | |
218 | |
219 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | |
220 // should highlight one endpoint ? | |
221 illuminateX = localPos.x(); | |
222 } | |
223 | |
224 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
225 { | |
226 draw = drawText = drawStart = drawEnd = false; | |
227 | |
228 TimeIntervalPtr ti = (*i); | |
229 | |
230 if (ti->start() >= frame0 && ti->start() < frame1) | |
231 { | |
232 xS = v->getXForFrame(ti->start()); | |
233 xE = v->getXForFrame(ti->end()); | |
234 if (xE <= x1) | |
235 drawEnd = true; | |
236 else | |
237 xE = x1; | |
238 draw = drawText = drawStart = true; | |
239 } | |
240 else if (ti->end() > frame0 && ti->end <= frame1) | |
241 { | |
242 xS = v->getXForFrame(ti->start()); | |
243 if (xS < x0) | |
244 xS = x0; | |
245 xE = v->getXForFrame(ti->end()); | |
246 draw = drawEnd = true; | |
247 } | |
248 else if (ti->start <= frame0 && ti->end >= frame1) | |
249 { | |
250 xS = x0; | |
251 xE = x1; | |
252 draw = true; | |
253 } | |
254 if (draw) | |
255 { | |
256 y = getYForHeight(v, ti->value()); | |
257 paint.setBrush(brushColour); | |
258 paint.fillRect(xS, y-gIntervalHeight/2, (xE-xS+1), gIntervalHeight, brushColour); | |
259 } | |
260 if (drawStart) | |
261 { | |
262 if (abs(illuminateX - xS) < 3) | |
263 paint.setPen(Qt::black); | |
264 else | |
265 paint.setPen(brushColour); | |
266 paint.drawLine(xS, 0, xS, v->height() - 1); | |
267 } | |
268 if (drawEnd) | |
269 { | |
270 if (abs (illuminateX - xE) < 3) | |
271 paint.setPen(Qt::black); | |
272 else | |
273 paint.setPen(brushColour); | |
274 paint.drawLine(xE, 0, xE, v->height() - 1); | |
275 } | |
276 if (drawText) | |
277 { | |
278 paint.setPen(penColour); | |
279 paint.drawText(xS+10, y, ti->label()); | |
280 } | |
281 } | |
282 | |
283 paint.restore(); | |
284 } | |
285 | |
286 | |
287 bool | |
288 IntervalLayer::getValueExtents(float &min, float &max, | |
289 bool &logarithmic, QString &unit) const | |
290 { | |
291 return false; | |
292 } | |
293 | |
294 IntervalList | |
295 IntervalLayer::getIntervalAt(View *v, int x, int y) // y < 0 means you don't make any test on it | |
296 { | |
297 IntervalList result; | |
298 IntervalList& intervals = m_model->intervals(); | |
299 | |
300 for (IntervalListIterator i = intervals.begin(); i != intervals.end(); ++i) | |
301 { | |
302 TimeIntervalPtr ti = (*i); | |
303 | |
304 int yT = getYForHeight(v, ti->value()); | |
305 int xS = v->getXForFrame(ti->start()); | |
306 int xE = v->getXForFrame(ti->end()); | |
307 if ((x >= xS) && (x <= xE)) | |
308 { | |
309 if ((y < 0) || (abs(y - yT) <= gIntervalHeight/2)) | |
310 result.push_back(ti); | |
311 } | |
312 } | |
313 | |
314 return result; | |
315 } | |
316 | |
317 IntervalList | |
318 IntervalLayer::getInterval(long start, long end) | |
319 { | |
320 IntervalList result; | |
321 IntervalList& intervals = m_model->intervals(); | |
322 | |
323 for (IntervalListIterator i = intervals.begin(); i != intervals.end(); ++i) | |
324 { | |
325 TimeIntervalPtr ti = (*i); | |
326 | |
327 if ( (start <= ti->start()) && (ti->start() <= end) && | |
328 (start <= ti->end()) && (ti->end() <= end) ) | |
329 { | |
330 result.push_back(ti); | |
331 } | |
332 } | |
333 | |
334 return result; | |
335 } | |
336 | |
337 QString | |
338 IntervalLayer::getFeatureDescription(View *v, QPoint& pos) const | |
339 { | |
340 if (!m_model || !m_model->getSampleRate()) return ""; | |
341 | |
342 QString description; | |
343 | |
344 int x = pos.x(); | |
345 int y = pos.y(); | |
346 | |
347 long frame = v->getFrameForX(x); | |
348 | |
349 IntervalList& intervals = m_model->intervals(); | |
350 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
351 { | |
352 TimeIntervalPtr ti = (*i); | |
353 | |
354 if (ti->start() <= frame && ti->end() >= frame) | |
355 { | |
356 int y = getYForHeight(v, ti->value()); | |
357 | |
358 if (abs(y - pos.y()) <= gIntervalHeight/2) | |
359 { | |
360 RealTime rtStart = RealTime::frame2RealTime(ti->start(), m_model->getSampleRate()); | |
361 RealTime rtEnd = RealTime::frame2RealTime(ti->end(), m_model->getSampleRate()); | |
362 RealTime rtDuration = rtEnd - rtStart; | |
363 | |
364 description = QString(tr("Interval:\t%1\nStart:\t%2 End:\t%3\tDuration:\t%4")) | |
365 .arg(ti->label()) | |
366 .arg(rtStart.toText(true).c_str()) | |
367 .arg(rtEnd.toText(true).c_str()) | |
368 .arg(rtDuration.toText(true).c_str()); | |
369 break; | |
370 } | |
371 } | |
372 } | |
373 | |
374 return description; | |
375 } | |
376 | |
377 | |
378 void | |
379 IntervalLayer::drawStart(View *v, QMouseEvent *e) | |
380 { | |
381 if (!m_model) { | |
382 std::cerr << "IntervalLayer::drawStart: no model" << std::endl; | |
383 return; | |
384 } | |
385 | |
386 long frame = v->getFrameForX(e->x()); | |
387 | |
388 if (frame < 0) | |
389 frame = 0; | |
390 | |
391 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
392 | |
393 int height = (int) (getHeightForY(v, e->y())*100+0.5); | |
394 float value = ((float) height)/100; | |
395 | |
396 m_editingInterval = new TimeInterval(frame, frame, "", value); | |
397 | |
398 m_model->addInterval(m_editingInterval); | |
399 | |
400 if (m_editingCommand) | |
401 { | |
402 CommandHistory::getInstance()->addCommand(m_editingCommand, false); | |
403 m_editingCommand = 0; | |
404 } | |
405 | |
406 m_editingCommand = new IntervalModel::IntervalCommand(m_model, m_editingInterval, | |
407 IntervalModel::IntervalCommand::Creation , | |
408 frame, frame, value, ""); | |
409 | |
410 m_editing = 1; | |
411 } | |
412 | |
413 void | |
414 IntervalLayer::drawDrag(View *v, QMouseEvent *e) | |
415 { | |
416 if (!m_model || !m_editing) return; | |
417 | |
418 long frame = v->getFrameForX(e->x()); | |
419 | |
420 if (frame < 0) | |
421 frame = 0; | |
422 | |
423 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
424 | |
425 long start = m_editingInterval->start(); | |
426 long end = frame; | |
427 | |
428 if (start < end) | |
429 { | |
430 m_editing = 2; | |
431 m_editingInterval->end(frame); | |
432 m_editingCommand->newEnd(frame); | |
433 } else { | |
434 m_editing = 1; | |
435 m_editingInterval->start(frame); | |
436 m_editingCommand->newStart(frame); | |
437 } | |
438 } | |
439 | |
440 void | |
441 IntervalLayer::drawEnd(View *v, QMouseEvent *e) | |
442 { | |
443 if (!m_model || !m_editing) | |
444 return; | |
445 | |
446 bool ok = false; | |
447 QString label = QInputDialog::getText(v, tr("Enter label"), | |
448 tr("Please enter a new label:"), | |
449 QLineEdit::Normal, "", &ok); | |
450 | |
451 if (ok) { | |
452 m_editingInterval->label(label); | |
453 m_editingCommand->newLabel(label); | |
454 } | |
455 | |
456 if (m_editingCommand) | |
457 { | |
458 CommandHistory::getInstance()->addCommand(m_editingCommand, false); | |
459 m_editingCommand = 0; | |
460 } | |
461 | |
462 m_editing = false; | |
463 } | |
464 | |
465 void | |
466 IntervalLayer::editStart(View *view, QMouseEvent *evt) | |
467 { | |
468 if (!m_model) | |
469 return; | |
470 | |
471 IntervalList intervals = getIntervalAt(view, evt->x(), evt->y()); | |
472 | |
473 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
474 { | |
475 TimeIntervalPtr ti = (*i); | |
476 | |
477 int xS = view->getXForFrame(ti->start()); | |
478 int xE = view->getXForFrame(ti->end()); | |
479 | |
480 if (abs(xS - evt->x()) < 5) | |
481 { | |
482 m_editing = 1; // editing start | |
483 m_editingInterval = ti; | |
484 break; | |
485 } | |
486 else if (abs(xE - evt->x()) < 5) | |
487 { | |
488 m_editing = 2; // editing end | |
489 m_editingInterval = ti; | |
490 break; | |
491 } | |
492 else | |
493 { | |
494 m_editing = 0; | |
495 } | |
496 } | |
497 | |
498 if (m_editing) | |
499 view->setCursor(Qt::SizeHorCursor); | |
500 | |
501 if (m_editingCommand) | |
502 { | |
503 CommandHistory::getInstance()->addCommand(m_editingCommand, false); | |
504 m_editingCommand = 0; | |
505 } | |
506 | |
507 } | |
508 | |
509 void | |
510 IntervalLayer::editDrag(View *view, QMouseEvent *evt) | |
511 { | |
512 if (!m_model || !m_editing) | |
513 return; | |
514 | |
515 long frame = view->getFrameForX(evt->x()); | |
516 | |
517 if (!m_editingCommand) | |
518 { | |
519 m_editingCommand = new IntervalModel::IntervalCommand(m_model, m_editingInterval, IntervalModel::IntervalCommand::Edition, | |
520 m_editingInterval->start(), | |
521 m_editingInterval->end(), | |
522 m_editingInterval->value(), | |
523 m_editingInterval->label()); | |
524 } | |
525 | |
526 if (m_editing == 1) // start | |
527 { | |
528 if (frame < m_editingInterval->end()) | |
529 m_editingCommand->newStart(frame); | |
530 } | |
531 else if (m_editing == 2) // end | |
532 { | |
533 if (frame > m_editingInterval->start()) | |
534 m_editingCommand->newEnd(frame); | |
535 } | |
536 } | |
537 | |
538 void | |
539 IntervalLayer::editEnd(View *view, QMouseEvent *evt) | |
540 { | |
541 if (!m_model || !m_editing) | |
542 return; | |
543 | |
544 view->setCursor(Qt::UpArrowCursor); | |
545 | |
546 if (m_editingCommand) | |
547 { | |
548 CommandHistory::getInstance()->addCommand(m_editingCommand, false); | |
549 m_editingCommand = 0; | |
550 } | |
551 | |
552 | |
553 m_editing = false; | |
554 } | |
555 | |
556 void | |
557 IntervalLayer::editOpen(View *view, QMouseEvent *evt) // on double-click | |
558 { | |
559 if (!m_model) return; | |
560 | |
561 IntervalList intervals = getIntervalAt(view, evt->x(), evt->y()); | |
562 if (! intervals.empty()) | |
563 { | |
564 TimeIntervalPtr ti = intervals.front(); | |
565 | |
566 bool ok = false; | |
567 ItemEditDialog *dialog = new ItemEditDialog | |
568 (m_model->getSampleRate(), | |
569 ItemEditDialog::ShowTime | | |
570 ItemEditDialog::ShowDuration | | |
571 ItemEditDialog::ShowText | | |
572 ItemEditDialog::ShowValue); | |
573 | |
574 dialog->setFrameTime(ti->start()); | |
575 dialog->setFrameDuration(ti->end() - ti->start()); | |
576 dialog->setText(ti->label()); | |
577 dialog->setValue((int)(ti->value()*100+0.5)); | |
578 | |
579 if (dialog->exec() == QDialog::Accepted) | |
580 { | |
581 | |
582 IntervalModel::IntervalCommand *command = | |
583 new IntervalModel::IntervalCommand(m_model, ti, IntervalModel::IntervalCommand::Edition, | |
584 dialog->getFrameTime(), | |
585 dialog->getFrameTime() + dialog->getFrameDuration(), | |
586 dialog->getValue()/100, | |
587 dialog->getText()); | |
588 | |
589 CommandHistory::getInstance()->addCommand(command); | |
590 | |
591 } | |
592 } | |
593 } | |
594 | |
595 void | |
596 IntervalLayer::moveSelection(Selection s, size_t newStartFrame) | |
597 { | |
598 if (!m_model) return; | |
599 | |
600 IntervalList intervals = getInterval(s.getStartFrame(), s.getEndFrame()); | |
601 | |
602 MacroCommand * command = new MacroCommand("Drag Selection"); | |
603 | |
604 long newStart = 0; | |
605 long newEnd = 0; | |
606 | |
607 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
608 { | |
609 TimeIntervalPtr ti = (*i); | |
610 | |
611 newStart = ti->start() + ((long) (newStartFrame - s.getStartFrame())); | |
612 newEnd = ti->end() + ((long) (newStartFrame - s.getStartFrame())); | |
613 | |
614 IntervalModel::IntervalCommand *intervalCommand = | |
615 new IntervalModel::IntervalCommand(m_model, ti, IntervalModel::IntervalCommand::Edition, | |
616 newStart, | |
617 newEnd, | |
618 ti->value(), | |
619 ti->label()); | |
620 | |
621 m_model->changeInterval(ti, newStart, newEnd, ti->value(), ti->label() ); | |
622 | |
623 command->addCommand(intervalCommand); | |
624 } | |
625 | |
626 CommandHistory::getInstance()->addCommand(command, false); | |
627 } | |
628 | |
629 void | |
630 IntervalLayer::resizeSelection(Selection s, Selection newSize) | |
631 { | |
632 if (!m_model) return; | |
633 | |
634 IntervalList intervals = getInterval(s.getStartFrame(), s.getEndFrame()); | |
635 | |
636 MacroCommand * command = new MacroCommand("Resize Selection"); | |
637 | |
638 long newStart = 0; | |
639 long newEnd = 0; | |
640 | |
641 double ratio = ((double) (newSize.getEndFrame() - newSize.getStartFrame())) / | |
642 ((double) (s.getEndFrame() - s.getStartFrame())); | |
643 | |
644 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
645 { | |
646 TimeIntervalPtr ti = (*i); | |
647 | |
648 newStart = (long) newSize.getStartFrame() + (long) ( ((double) ti->start() - (double) s.getStartFrame()) * ratio ); | |
649 newEnd = (long) newSize.getStartFrame() + (long) ( ((double) ti->end() - (double) s.getStartFrame()) * ratio ); | |
650 | |
651 IntervalModel::IntervalCommand *intervalCommand = | |
652 new IntervalModel::IntervalCommand(m_model, ti, IntervalModel::IntervalCommand::Edition, | |
653 newStart, | |
654 newEnd, | |
655 ti->value(), | |
656 ti->label()); | |
657 | |
658 m_model->changeInterval(ti, newStart, newEnd, ti->value(), ti->label() ); | |
659 | |
660 command->addCommand(intervalCommand); | |
661 } | |
662 | |
663 CommandHistory::getInstance()->addCommand(command, false); | |
664 } | |
665 | |
666 void | |
667 IntervalLayer::deleteSelection(Selection s) | |
668 { | |
669 if (!m_model) return; | |
670 | |
671 IntervalList intervals = getInterval(s.getStartFrame(), s.getEndFrame()); | |
672 | |
673 MacroCommand * command = new MacroCommand("Delete Selected Intervals"); | |
674 | |
675 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
676 { | |
677 TimeIntervalPtr ti = (*i); | |
678 | |
679 m_model->removeInterval(ti); | |
680 | |
681 IntervalModel::IntervalCommand *intervalCommand = | |
682 new IntervalModel::IntervalCommand(m_model, ti, IntervalModel::IntervalCommand::Deletion, | |
683 ti->start(), | |
684 ti->end(), | |
685 ti->value(), | |
686 ti->label()); | |
687 | |
688 command->addCommand(intervalCommand); | |
689 } | |
690 | |
691 CommandHistory::getInstance()->addCommand(command, false); | |
692 } | |
693 | |
694 void | |
695 IntervalLayer::paste(const Clipboard &from, int frameOffset) | |
696 { | |
697 if (!m_model) return; | |
698 | |
699 const Clipboard::PointList &points = from.getPoints(); | |
700 | |
701 MacroCommand * command = new MacroCommand("Paste"); | |
702 | |
703 for (Clipboard::PointList::const_iterator i = points.begin(); i != points.end(); ++i) | |
704 { | |
705 if (!i->haveFrame()) | |
706 continue; | |
707 | |
708 size_t frame = 0; | |
709 | |
710 if (frameOffset > 0 || -frameOffset < i->getFrame()) { | |
711 frame = i->getFrame() + frameOffset; | |
712 } | |
713 | |
714 TimeIntervalPtr ti = new TimeInterval((long) frame, (long) (frame+i->getDuration()), i->getLabel(), i->getValue()); | |
715 | |
716 m_model->addInterval(ti); | |
717 | |
718 IntervalModel::IntervalCommand *intervalCommand = | |
719 new IntervalModel::IntervalCommand(m_model, ti, IntervalModel::IntervalCommand::Creation, | |
720 ti->start(), | |
721 ti->end(), | |
722 ti->value(), | |
723 ti->label()); | |
724 | |
725 command->addCommand(intervalCommand); | |
726 | |
727 } | |
728 | |
729 CommandHistory::getInstance()->addCommand(command, false); | |
730 } | |
731 | |
732 void | |
733 IntervalLayer::copy(Selection s, Clipboard &to) | |
734 { | |
735 if (!m_model) return; | |
736 | |
737 IntervalList intervals = getInterval(s.getStartFrame(), s.getEndFrame()); | |
738 | |
739 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
740 { | |
741 TimeIntervalPtr ti = (*i); | |
742 | |
743 Clipboard::Point point(ti->start(), ti->value(), ti->end()-ti->start(), ti->label()); | |
744 to.addPoint(point); | |
745 } | |
746 } | |
747 | |
748 bool | |
749 IntervalLayer::snapToFeatureFrame(View *v, int &frame, | |
750 size_t &resolution, | |
751 SnapType snap) const | |
752 { | |
753 if (!m_model) | |
754 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | |
755 | |
756 resolution = m_model->getResolution(); | |
757 | |
758 IntervalList& intervals = m_model->intervals(); | |
759 | |
760 int snapped, best = frame; | |
761 bool found = false; | |
762 | |
763 unsigned int dist, distMin; | |
764 | |
765 dist = distMin = m_model->getEndFrame(); | |
766 | |
767 for (IntervalListConstIterator i = intervals.begin(); i != intervals.end(); ++i) | |
768 { | |
769 TimeIntervalPtr ti = (*i); | |
770 switch (snap) | |
771 { | |
772 case SnapRight: | |
773 if (ti->start() >= frame) | |
774 { | |
775 dist = ti->start() - frame; | |
776 snapped = ti->start(); | |
777 } | |
778 else if (ti->end() >= frame) | |
779 { | |
780 dist = ti->end() - frame; | |
781 snapped = ti->end(); | |
782 } | |
783 break; | |
784 | |
785 case SnapLeft: | |
786 if (ti->end() <= frame) | |
787 { | |
788 dist = frame - ti->end(); | |
789 snapped = ti->end(); | |
790 } | |
791 else if (ti->start() <= frame) | |
792 { | |
793 dist = frame - ti->start(); | |
794 snapped = ti->start(); | |
795 } | |
796 break; | |
797 | |
798 case SnapNearest: | |
799 { | |
800 int distS = abs(ti->start() - frame); | |
801 int distE = abs(ti->end() - frame); | |
802 if (distS < distE) | |
803 { | |
804 dist = distS; | |
805 snapped = ti->start(); | |
806 } else | |
807 { | |
808 dist = distE; | |
809 snapped = ti->end(); | |
810 } | |
811 } | |
812 break; | |
813 | |
814 case SnapNeighbouring: | |
815 { | |
816 int distS = abs(ti->start() - frame); | |
817 int distE = abs(ti->end() - frame); | |
818 if (distS < 5) | |
819 { | |
820 dist = distS; | |
821 snapped = ti->start(); | |
822 } else if (distE < 5) | |
823 { | |
824 dist = distE; | |
825 snapped = ti->end(); | |
826 } | |
827 } | |
828 break; | |
829 } | |
830 | |
831 if (dist < distMin) | |
832 { | |
833 found = true; | |
834 distMin = dist; | |
835 best = snapped; | |
836 } | |
837 | |
838 } | |
839 | |
840 | |
841 if (found) | |
842 { | |
843 frame = best; | |
844 } | |
845 | |
846 return found; | |
847 } |