Mercurial > hg > easaier-soundaccess
comparison layer/TimeInstantLayer.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children | d8e6709e9075 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
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 Chris Cannam. | |
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 "TimeInstantLayer.h" | |
17 | |
18 #include "data/model/Model.h" | |
19 #include "base/RealTime.h" | |
20 #include "view/View.h" | |
21 #include "base/Profiler.h" | |
22 #include "base/Clipboard.h" | |
23 | |
24 #include "data/model/SparseOneDimensionalModel.h" | |
25 | |
26 #include "widgets/ItemEditDialog.h" | |
27 | |
28 #include <QPainter> | |
29 #include <QMouseEvent> | |
30 | |
31 #include <iostream> | |
32 #include <cmath> | |
33 | |
34 TimeInstantLayer::TimeInstantLayer() : | |
35 Layer(), | |
36 m_model(0), | |
37 m_editing(false), | |
38 m_editingPoint(0, tr("New Point")), | |
39 m_editingCommand(0), | |
40 m_colour(QColor(200, 50, 255)), | |
41 m_plotStyle(PlotInstants) | |
42 { | |
43 | |
44 } | |
45 | |
46 void | |
47 TimeInstantLayer::setModel(SparseOneDimensionalModel *model) | |
48 { | |
49 if (m_model == model) return; | |
50 m_model = model; | |
51 | |
52 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
53 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
54 this, SIGNAL(modelChanged(size_t, size_t))); | |
55 | |
56 connect(m_model, SIGNAL(completionChanged()), | |
57 this, SIGNAL(modelCompletionChanged())); | |
58 | |
59 std::cerr << "TimeInstantLayer::setModel(" << model << ")" << std::endl; | |
60 | |
61 emit modelReplaced(); | |
62 } | |
63 | |
64 Layer::PropertyList | |
65 TimeInstantLayer::getProperties() const | |
66 { | |
67 PropertyList list; | |
68 list.push_back("Colour"); | |
69 list.push_back("Plot Type"); | |
70 return list; | |
71 } | |
72 | |
73 QString | |
74 TimeInstantLayer::getPropertyLabel(const PropertyName &name) const | |
75 { | |
76 if (name == "Colour") return tr("Colour"); | |
77 if (name == "Plot Type") return tr("Plot Type"); | |
78 return ""; | |
79 } | |
80 | |
81 Layer::PropertyType | |
82 TimeInstantLayer::getPropertyType(const PropertyName &) const | |
83 { | |
84 return ValueProperty; | |
85 } | |
86 | |
87 int | |
88 TimeInstantLayer::getPropertyRangeAndValue(const PropertyName &name, | |
89 int *min, int *max, int *deflt) const | |
90 { | |
91 int val = 0; | |
92 | |
93 if (name == "Colour") { | |
94 | |
95 if (min) *min = 0; | |
96 if (max) *max = 5; | |
97 if (deflt) *deflt = 0; | |
98 | |
99 if (m_colour == Qt::black) val = 0; | |
100 else if (m_colour == Qt::darkRed) val = 1; | |
101 else if (m_colour == Qt::darkBlue) val = 2; | |
102 else if (m_colour == Qt::darkGreen) val = 3; | |
103 else if (m_colour == QColor(200, 50, 255)) val = 4; | |
104 else if (m_colour == QColor(255, 150, 50)) val = 5; | |
105 | |
106 } else if (name == "Plot Type") { | |
107 | |
108 if (min) *min = 0; | |
109 if (max) *max = 1; | |
110 if (deflt) *deflt = 0; | |
111 | |
112 val = int(m_plotStyle); | |
113 | |
114 } else { | |
115 | |
116 val = Layer::getPropertyRangeAndValue(name, min, max, deflt); | |
117 } | |
118 | |
119 return val; | |
120 } | |
121 | |
122 QString | |
123 TimeInstantLayer::getPropertyValueLabel(const PropertyName &name, | |
124 int value) const | |
125 { | |
126 if (name == "Colour") { | |
127 switch (value) { | |
128 default: | |
129 case 0: return tr("Black"); | |
130 case 1: return tr("Red"); | |
131 case 2: return tr("Blue"); | |
132 case 3: return tr("Green"); | |
133 case 4: return tr("Purple"); | |
134 case 5: return tr("Orange"); | |
135 } | |
136 } else if (name == "Plot Type") { | |
137 switch (value) { | |
138 default: | |
139 case 0: return tr("Instants"); | |
140 case 1: return tr("Segmentation"); | |
141 } | |
142 } | |
143 return tr("<unknown>"); | |
144 } | |
145 | |
146 void | |
147 TimeInstantLayer::setProperty(const PropertyName &name, int value) | |
148 { | |
149 if (name == "Colour") { | |
150 switch (value) { | |
151 default: | |
152 case 0: setBaseColour(Qt::black); break; | |
153 case 1: setBaseColour(Qt::darkRed); break; | |
154 case 2: setBaseColour(Qt::darkBlue); break; | |
155 case 3: setBaseColour(Qt::darkGreen); break; | |
156 case 4: setBaseColour(QColor(200, 50, 255)); break; | |
157 case 5: setBaseColour(QColor(255, 150, 50)); break; | |
158 } | |
159 } else if (name == "Plot Type") { | |
160 setPlotStyle(PlotStyle(value)); | |
161 } | |
162 } | |
163 | |
164 void | |
165 TimeInstantLayer::setBaseColour(QColor colour) | |
166 { | |
167 if (m_colour == colour) return; | |
168 m_colour = colour; | |
169 emit layerParametersChanged(); | |
170 } | |
171 | |
172 void | |
173 TimeInstantLayer::setPlotStyle(PlotStyle style) | |
174 { | |
175 if (m_plotStyle == style) return; | |
176 m_plotStyle = style; | |
177 emit layerParametersChanged(); | |
178 } | |
179 | |
180 bool | |
181 TimeInstantLayer::isLayerScrollable(const View *v) const | |
182 { | |
183 QPoint discard; | |
184 return !v->shouldIlluminateLocalFeatures(this, discard); | |
185 } | |
186 | |
187 SparseOneDimensionalModel::PointList | |
188 TimeInstantLayer::getLocalPoints(View *v, int x) const | |
189 { | |
190 // Return a set of points that all have the same frame number, the | |
191 // nearest to the given x coordinate, and that are within a | |
192 // certain fuzz distance of that x coordinate. | |
193 | |
194 if (!m_model) return SparseOneDimensionalModel::PointList(); | |
195 | |
196 long frame = v->getFrameForX(x); | |
197 | |
198 SparseOneDimensionalModel::PointList onPoints = | |
199 m_model->getPoints(frame); | |
200 | |
201 if (!onPoints.empty()) { | |
202 return onPoints; | |
203 } | |
204 | |
205 SparseOneDimensionalModel::PointList prevPoints = | |
206 m_model->getPreviousPoints(frame); | |
207 SparseOneDimensionalModel::PointList nextPoints = | |
208 m_model->getNextPoints(frame); | |
209 | |
210 SparseOneDimensionalModel::PointList usePoints = prevPoints; | |
211 | |
212 if (prevPoints.empty()) { | |
213 usePoints = nextPoints; | |
214 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() && | |
215 !(nextPoints.begin()->frame > v->getEndFrame())) { | |
216 usePoints = nextPoints; | |
217 } else if (nextPoints.begin()->frame - frame < | |
218 frame - prevPoints.begin()->frame) { | |
219 usePoints = nextPoints; | |
220 } | |
221 | |
222 if (!usePoints.empty()) { | |
223 int fuzz = 2; | |
224 int px = v->getXForFrame(usePoints.begin()->frame); | |
225 if ((px > x && px - x > fuzz) || | |
226 (px < x && x - px > fuzz + 1)) { | |
227 usePoints.clear(); | |
228 } | |
229 } | |
230 | |
231 return usePoints; | |
232 } | |
233 | |
234 QString | |
235 TimeInstantLayer::getFeatureDescription(View *v, QPoint &pos) const | |
236 { | |
237 int x = pos.x(); | |
238 | |
239 if (!m_model || !m_model->getSampleRate()) return ""; | |
240 | |
241 SparseOneDimensionalModel::PointList points = getLocalPoints(v, x); | |
242 | |
243 if (points.empty()) { | |
244 if (!m_model->isReady()) { | |
245 return tr("In progress"); | |
246 } else { | |
247 return tr("No local points"); | |
248 } | |
249 } | |
250 | |
251 long useFrame = points.begin()->frame; | |
252 | |
253 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | |
254 | |
255 QString text; | |
256 | |
257 if (points.begin()->label == "") { | |
258 text = QString(tr("Time:\t%1\nNo label")) | |
259 .arg(rt.toText(true).c_str()); | |
260 } else { | |
261 text = QString(tr("Time:\t%1\nLabel:\t%2")) | |
262 .arg(rt.toText(true).c_str()) | |
263 .arg(points.begin()->label); | |
264 } | |
265 | |
266 pos = QPoint(v->getXForFrame(useFrame), pos.y()); | |
267 return text; | |
268 } | |
269 | |
270 bool | |
271 TimeInstantLayer::snapToFeatureFrame(View *v, int &frame, | |
272 size_t &resolution, | |
273 SnapType snap) const | |
274 { | |
275 if (!m_model) { | |
276 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | |
277 } | |
278 | |
279 resolution = m_model->getResolution(); | |
280 SparseOneDimensionalModel::PointList points; | |
281 | |
282 if (snap == SnapNeighbouring) { | |
283 | |
284 points = getLocalPoints(v, v->getXForFrame(frame)); | |
285 if (points.empty()) return false; | |
286 frame = points.begin()->frame; | |
287 return true; | |
288 } | |
289 | |
290 points = m_model->getPoints(frame, frame); | |
291 int snapped = frame; | |
292 bool found = false; | |
293 | |
294 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); | |
295 i != points.end(); ++i) { | |
296 | |
297 if (snap == SnapRight) { | |
298 | |
299 if (i->frame >= frame) { | |
300 snapped = i->frame; | |
301 found = true; | |
302 break; | |
303 } | |
304 | |
305 } else if (snap == SnapLeft) { | |
306 | |
307 if (i->frame <= frame) { | |
308 snapped = i->frame; | |
309 found = true; // don't break, as the next may be better | |
310 } else { | |
311 break; | |
312 } | |
313 | |
314 } else { // nearest | |
315 | |
316 SparseOneDimensionalModel::PointList::const_iterator j = i; | |
317 ++j; | |
318 | |
319 if (j == points.end()) { | |
320 | |
321 snapped = i->frame; | |
322 found = true; | |
323 break; | |
324 | |
325 } else if (j->frame >= frame) { | |
326 | |
327 if (j->frame - frame < frame - i->frame) { | |
328 snapped = j->frame; | |
329 } else { | |
330 snapped = i->frame; | |
331 } | |
332 found = true; | |
333 break; | |
334 } | |
335 } | |
336 } | |
337 | |
338 frame = snapped; | |
339 return found; | |
340 } | |
341 | |
342 void | |
343 TimeInstantLayer::paint(View *v, QPainter &paint, QRect rect) const | |
344 { | |
345 if (!m_model || !m_model->isOK()) return; | |
346 | |
347 // Profiler profiler("TimeInstantLayer::paint", true); | |
348 | |
349 int x0 = rect.left(), x1 = rect.right(); | |
350 | |
351 long frame0 = v->getFrameForX(x0); | |
352 long frame1 = v->getFrameForX(x1); | |
353 | |
354 SparseOneDimensionalModel::PointList points(m_model->getPoints | |
355 (frame0, frame1)); | |
356 | |
357 bool odd = false; | |
358 if (m_plotStyle == PlotSegmentation && !points.empty()) { | |
359 int index = m_model->getIndexOf(*points.begin()); | |
360 odd = ((index % 2) == 1); | |
361 } | |
362 | |
363 paint.setPen(m_colour); | |
364 | |
365 QColor brushColour(m_colour); | |
366 brushColour.setAlpha(100); | |
367 paint.setBrush(brushColour); | |
368 | |
369 QColor oddBrushColour(brushColour); | |
370 if (m_plotStyle == PlotSegmentation) { | |
371 if (m_colour == Qt::black) { | |
372 oddBrushColour = Qt::gray; | |
373 } else if (m_colour == Qt::darkRed) { | |
374 oddBrushColour = Qt::red; | |
375 } else if (m_colour == Qt::darkBlue) { | |
376 oddBrushColour = Qt::blue; | |
377 } else if (m_colour == Qt::darkGreen) { | |
378 oddBrushColour = Qt::green; | |
379 } else { | |
380 oddBrushColour = oddBrushColour.light(150); | |
381 } | |
382 oddBrushColour.setAlpha(100); | |
383 } | |
384 | |
385 // std::cerr << "TimeInstantLayer::paint: resolution is " | |
386 // << m_model->getResolution() << " frames" << std::endl; | |
387 | |
388 QPoint localPos; | |
389 long illuminateFrame = -1; | |
390 | |
391 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | |
392 SparseOneDimensionalModel::PointList localPoints = | |
393 getLocalPoints(v, localPos.x()); | |
394 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | |
395 } | |
396 | |
397 int prevX = -1; | |
398 int textY = v->getTextLabelHeight(this, paint); | |
399 | |
400 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); | |
401 i != points.end(); ++i) { | |
402 | |
403 const SparseOneDimensionalModel::Point &p(*i); | |
404 SparseOneDimensionalModel::PointList::const_iterator j = i; | |
405 ++j; | |
406 | |
407 int x = v->getXForFrame(p.frame); | |
408 if (x == prevX && p.frame != illuminateFrame) continue; | |
409 | |
410 int iw = v->getXForFrame(p.frame + m_model->getResolution()) - x; | |
411 if (iw < 2) { | |
412 if (iw < 1) { | |
413 iw = 2; | |
414 if (j != points.end()) { | |
415 int nx = v->getXForFrame(j->frame); | |
416 if (nx < x + 3) iw = 1; | |
417 } | |
418 } else { | |
419 iw = 2; | |
420 } | |
421 } | |
422 | |
423 if (p.frame == illuminateFrame) { | |
424 paint.setPen(Qt::black); //!!! | |
425 } else { | |
426 paint.setPen(brushColour); | |
427 } | |
428 | |
429 if (m_plotStyle == PlotInstants) { | |
430 if (iw > 1) { | |
431 paint.drawRect(x, 0, iw - 1, v->height() - 1); | |
432 } else { | |
433 paint.drawLine(x, 0, x, v->height() - 1); | |
434 } | |
435 } else { | |
436 | |
437 if (odd) paint.setBrush(oddBrushColour); | |
438 else paint.setBrush(brushColour); | |
439 | |
440 int nx; | |
441 | |
442 if (j != points.end()) { | |
443 const SparseOneDimensionalModel::Point &q(*j); | |
444 nx = v->getXForFrame(q.frame); | |
445 } else { | |
446 nx = v->getXForFrame(m_model->getEndFrame()); | |
447 } | |
448 | |
449 if (nx >= x) { | |
450 | |
451 if (illuminateFrame != p.frame && | |
452 (nx < x + 5 || x >= v->width() - 1)) { | |
453 paint.setPen(Qt::NoPen); | |
454 } | |
455 | |
456 paint.drawRect(x, -1, nx - x, v->height() + 1); | |
457 } | |
458 | |
459 odd = !odd; | |
460 } | |
461 | |
462 paint.setPen(m_colour); | |
463 | |
464 if (p.label != "") { | |
465 | |
466 // only draw if there's enough room from here to the next point | |
467 | |
468 int lw = paint.fontMetrics().width(p.label); | |
469 bool good = true; | |
470 | |
471 if (j != points.end()) { | |
472 int nx = v->getXForFrame(j->frame); | |
473 if (nx >= x && nx - x - iw - 3 <= lw) good = false; | |
474 } | |
475 | |
476 if (good) { | |
477 paint.drawText(x + iw + 2, textY, p.label); | |
478 } | |
479 } | |
480 | |
481 prevX = x; | |
482 } | |
483 } | |
484 | |
485 void | |
486 TimeInstantLayer::drawStart(View *v, QMouseEvent *e) | |
487 { | |
488 std::cerr << "TimeInstantLayer::drawStart(" << e->x() << ")" << std::endl; | |
489 | |
490 if (!m_model) return; | |
491 | |
492 long frame = v->getFrameForX(e->x()); | |
493 if (frame < 0) frame = 0; | |
494 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
495 | |
496 m_editingPoint = SparseOneDimensionalModel::Point(frame, tr("New Point")); | |
497 | |
498 if (m_editingCommand) m_editingCommand->finish(); | |
499 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, | |
500 tr("Draw Point")); | |
501 m_editingCommand->addPoint(m_editingPoint); | |
502 | |
503 m_editing = true; | |
504 } | |
505 | |
506 void | |
507 TimeInstantLayer::drawDrag(View *v, QMouseEvent *e) | |
508 { | |
509 std::cerr << "TimeInstantLayer::drawDrag(" << e->x() << ")" << std::endl; | |
510 | |
511 if (!m_model || !m_editing) return; | |
512 | |
513 long frame = v->getFrameForX(e->x()); | |
514 if (frame < 0) frame = 0; | |
515 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
516 m_editingCommand->deletePoint(m_editingPoint); | |
517 m_editingPoint.frame = frame; | |
518 m_editingCommand->addPoint(m_editingPoint); | |
519 } | |
520 | |
521 void | |
522 TimeInstantLayer::drawEnd(View *, QMouseEvent *e) | |
523 { | |
524 std::cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << std::endl; | |
525 if (!m_model || !m_editing) return; | |
526 QString newName = tr("Add Point at %1 s") | |
527 .arg(RealTime::frame2RealTime(m_editingPoint.frame, | |
528 m_model->getSampleRate()) | |
529 .toText(false).c_str()); | |
530 m_editingCommand->setName(newName); | |
531 m_editingCommand->finish(); | |
532 m_editingCommand = 0; | |
533 m_editing = false; | |
534 } | |
535 | |
536 void | |
537 TimeInstantLayer::editStart(View *v, QMouseEvent *e) | |
538 { | |
539 std::cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << std::endl; | |
540 | |
541 if (!m_model) return; | |
542 | |
543 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); | |
544 if (points.empty()) return; | |
545 | |
546 m_editingPoint = *points.begin(); | |
547 | |
548 if (m_editingCommand) { | |
549 m_editingCommand->finish(); | |
550 m_editingCommand = 0; | |
551 } | |
552 | |
553 m_editing = true; | |
554 } | |
555 | |
556 void | |
557 TimeInstantLayer::editDrag(View *v, QMouseEvent *e) | |
558 { | |
559 std::cerr << "TimeInstantLayer::editDrag(" << e->x() << ")" << std::endl; | |
560 | |
561 if (!m_model || !m_editing) return; | |
562 | |
563 long frame = v->getFrameForX(e->x()); | |
564 if (frame < 0) frame = 0; | |
565 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
566 | |
567 if (!m_editingCommand) { | |
568 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, | |
569 tr("Drag Point")); | |
570 } | |
571 | |
572 m_editingCommand->deletePoint(m_editingPoint); | |
573 m_editingPoint.frame = frame; | |
574 m_editingCommand->addPoint(m_editingPoint); | |
575 } | |
576 | |
577 void | |
578 TimeInstantLayer::editEnd(View *, QMouseEvent *e) | |
579 { | |
580 std::cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << std::endl; | |
581 if (!m_model || !m_editing) return; | |
582 if (m_editingCommand) { | |
583 QString newName = tr("Move Point to %1 s") | |
584 .arg(RealTime::frame2RealTime(m_editingPoint.frame, | |
585 m_model->getSampleRate()) | |
586 .toText(false).c_str()); | |
587 m_editingCommand->setName(newName); | |
588 m_editingCommand->finish(); | |
589 } | |
590 m_editingCommand = 0; | |
591 m_editing = false; | |
592 } | |
593 | |
594 void | |
595 TimeInstantLayer::editOpen(View *v, QMouseEvent *e) | |
596 { | |
597 if (!m_model) return; | |
598 | |
599 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); | |
600 if (points.empty()) return; | |
601 | |
602 SparseOneDimensionalModel::Point point = *points.begin(); | |
603 | |
604 ItemEditDialog *dialog = new ItemEditDialog | |
605 (m_model->getSampleRate(), | |
606 ItemEditDialog::ShowTime | | |
607 ItemEditDialog::ShowText); | |
608 | |
609 dialog->setFrameTime(point.frame); | |
610 dialog->setText(point.label); | |
611 | |
612 if (dialog->exec() == QDialog::Accepted) { | |
613 | |
614 SparseOneDimensionalModel::Point newPoint = point; | |
615 newPoint.frame = dialog->getFrameTime(); | |
616 newPoint.label = dialog->getText(); | |
617 | |
618 SparseOneDimensionalModel::EditCommand *command = | |
619 new SparseOneDimensionalModel::EditCommand(m_model, tr("Edit Point")); | |
620 command->deletePoint(point); | |
621 command->addPoint(newPoint); | |
622 command->finish(); | |
623 } | |
624 | |
625 delete dialog; | |
626 } | |
627 | |
628 void | |
629 TimeInstantLayer::moveSelection(Selection s, size_t newStartFrame) | |
630 { | |
631 if (!m_model) return; | |
632 | |
633 SparseOneDimensionalModel::EditCommand *command = | |
634 new SparseOneDimensionalModel::EditCommand(m_model, | |
635 tr("Drag Selection")); | |
636 | |
637 SparseOneDimensionalModel::PointList points = | |
638 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
639 | |
640 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); | |
641 i != points.end(); ++i) { | |
642 | |
643 if (s.contains(i->frame)) { | |
644 SparseOneDimensionalModel::Point newPoint(*i); | |
645 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); | |
646 command->deletePoint(*i); | |
647 command->addPoint(newPoint); | |
648 } | |
649 } | |
650 | |
651 command->finish(); | |
652 } | |
653 | |
654 void | |
655 TimeInstantLayer::resizeSelection(Selection s, Selection newSize) | |
656 { | |
657 if (!m_model) return; | |
658 | |
659 SparseOneDimensionalModel::EditCommand *command = | |
660 new SparseOneDimensionalModel::EditCommand(m_model, | |
661 tr("Resize Selection")); | |
662 | |
663 SparseOneDimensionalModel::PointList points = | |
664 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
665 | |
666 double ratio = | |
667 double(newSize.getEndFrame() - newSize.getStartFrame()) / | |
668 double(s.getEndFrame() - s.getStartFrame()); | |
669 | |
670 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); | |
671 i != points.end(); ++i) { | |
672 | |
673 if (s.contains(i->frame)) { | |
674 | |
675 double target = i->frame; | |
676 target = newSize.getStartFrame() + | |
677 double(target - s.getStartFrame()) * ratio; | |
678 | |
679 SparseOneDimensionalModel::Point newPoint(*i); | |
680 newPoint.frame = lrint(target); | |
681 command->deletePoint(*i); | |
682 command->addPoint(newPoint); | |
683 } | |
684 } | |
685 | |
686 command->finish(); | |
687 } | |
688 | |
689 void | |
690 TimeInstantLayer::deleteSelection(Selection s) | |
691 { | |
692 if (!m_model) return; | |
693 | |
694 SparseOneDimensionalModel::EditCommand *command = | |
695 new SparseOneDimensionalModel::EditCommand(m_model, | |
696 tr("Delete Selection")); | |
697 | |
698 SparseOneDimensionalModel::PointList points = | |
699 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
700 | |
701 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); | |
702 i != points.end(); ++i) { | |
703 if (s.contains(i->frame)) command->deletePoint(*i); | |
704 } | |
705 | |
706 command->finish(); | |
707 } | |
708 | |
709 void | |
710 TimeInstantLayer::copy(Selection s, Clipboard &to) | |
711 { | |
712 if (!m_model) return; | |
713 | |
714 SparseOneDimensionalModel::PointList points = | |
715 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
716 | |
717 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); | |
718 i != points.end(); ++i) { | |
719 if (s.contains(i->frame)) { | |
720 Clipboard::Point point(i->frame, i->label); | |
721 to.addPoint(point); | |
722 } | |
723 } | |
724 } | |
725 | |
726 bool | |
727 TimeInstantLayer::paste(const Clipboard &from, int frameOffset, bool) | |
728 { | |
729 if (!m_model) return false; | |
730 | |
731 const Clipboard::PointList &points = from.getPoints(); | |
732 | |
733 SparseOneDimensionalModel::EditCommand *command = | |
734 new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste")); | |
735 | |
736 for (Clipboard::PointList::const_iterator i = points.begin(); | |
737 i != points.end(); ++i) { | |
738 | |
739 if (!i->haveFrame()) continue; | |
740 size_t frame = 0; | |
741 if (frameOffset > 0 || -frameOffset < i->getFrame()) { | |
742 frame = i->getFrame() + frameOffset; | |
743 } | |
744 SparseOneDimensionalModel::Point newPoint(frame); | |
745 if (i->haveLabel()) { | |
746 newPoint.label = i->getLabel(); | |
747 } else if (i->haveValue()) { | |
748 newPoint.label = QString("%1").arg(i->getValue()); | |
749 } | |
750 | |
751 command->addPoint(newPoint); | |
752 } | |
753 | |
754 command->finish(); | |
755 return true; | |
756 } | |
757 | |
758 QString | |
759 TimeInstantLayer::toXmlString(QString indent, QString extraAttributes) const | |
760 { | |
761 return Layer::toXmlString(indent, extraAttributes + | |
762 QString(" colour=\"%1\" plotStyle=\"%2\"") | |
763 .arg(encodeColour(m_colour)).arg(m_plotStyle)); | |
764 } | |
765 | |
766 void | |
767 TimeInstantLayer::setProperties(const QXmlAttributes &attributes) | |
768 { | |
769 QString colourSpec = attributes.value("colour"); | |
770 if (colourSpec != "") { | |
771 QColor colour(colourSpec); | |
772 if (colour.isValid()) { | |
773 setBaseColour(QColor(colourSpec)); | |
774 } | |
775 } | |
776 | |
777 bool ok; | |
778 PlotStyle style = (PlotStyle) | |
779 attributes.value("plotStyle").toInt(&ok); | |
780 if (ok) setPlotStyle(style); | |
781 } | |
782 |