comparison layer/TextLayer.cpp @ 1486:ac0a8addabcf

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:25:16 +0100
parents 36ad3cdabf55
children 37df1530519d
comparison
equal deleted inserted replaced
1468:de41a11cabc2 1486:ac0a8addabcf
32 #include <iostream> 32 #include <iostream>
33 #include <cmath> 33 #include <cmath>
34 34
35 TextLayer::TextLayer() : 35 TextLayer::TextLayer() :
36 SingleColourLayer(), 36 SingleColourLayer(),
37 m_model(nullptr),
38 m_editing(false), 37 m_editing(false),
39 m_originalPoint(0, 0.0, tr("Empty Label")), 38 m_originalPoint(0, 0.0, tr("Empty Label")),
40 m_editingPoint(0, 0.0, tr("Empty Label")), 39 m_editingPoint(0, 0.0, tr("Empty Label")),
41 m_editingCommand(nullptr) 40 m_editingCommand(nullptr)
42 { 41 {
43 42
44 } 43 }
45 44
46 void 45 int
47 TextLayer::setModel(TextModel *model) 46 TextLayer::getCompletion(LayerGeometryProvider *) const
48 { 47 {
49 if (m_model == model) return; 48 auto model = ModelById::get(m_model);
50 m_model = model; 49 if (model) return model->getCompletion();
51 50 else return 0;
52 connectSignals(m_model); 51 }
53 52
54 // SVDEBUG << "TextLayer::setModel(" << model << ")" << endl; 53 void
54 TextLayer::setModel(ModelId modelId)
55 {
56 auto newModel = ModelById::getAs<TextModel>(modelId);
57
58 if (!modelId.isNone() && !newModel) {
59 throw std::logic_error("Not a TextModel");
60 }
61
62 if (m_model == modelId) return;
63 m_model = modelId;
64
65 if (newModel) {
66 connectSignals(m_model);
67 }
55 68
56 emit modelReplaced(); 69 emit modelReplaced();
57 } 70 }
58 71
59 Layer::PropertyList 72 Layer::PropertyList
109 } 122 }
110 123
111 EventVector 124 EventVector
112 TextLayer::getLocalPoints(LayerGeometryProvider *v, int x, int y) const 125 TextLayer::getLocalPoints(LayerGeometryProvider *v, int x, int y) const
113 { 126 {
114 if (!m_model) return {}; 127 auto model = ModelById::getAs<TextModel>(m_model);
128 if (!model) return {};
115 129
116 int overlap = ViewManager::scalePixelSize(150); 130 int overlap = ViewManager::scalePixelSize(150);
117 131
118 sv_frame_t frame0 = v->getFrameForX(-overlap); 132 sv_frame_t frame0 = v->getFrameForX(-overlap);
119 sv_frame_t frame1 = v->getFrameForX(v->getPaintWidth() + overlap); 133 sv_frame_t frame1 = v->getFrameForX(v->getPaintWidth() + overlap);
120 134
121 EventVector points(m_model->getEventsSpanning(frame0, frame1 - frame0)); 135 EventVector points(model->getEventsSpanning(frame0, frame1 - frame0));
122 136
123 EventVector rv; 137 EventVector rv;
124 QFontMetrics metrics = QFontMetrics(QFont()); 138 QFontMetrics metrics = QFontMetrics(QFont());
125 139
126 for (EventVector::iterator i = points.begin(); i != points.end(); ++i) { 140 for (EventVector::iterator i = points.begin(); i != points.end(); ++i) {
154 } 168 }
155 169
156 bool 170 bool
157 TextLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &p) const 171 TextLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &p) const
158 { 172 {
159 if (!m_model) return false; 173 auto model = ModelById::getAs<TextModel>(m_model);
174 if (!model) return false;
160 175
161 sv_frame_t a = v->getFrameForX(x - ViewManager::scalePixelSize(120)); 176 sv_frame_t a = v->getFrameForX(x - ViewManager::scalePixelSize(120));
162 sv_frame_t b = v->getFrameForX(x + ViewManager::scalePixelSize(10)); 177 sv_frame_t b = v->getFrameForX(x + ViewManager::scalePixelSize(10));
163 EventVector onPoints = m_model->getEventsWithin(a, b); 178 EventVector onPoints = model->getEventsWithin(a, b);
164 if (onPoints.empty()) return false; 179 if (onPoints.empty()) return false;
165 180
166 double nearestDistance = -1; 181 double nearestDistance = -1;
167 182
168 for (EventVector::const_iterator i = onPoints.begin(); 183 for (EventVector::const_iterator i = onPoints.begin();
184 QString 199 QString
185 TextLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const 200 TextLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
186 { 201 {
187 int x = pos.x(); 202 int x = pos.x();
188 203
189 if (!m_model || !m_model->getSampleRate()) return ""; 204 auto model = ModelById::getAs<TextModel>(m_model);
205 if (!model || !model->getSampleRate()) return "";
190 206
191 EventVector points = getLocalPoints(v, x, pos.y()); 207 EventVector points = getLocalPoints(v, x, pos.y());
192 208
193 if (points.empty()) { 209 if (points.empty()) {
194 if (!m_model->isReady()) { 210 if (!model->isReady()) {
195 return tr("In progress"); 211 return tr("In progress");
196 } else { 212 } else {
197 return ""; 213 return "";
198 } 214 }
199 } 215 }
200 216
201 sv_frame_t useFrame = points.begin()->getFrame(); 217 sv_frame_t useFrame = points.begin()->getFrame();
202 218
203 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); 219 RealTime rt = RealTime::frame2RealTime(useFrame, model->getSampleRate());
204 220
205 QString text; 221 QString text;
206 222
207 if (points.begin()->getLabel() == "") { 223 if (points.begin()->getLabel() == "") {
208 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3")) 224 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3"))
222 bool 238 bool
223 TextLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, 239 TextLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
224 int &resolution, 240 int &resolution,
225 SnapType snap) const 241 SnapType snap) const
226 { 242 {
227 if (!m_model) { 243 auto model = ModelById::getAs<TextModel>(m_model);
244 if (!model) {
228 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 245 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
229 } 246 }
230 247
231 // SnapLeft / SnapRight: return frame of nearest feature in that 248 // SnapLeft / SnapRight: return frame of nearest feature in that
232 // direction no matter how far away 249 // direction no matter how far away
233 // 250 //
234 // SnapNeighbouring: return frame of feature that would be used in 251 // SnapNeighbouring: return frame of feature that would be used in
235 // an editing operation, i.e. closest feature in either direction 252 // an editing operation, i.e. closest feature in either direction
236 // but only if it is "close enough" 253 // but only if it is "close enough"
237 254
238 resolution = m_model->getResolution(); 255 resolution = model->getResolution();
239 256
240 if (snap == SnapNeighbouring) { 257 if (snap == SnapNeighbouring) {
241 EventVector points = getLocalPoints(v, v->getXForFrame(frame), -1); 258 EventVector points = getLocalPoints(v, v->getXForFrame(frame), -1);
242 if (points.empty()) return false; 259 if (points.empty()) return false;
243 frame = points.begin()->getFrame(); 260 frame = points.begin()->getFrame();
244 return true; 261 return true;
245 } 262 }
246 263
247 Event e; 264 Event e;
248 if (m_model->getNearestEventMatching 265 if (model->getNearestEventMatching
249 (frame, 266 (frame,
250 [](Event) { return true; }, 267 [](Event) { return true; },
251 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward, 268 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward,
252 e)) { 269 e)) {
253 frame = e.getFrame(); 270 frame = e.getFrame();
272 } 289 }
273 290
274 void 291 void
275 TextLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 292 TextLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
276 { 293 {
277 if (!m_model || !m_model->isOK()) return; 294 auto model = ModelById::getAs<TextModel>(m_model);
278 295 if (!model || !model->isOK()) return;
279 sv_samplerate_t sampleRate = m_model->getSampleRate(); 296
297 sv_samplerate_t sampleRate = model->getSampleRate();
280 if (!sampleRate) return; 298 if (!sampleRate) return;
281 299
282 // Profiler profiler("TextLayer::paint", true); 300 // Profiler profiler("TextLayer::paint", true);
283 301
284 int x0 = rect.left(), x1 = rect.right(); 302 int x0 = rect.left(), x1 = rect.right();
285 int overlap = ViewManager::scalePixelSize(150); 303 int overlap = ViewManager::scalePixelSize(150);
286 sv_frame_t frame0 = v->getFrameForX(x0 - overlap); 304 sv_frame_t frame0 = v->getFrameForX(x0 - overlap);
287 sv_frame_t frame1 = v->getFrameForX(x1 + overlap); 305 sv_frame_t frame1 = v->getFrameForX(x1 + overlap);
288 306
289 EventVector points(m_model->getEventsWithin(frame0, frame1 - frame0, 2)); 307 EventVector points(model->getEventsWithin(frame0, frame1 - frame0, 2));
290 if (points.empty()) return; 308 if (points.empty()) return;
291 309
292 QColor brushColour(getBaseQColor()); 310 QColor brushColour(getBaseQColor());
293 311
294 int h, s, val; 312 int h, s, val;
297 315
298 QColor penColour; 316 QColor penColour;
299 penColour = v->getForeground(); 317 penColour = v->getForeground();
300 318
301 // SVDEBUG << "TextLayer::paint: resolution is " 319 // SVDEBUG << "TextLayer::paint: resolution is "
302 // << m_model->getResolution() << " frames" << endl; 320 // << model->getResolution() << " frames" << endl;
303 321
304 QPoint localPos; 322 QPoint localPos;
305 Event illuminatePoint(0); 323 Event illuminatePoint(0);
306 bool shouldIlluminate = false; 324 bool shouldIlluminate = false;
307 325
377 void 395 void
378 TextLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e) 396 TextLayer::drawStart(LayerGeometryProvider *v, QMouseEvent *e)
379 { 397 {
380 // SVDEBUG << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl; 398 // SVDEBUG << "TextLayer::drawStart(" << e->x() << "," << e->y() << ")" << endl;
381 399
382 if (!m_model) { 400 auto model = ModelById::getAs<TextModel>(m_model);
401 if (!model) {
383 SVDEBUG << "TextLayer::drawStart: no model" << endl; 402 SVDEBUG << "TextLayer::drawStart: no model" << endl;
384 return; 403 return;
385 } 404 }
386 405
387 sv_frame_t frame = v->getFrameForX(e->x()); 406 sv_frame_t frame = v->getFrameForX(e->x());
388 if (frame < 0) frame = 0; 407 if (frame < 0) frame = 0;
389 frame = frame / m_model->getResolution() * m_model->getResolution(); 408 frame = frame / model->getResolution() * model->getResolution();
390 409
391 double height = getHeightForY(v, e->y()); 410 double height = getHeightForY(v, e->y());
392 411
393 m_editingPoint = Event(frame, float(height), ""); 412 m_editingPoint = Event(frame, float(height), "");
394 m_originalPoint = m_editingPoint; 413 m_originalPoint = m_editingPoint;
395 414
396 if (m_editingCommand) finish(m_editingCommand); 415 if (m_editingCommand) finish(m_editingCommand);
397 m_editingCommand = new ChangeEventsCommand(m_model, "Add Label"); 416 m_editingCommand = new ChangeEventsCommand(m_model.untyped, "Add Label");
398 m_editingCommand->add(m_editingPoint); 417 m_editingCommand->add(m_editingPoint);
399 418
400 m_editing = true; 419 m_editing = true;
401 } 420 }
402 421
403 void 422 void
404 TextLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e) 423 TextLayer::drawDrag(LayerGeometryProvider *v, QMouseEvent *e)
405 { 424 {
406 // SVDEBUG << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl; 425 // SVDEBUG << "TextLayer::drawDrag(" << e->x() << "," << e->y() << ")" << endl;
407 426
408 if (!m_model || !m_editing) return; 427 auto model = ModelById::getAs<TextModel>(m_model);
428 if (!model || !m_editing) return;
409 429
410 sv_frame_t frame = v->getFrameForX(e->x()); 430 sv_frame_t frame = v->getFrameForX(e->x());
411 if (frame < 0) frame = 0; 431 if (frame < 0) frame = 0;
412 frame = frame / m_model->getResolution() * m_model->getResolution(); 432 frame = frame / model->getResolution() * model->getResolution();
413 433
414 double height = getHeightForY(v, e->y()); 434 double height = getHeightForY(v, e->y());
415 435
416 m_editingCommand->remove(m_editingPoint); 436 m_editingCommand->remove(m_editingPoint);
417 m_editingPoint = m_editingPoint 437 m_editingPoint = m_editingPoint
422 442
423 void 443 void
424 TextLayer::drawEnd(LayerGeometryProvider *v, QMouseEvent *) 444 TextLayer::drawEnd(LayerGeometryProvider *v, QMouseEvent *)
425 { 445 {
426 // SVDEBUG << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl; 446 // SVDEBUG << "TextLayer::drawEnd(" << e->x() << "," << e->y() << ")" << endl;
427 if (!m_model || !m_editing) return; 447 auto model = ModelById::getAs<TextModel>(m_model);
448 if (!model || !m_editing) return;
428 449
429 bool ok = false; 450 bool ok = false;
430 QString label = QInputDialog::getText(v->getView(), tr("Enter label"), 451 QString label = QInputDialog::getText(v->getView(), tr("Enter label"),
431 tr("Please enter a new label:"), 452 tr("Please enter a new label:"),
432 QLineEdit::Normal, "", &ok); 453 QLineEdit::Normal, "", &ok);
445 } 466 }
446 467
447 void 468 void
448 TextLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) 469 TextLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e)
449 { 470 {
450 if (!m_model) return; 471 auto model = ModelById::getAs<TextModel>(m_model);
472 if (!model) return;
451 473
452 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return; 474 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) return;
453 475
454 if (m_editingCommand) { 476 if (m_editingCommand) {
455 finish(m_editingCommand); 477 finish(m_editingCommand);
465 } 487 }
466 488
467 void 489 void
468 TextLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e) 490 TextLayer::eraseEnd(LayerGeometryProvider *v, QMouseEvent *e)
469 { 491 {
470 if (!m_model || !m_editing) return; 492 auto model = ModelById::getAs<TextModel>(m_model);
493 if (!model || !m_editing) return;
471 494
472 m_editing = false; 495 m_editing = false;
473 496
474 Event p; 497 Event p;
475 if (!getPointToDrag(v, e->x(), e->y(), p)) return; 498 if (!getPointToDrag(v, e->x(), e->y(), p)) return;
476 if (p.getFrame() != m_editingPoint.getFrame() || 499 if (p.getFrame() != m_editingPoint.getFrame() ||
477 p.getValue() != m_editingPoint.getValue()) return; 500 p.getValue() != m_editingPoint.getValue()) return;
478 501
479 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point")); 502 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Erase Point"));
480 m_editingCommand->remove(m_editingPoint); 503 m_editingCommand->remove(m_editingPoint);
481 finish(m_editingCommand); 504 finish(m_editingCommand);
482 m_editingCommand = nullptr; 505 m_editingCommand = nullptr;
483 m_editing = false; 506 m_editing = false;
484 } 507 }
486 void 509 void
487 TextLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e) 510 TextLayer::editStart(LayerGeometryProvider *v, QMouseEvent *e)
488 { 511 {
489 // SVDEBUG << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << endl; 512 // SVDEBUG << "TextLayer::editStart(" << e->x() << "," << e->y() << ")" << endl;
490 513
491 if (!m_model) return; 514 auto model = ModelById::getAs<TextModel>(m_model);
515 if (!model) return;
492 516
493 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) { 517 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) {
494 return; 518 return;
495 } 519 }
496 520
506 } 530 }
507 531
508 void 532 void
509 TextLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e) 533 TextLayer::editDrag(LayerGeometryProvider *v, QMouseEvent *e)
510 { 534 {
511 if (!m_model || !m_editing) return; 535 auto model = ModelById::getAs<TextModel>(m_model);
536 if (!model || !m_editing) return;
512 537
513 sv_frame_t frameDiff = 538 sv_frame_t frameDiff =
514 v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x()); 539 v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x());
515 double heightDiff = 540 double heightDiff =
516 getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y()); 541 getHeightForY(v, e->y()) - getHeightForY(v, m_editOrigin.y());
517 542
518 sv_frame_t frame = m_originalPoint.getFrame() + frameDiff; 543 sv_frame_t frame = m_originalPoint.getFrame() + frameDiff;
519 double height = m_originalPoint.getValue() + heightDiff; 544 double height = m_originalPoint.getValue() + heightDiff;
520 545
521 if (frame < 0) frame = 0; 546 if (frame < 0) frame = 0;
522 frame = (frame / m_model->getResolution()) * m_model->getResolution(); 547 frame = (frame / model->getResolution()) * model->getResolution();
523 548
524 if (!m_editingCommand) { 549 if (!m_editingCommand) {
525 m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Label")); 550 m_editingCommand = new ChangeEventsCommand(m_model.untyped, tr("Drag Label"));
526 } 551 }
527 552
528 m_editingCommand->remove(m_editingPoint); 553 m_editingCommand->remove(m_editingPoint);
529 m_editingPoint = m_editingPoint 554 m_editingPoint = m_editingPoint
530 .withFrame(frame) 555 .withFrame(frame)
534 559
535 void 560 void
536 TextLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) 561 TextLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
537 { 562 {
538 // SVDEBUG << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl; 563 // SVDEBUG << "TextLayer::editEnd(" << e->x() << "," << e->y() << ")" << endl;
539 if (!m_model || !m_editing) return; 564 auto model = ModelById::getAs<TextModel>(m_model);
565 if (!model || !m_editing) return;
540 566
541 if (m_editingCommand) { 567 if (m_editingCommand) {
542 568
543 QString newName = m_editingCommand->getName(); 569 QString newName = m_editingCommand->getName();
544 570
561 } 587 }
562 588
563 bool 589 bool
564 TextLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) 590 TextLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
565 { 591 {
566 if (!m_model) return false; 592 auto model = ModelById::getAs<TextModel>(m_model);
593 if (!model) return false;
567 594
568 Event text; 595 Event text;
569 if (!getPointToDrag(v, e->x(), e->y(), text)) return false; 596 if (!getPointToDrag(v, e->x(), e->y(), text)) return false;
570 597
571 QString label = text.getLabel(); 598 QString label = text.getLabel();
574 label = QInputDialog::getText(v->getView(), tr("Enter label"), 601 label = QInputDialog::getText(v->getView(), tr("Enter label"),
575 tr("Please enter a new label:"), 602 tr("Please enter a new label:"),
576 QLineEdit::Normal, label, &ok); 603 QLineEdit::Normal, label, &ok);
577 if (ok && label != text.getLabel()) { 604 if (ok && label != text.getLabel()) {
578 ChangeEventsCommand *command = 605 ChangeEventsCommand *command =
579 new ChangeEventsCommand(m_model, tr("Re-Label Point")); 606 new ChangeEventsCommand(m_model.untyped, tr("Re-Label Point"));
580 command->remove(text); 607 command->remove(text);
581 command->add(text.withLabel(label)); 608 command->add(text.withLabel(label));
582 finish(command); 609 finish(command);
583 } 610 }
584 611
586 } 613 }
587 614
588 void 615 void
589 TextLayer::moveSelection(Selection s, sv_frame_t newStartFrame) 616 TextLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
590 { 617 {
591 if (!m_model) return; 618 auto model = ModelById::getAs<TextModel>(m_model);
619 if (!model) return;
592 620
593 ChangeEventsCommand *command = 621 ChangeEventsCommand *command =
594 new ChangeEventsCommand(m_model, tr("Drag Selection")); 622 new ChangeEventsCommand(m_model.untyped, tr("Drag Selection"));
595 623
596 EventVector points = 624 EventVector points =
597 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); 625 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
598 626
599 for (Event p: points) { 627 for (Event p: points) {
600 command->remove(p); 628 command->remove(p);
601 Event moved = p.withFrame(p.getFrame() + 629 Event moved = p.withFrame(p.getFrame() +
602 newStartFrame - s.getStartFrame()); 630 newStartFrame - s.getStartFrame());
607 } 635 }
608 636
609 void 637 void
610 TextLayer::resizeSelection(Selection s, Selection newSize) 638 TextLayer::resizeSelection(Selection s, Selection newSize)
611 { 639 {
612 if (!m_model) return; 640 auto model = ModelById::getAs<TextModel>(m_model);
641 if (!model) return;
613 642
614 ChangeEventsCommand *command = 643 ChangeEventsCommand *command =
615 new ChangeEventsCommand(m_model, tr("Resize Selection")); 644 new ChangeEventsCommand(m_model.untyped, tr("Resize Selection"));
616 645
617 EventVector points = 646 EventVector points =
618 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); 647 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
619 648
620 double ratio = double(newSize.getDuration()) / double(s.getDuration()); 649 double ratio = double(newSize.getDuration()) / double(s.getDuration());
621 double oldStart = double(s.getStartFrame()); 650 double oldStart = double(s.getStartFrame());
622 double newStart = double(newSize.getStartFrame()); 651 double newStart = double(newSize.getStartFrame());
623 652
635 } 664 }
636 665
637 void 666 void
638 TextLayer::deleteSelection(Selection s) 667 TextLayer::deleteSelection(Selection s)
639 { 668 {
640 if (!m_model) return; 669 auto model = ModelById::getAs<TextModel>(m_model);
670 if (!model) return;
641 671
642 ChangeEventsCommand *command = 672 ChangeEventsCommand *command =
643 new ChangeEventsCommand(m_model, tr("Delete Selection")); 673 new ChangeEventsCommand(m_model.untyped, tr("Delete Selection"));
644 674
645 EventVector points = 675 EventVector points =
646 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); 676 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
647 677
648 for (Event p: points) { 678 for (Event p: points) {
649 command->remove(p); 679 command->remove(p);
650 } 680 }
651 681
653 } 683 }
654 684
655 void 685 void
656 TextLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) 686 TextLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
657 { 687 {
658 if (!m_model) return; 688 auto model = ModelById::getAs<TextModel>(m_model);
689 if (!model) return;
659 690
660 EventVector points = 691 EventVector points =
661 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration()); 692 model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
662 693
663 for (Event p: points) { 694 for (Event p: points) {
664 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame()))); 695 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame())));
665 } 696 }
666 } 697 }
667 698
668 bool 699 bool
669 TextLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) 700 TextLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */)
670 { 701 {
671 if (!m_model) return false; 702 auto model = ModelById::getAs<TextModel>(m_model);
703 if (!model) return false;
672 704
673 const EventVector &points = from.getPoints(); 705 const EventVector &points = from.getPoints();
674 706
675 bool realign = false; 707 bool realign = false;
676 708
690 realign = true; 722 realign = true;
691 } 723 }
692 } 724 }
693 725
694 ChangeEventsCommand *command = 726 ChangeEventsCommand *command =
695 new ChangeEventsCommand(m_model, tr("Paste")); 727 new ChangeEventsCommand(m_model.untyped, tr("Paste"));
696 728
697 double valueMin = 0.0, valueMax = 1.0; 729 double valueMin = 0.0, valueMax = 1.0;
698 for (EventVector::const_iterator i = points.begin(); 730 for (EventVector::const_iterator i = points.begin();
699 i != points.end(); ++i) { 731 i != points.end(); ++i) {
700 if (i->hasValue()) { 732 if (i->hasValue()) {