comparison layer/TimeInstantLayer.cpp @ 1433:9abddbd57667 single-point

Updates for SparseOneDimensionalModel in new API
author Chris Cannam
date Thu, 21 Mar 2019 13:34:08 +0000
parents 62e908518c71
children e561f0a8d75b
comparison
equal deleted inserted replaced
1432:5b9692768beb 1433:9abddbd57667
153 { 153 {
154 QPoint discard; 154 QPoint discard;
155 return !v->shouldIlluminateLocalFeatures(this, discard); 155 return !v->shouldIlluminateLocalFeatures(this, discard);
156 } 156 }
157 157
158 SparseOneDimensionalModel::PointList 158 EventVector
159 TimeInstantLayer::getLocalPoints(LayerGeometryProvider *v, int x) const 159 TimeInstantLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
160 { 160 {
161 if (!m_model) return {};
162
161 // Return a set of points that all have the same frame number, the 163 // Return a set of points that all have the same frame number, the
162 // nearest to the given x coordinate, and that are within a 164 // nearest to the given x coordinate, and that are within a
163 // certain fuzz distance of that x coordinate. 165 // certain fuzz distance of that x coordinate.
164 166
165 if (!m_model) return SparseOneDimensionalModel::PointList();
166
167 sv_frame_t frame = v->getFrameForX(x); 167 sv_frame_t frame = v->getFrameForX(x);
168 168
169 SparseOneDimensionalModel::PointList onPoints = 169 EventVector exact = m_model->getEventsStartingAt(frame);
170 m_model->getPoints(frame); 170 if (!exact.empty()) return exact;
171 171
172 if (!onPoints.empty()) { 172 // overspill == 1, so one event either side of the given span
173 return onPoints; 173 EventVector neighbouring = m_model->getEventsWithin
174 } 174 (frame, m_model->getResolution(), 1);
175 175
176 SparseOneDimensionalModel::PointList prevPoints = 176 double fuzz = v->scaleSize(2);
177 m_model->getPreviousPoints(frame); 177 sv_frame_t suitable = 0;
178 SparseOneDimensionalModel::PointList nextPoints = 178 bool have = false;
179 m_model->getNextPoints(frame); 179
180 180 for (Event e: neighbouring) {
181 SparseOneDimensionalModel::PointList usePoints = prevPoints; 181 sv_frame_t f = e.getFrame();
182 182 if (f < v->getStartFrame() || f > v->getEndFrame()) {
183 if (prevPoints.empty()) { 183 continue;
184 usePoints = nextPoints; 184 }
185 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() && 185 int px = v->getXForFrame(f);
186 !(nextPoints.begin()->frame > v->getEndFrame())) { 186 if ((px > x && px - x > fuzz) || (px < x && x - px > fuzz + 3)) {
187 usePoints = nextPoints; 187 continue;
188 } else if (nextPoints.begin()->frame - frame < 188 }
189 frame - prevPoints.begin()->frame) { 189 if (!have) {
190 usePoints = nextPoints; 190 suitable = f;
191 } 191 have = true;
192 192 } else if (llabs(frame - f) < llabs(suitable - f)) {
193 if (!usePoints.empty()) { 193 suitable = f;
194 int fuzz = ViewManager::scalePixelSize(2); 194 }
195 int px = v->getXForFrame(usePoints.begin()->frame); 195 }
196 if ((px > x && px - x > fuzz) || 196
197 (px < x && x - px > fuzz + 1)) { 197 if (have) {
198 usePoints.clear(); 198 return m_model->getEventsStartingAt(suitable);
199 } 199 } else {
200 } 200 return {};
201 201 }
202 return usePoints;
203 } 202 }
204 203
205 QString 204 QString
206 TimeInstantLayer::getLabelPreceding(sv_frame_t frame) const 205 TimeInstantLayer::getLabelPreceding(sv_frame_t frame) const
207 { 206 {
208 if (!m_model) return ""; 207 if (!m_model || !m_model->hasTextLabels()) return "";
209 SparseOneDimensionalModel::PointList points = m_model->getPreviousPoints(frame); 208
210 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 209 Event e;
211 i != points.end(); ++i) { 210 if (m_model->getNearestEventMatching
212 if (i->label != "") return i->label; 211 (frame,
213 } 212 [](Event e) { return e.hasLabel() && e.getLabel() != ""; },
213 EventSeries::Backward,
214 e)) {
215 return e.getLabel();
216 }
217
214 return ""; 218 return "";
215 } 219 }
216 220
217 QString 221 QString
218 TimeInstantLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const 222 TimeInstantLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
219 { 223 {
220 int x = pos.x(); 224 int x = pos.x();
221 225
222 if (!m_model || !m_model->getSampleRate()) return ""; 226 if (!m_model || !m_model->getSampleRate()) return "";
223 227
224 SparseOneDimensionalModel::PointList points = getLocalPoints(v, x); 228 EventVector points = getLocalPoints(v, x);
225 229
226 if (points.empty()) { 230 if (points.empty()) {
227 if (!m_model->isReady()) { 231 if (!m_model->isReady()) {
228 return tr("In progress"); 232 return tr("In progress");
229 } else { 233 } else {
230 return tr("No local points"); 234 return tr("No local points");
231 } 235 }
232 } 236 }
233 237
234 sv_frame_t useFrame = points.begin()->frame; 238 sv_frame_t useFrame = points.begin()->getFrame();
235 239
236 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); 240 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
237 241
238 QString text; 242 QString text;
239 243
240 if (points.begin()->label == "") { 244 if (points.begin()->getLabel() == "") {
241 text = QString(tr("Time:\t%1\nNo label")) 245 text = QString(tr("Time:\t%1\nNo label"))
242 .arg(rt.toText(true).c_str()); 246 .arg(rt.toText(true).c_str());
243 } else { 247 } else {
244 text = QString(tr("Time:\t%1\nLabel:\t%2")) 248 text = QString(tr("Time:\t%1\nLabel:\t%2"))
245 .arg(rt.toText(true).c_str()) 249 .arg(rt.toText(true).c_str())
246 .arg(points.begin()->label); 250 .arg(points.begin()->getLabel());
247 } 251 }
248 252
249 pos = QPoint(v->getXForFrame(useFrame), pos.y()); 253 pos = QPoint(v->getXForFrame(useFrame), pos.y());
250 return text; 254 return text;
251 } 255 }
257 { 261 {
258 if (!m_model) { 262 if (!m_model) {
259 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 263 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
260 } 264 }
261 265
266 // SnapLeft / SnapRight: return frame of nearest feature in that
267 // direction no matter how far away
268 //
269 // SnapNeighbouring: return frame of feature that would be used in
270 // an editing operation, i.e. closest feature in either direction
271 // but only if it is "close enough"
272
262 resolution = m_model->getResolution(); 273 resolution = m_model->getResolution();
263 SparseOneDimensionalModel::PointList points;
264 274
265 if (snap == SnapNeighbouring) { 275 if (snap == SnapNeighbouring) {
266 276 EventVector points = getLocalPoints(v, v->getXForFrame(frame));
267 points = getLocalPoints(v, v->getXForFrame(frame));
268 if (points.empty()) return false; 277 if (points.empty()) return false;
269 frame = points.begin()->frame; 278 frame = points.begin()->getFrame();
270 return true; 279 return true;
271 } 280 }
272 281
273 points = m_model->getPoints(frame, frame); 282 Event e;
274 sv_frame_t snapped = frame; 283 if (m_model->getNearestEventMatching
275 bool found = false; 284 (frame,
276 285 [](Event) { return true; },
277 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 286 snap == SnapLeft ? EventSeries::Backward : EventSeries::Forward,
278 i != points.end(); ++i) { 287 e)) {
279 288 frame = e.getFrame();
280 if (snap == SnapRight) { 289 return true;
281 290 }
282 if (i->frame >= frame) { 291
283 snapped = i->frame; 292 return false;
284 found = true;
285 break;
286 }
287
288 } else if (snap == SnapLeft) {
289
290 if (i->frame <= frame) {
291 snapped = i->frame;
292 found = true; // don't break, as the next may be better
293 } else {
294 break;
295 }
296
297 } else { // nearest
298
299 SparseOneDimensionalModel::PointList::const_iterator j = i;
300 ++j;
301
302 if (j == points.end()) {
303
304 snapped = i->frame;
305 found = true;
306 break;
307
308 } else if (j->frame >= frame) {
309
310 if (j->frame - frame < frame - i->frame) {
311 snapped = j->frame;
312 } else {
313 snapped = i->frame;
314 }
315 found = true;
316 break;
317 }
318 }
319 }
320
321 frame = snapped;
322 return found;
323 } 293 }
324 294
325 void 295 void
326 TimeInstantLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const 296 TimeInstantLayer::paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const
327 { 297 {
332 int x0 = rect.left(), x1 = rect.right(); 302 int x0 = rect.left(), x1 = rect.right();
333 303
334 sv_frame_t frame0 = v->getFrameForX(x0); 304 sv_frame_t frame0 = v->getFrameForX(x0);
335 sv_frame_t frame1 = v->getFrameForX(x1); 305 sv_frame_t frame1 = v->getFrameForX(x1);
336 306
337 SparseOneDimensionalModel::PointList points(m_model->getPoints 307 EventVector points(m_model->getEventsWithin(frame0, frame1 - frame0));
338 (frame0, frame1));
339 308
340 bool odd = false; 309 bool odd = false;
341 if (m_plotStyle == PlotSegmentation && !points.empty()) { 310 if (m_plotStyle == PlotSegmentation && !points.empty()) {
342 int index = m_model->getIndexOf(*points.begin()); 311 int index = m_model->getRowForFrame(points.begin()->getFrame());
343 odd = ((index % 2) == 1); 312 odd = ((index % 2) == 1);
344 } 313 }
345 314
346 paint.setPen(getBaseQColor()); 315 paint.setPen(getBaseQColor());
347 316
370 339
371 QPoint localPos; 340 QPoint localPos;
372 sv_frame_t illuminateFrame = -1; 341 sv_frame_t illuminateFrame = -1;
373 342
374 if (v->shouldIlluminateLocalFeatures(this, localPos)) { 343 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
375 SparseOneDimensionalModel::PointList localPoints = 344 EventVector localPoints = getLocalPoints(v, localPos.x());
376 getLocalPoints(v, localPos.x()); 345 if (!localPoints.empty()) {
377 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; 346 illuminateFrame = localPoints.begin()->getFrame();
347 }
378 } 348 }
379 349
380 int prevX = -1; 350 int prevX = -1;
381 int textY = v->getTextLabelHeight(this, paint); 351 int textY = v->getTextLabelHeight(this, paint);
382 352
383 for (SparseOneDimensionalModel::PointList::const_iterator i = points.begin(); 353 for (EventVector::const_iterator i = points.begin();
384 i != points.end(); ++i) { 354 i != points.end(); ++i) {
385 355
386 const SparseOneDimensionalModel::Point &p(*i); 356 Event p(*i);
387 SparseOneDimensionalModel::PointList::const_iterator j = i; 357 EventVector::const_iterator j = i;
388 ++j; 358 ++j;
389 359
390 int x = v->getXForFrame(p.frame); 360 int x = v->getXForFrame(p.getFrame());
391 if (x == prevX && m_plotStyle == PlotInstants && 361 if (x == prevX && m_plotStyle == PlotInstants &&
392 p.frame != illuminateFrame) continue; 362 p.getFrame() != illuminateFrame) continue;
393 363
394 int iw = v->getXForFrame(p.frame + m_model->getResolution()) - x; 364 int iw = v->getXForFrame(p.getFrame() + m_model->getResolution()) - x;
395 if (iw < 2) { 365 if (iw < 2) {
396 if (iw < 1) { 366 if (iw < 1) {
397 iw = 2; 367 iw = 2;
398 if (j != points.end()) { 368 if (j != points.end()) {
399 int nx = v->getXForFrame(j->frame); 369 int nx = v->getXForFrame(j->getFrame());
400 if (nx < x + 3) iw = 1; 370 if (nx < x + 3) iw = 1;
401 } 371 }
402 } else { 372 } else {
403 iw = 2; 373 iw = 2;
404 } 374 }
405 } 375 }
406 376
407 if (p.frame == illuminateFrame) { 377 if (p.getFrame() == illuminateFrame) {
408 paint.setPen(getForegroundQColor(v->getView())); 378 paint.setPen(getForegroundQColor(v->getView()));
409 } else { 379 } else {
410 paint.setPen(brushColour); 380 paint.setPen(brushColour);
411 } 381 }
412 382
422 else paint.setBrush(brushColour); 392 else paint.setBrush(brushColour);
423 393
424 int nx; 394 int nx;
425 395
426 if (j != points.end()) { 396 if (j != points.end()) {
427 const SparseOneDimensionalModel::Point &q(*j); 397 Event q(*j);
428 nx = v->getXForFrame(q.frame); 398 nx = v->getXForFrame(q.getFrame());
429 } else { 399 } else {
430 nx = v->getXForFrame(m_model->getEndFrame()); 400 nx = v->getXForFrame(m_model->getEndFrame());
431 } 401 }
432 402
433 if (nx >= x) { 403 if (nx >= x) {
434 404
435 if (illuminateFrame != p.frame && 405 if (illuminateFrame != p.getFrame() &&
436 (nx < x + 5 || x >= v->getPaintWidth() - 1)) { 406 (nx < x + 5 || x >= v->getPaintWidth() - 1)) {
437 paint.setPen(Qt::NoPen); 407 paint.setPen(Qt::NoPen);
438 } 408 }
439 409
440 paint.drawRect(x, -1, nx - x, v->getPaintHeight() + 1); 410 paint.drawRect(x, -1, nx - x, v->getPaintHeight() + 1);
443 odd = !odd; 413 odd = !odd;
444 } 414 }
445 415
446 paint.setPen(getBaseQColor()); 416 paint.setPen(getBaseQColor());
447 417
448 if (p.label != "") { 418 if (p.getLabel() != "") {
449 419
450 // only draw if there's enough room from here to the next point 420 // only draw if there's enough room from here to the next point
451 421
452 int lw = paint.fontMetrics().width(p.label); 422 int lw = paint.fontMetrics().width(p.getLabel());
453 bool good = true; 423 bool good = true;
454 424
455 if (j != points.end()) { 425 if (j != points.end()) {
456 int nx = v->getXForFrame(j->frame); 426 int nx = v->getXForFrame(j->getFrame());
457 if (nx >= x && nx - x - iw - 3 <= lw) good = false; 427 if (nx >= x && nx - x - iw - 3 <= lw) good = false;
458 } 428 }
459 429
460 if (good) { 430 if (good) {
461 PaintAssistant::drawVisibleText(v, paint, 431 PaintAssistant::drawVisibleText(v, paint,
462 x + iw + 2, textY, 432 x + iw + 2, textY,
463 p.label, 433 p.getLabel(),
464 PaintAssistant::OutlinedText); 434 PaintAssistant::OutlinedText);
465 } 435 }
466 } 436 }
467 437
468 prevX = x; 438 prevX = x;
480 450
481 sv_frame_t frame = v->getFrameForX(e->x()); 451 sv_frame_t frame = v->getFrameForX(e->x());
482 if (frame < 0) frame = 0; 452 if (frame < 0) frame = 0;
483 frame = frame / m_model->getResolution() * m_model->getResolution(); 453 frame = frame / m_model->getResolution() * m_model->getResolution();
484 454
485 m_editingPoint = SparseOneDimensionalModel::Point(frame, tr("New Point")); 455 m_editingPoint = Event(frame, tr("New Point"));
486 456
487 if (m_editingCommand) finish(m_editingCommand); 457 if (m_editingCommand) finish(m_editingCommand);
488 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, 458 m_editingCommand = new ChangeEventsCommand(m_model, tr("Draw Point"));
489 tr("Draw Point")); 459 m_editingCommand->add(m_editingPoint);
490 m_editingCommand->addPoint(m_editingPoint);
491 460
492 m_editing = true; 461 m_editing = true;
493 } 462 }
494 463
495 void 464 void
502 if (!m_model || !m_editing) return; 471 if (!m_model || !m_editing) return;
503 472
504 sv_frame_t frame = v->getFrameForX(e->x()); 473 sv_frame_t frame = v->getFrameForX(e->x());
505 if (frame < 0) frame = 0; 474 if (frame < 0) frame = 0;
506 frame = frame / m_model->getResolution() * m_model->getResolution(); 475 frame = frame / m_model->getResolution() * m_model->getResolution();
507 m_editingCommand->deletePoint(m_editingPoint); 476 m_editingCommand->remove(m_editingPoint);
508 m_editingPoint.frame = frame; 477 m_editingPoint = m_editingPoint.withFrame(frame);
509 m_editingCommand->addPoint(m_editingPoint); 478 m_editingCommand->add(m_editingPoint);
510 } 479 }
511 480
512 void 481 void
513 TimeInstantLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *) 482 TimeInstantLayer::drawEnd(LayerGeometryProvider *, QMouseEvent *)
514 { 483 {
515 #ifdef DEBUG_TIME_INSTANT_LAYER 484 #ifdef DEBUG_TIME_INSTANT_LAYER
516 cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << endl; 485 cerr << "TimeInstantLayer::drawEnd(" << e->x() << ")" << endl;
517 #endif 486 #endif
518 if (!m_model || !m_editing) return; 487 if (!m_model || !m_editing) return;
519 QString newName = tr("Add Point at %1 s") 488 QString newName = tr("Add Point at %1 s")
520 .arg(RealTime::frame2RealTime(m_editingPoint.frame, 489 .arg(RealTime::frame2RealTime(m_editingPoint.getFrame(),
521 m_model->getSampleRate()) 490 m_model->getSampleRate())
522 .toText(false).c_str()); 491 .toText(false).c_str());
523 m_editingCommand->setName(newName); 492 m_editingCommand->setName(newName);
524 finish(m_editingCommand); 493 finish(m_editingCommand);
525 m_editingCommand = nullptr; 494 m_editingCommand = nullptr;
529 void 498 void
530 TimeInstantLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e) 499 TimeInstantLayer::eraseStart(LayerGeometryProvider *v, QMouseEvent *e)
531 { 500 {
532 if (!m_model) return; 501 if (!m_model) return;
533 502
534 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 503 EventVector points = getLocalPoints(v, e->x());
535 if (points.empty()) return; 504 if (points.empty()) return;
536 505
537 m_editingPoint = *points.begin(); 506 m_editingPoint = *points.begin();
538 507
539 if (m_editingCommand) { 508 if (m_editingCommand) {
554 { 523 {
555 if (!m_model || !m_editing) return; 524 if (!m_model || !m_editing) return;
556 525
557 m_editing = false; 526 m_editing = false;
558 527
559 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 528 EventVector points = getLocalPoints(v, e->x());
560 if (points.empty()) return; 529 if (points.empty()) return;
561 if (points.begin()->frame != m_editingPoint.frame) return; 530 if (points.begin()->getFrame() != m_editingPoint.getFrame()) return;
562 531
563 m_editingCommand = new SparseOneDimensionalModel::EditCommand 532 m_editingCommand = new ChangeEventsCommand(m_model, tr("Erase Point"));
564 (m_model, tr("Erase Point")); 533 m_editingCommand->remove(m_editingPoint);
565
566 m_editingCommand->deletePoint(m_editingPoint);
567
568 finish(m_editingCommand); 534 finish(m_editingCommand);
569 m_editingCommand = nullptr; 535 m_editingCommand = nullptr;
570 m_editing = false; 536 m_editing = false;
571 } 537 }
572 538
577 cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << endl; 543 cerr << "TimeInstantLayer::editStart(" << e->x() << ")" << endl;
578 #endif 544 #endif
579 545
580 if (!m_model) return; 546 if (!m_model) return;
581 547
582 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 548 EventVector points = getLocalPoints(v, e->x());
583 if (points.empty()) return; 549 if (points.empty()) return;
584 550
585 m_editingPoint = *points.begin(); 551 m_editingPoint = *points.begin();
586 552
587 if (m_editingCommand) { 553 if (m_editingCommand) {
604 sv_frame_t frame = v->getFrameForX(e->x()); 570 sv_frame_t frame = v->getFrameForX(e->x());
605 if (frame < 0) frame = 0; 571 if (frame < 0) frame = 0;
606 frame = frame / m_model->getResolution() * m_model->getResolution(); 572 frame = frame / m_model->getResolution() * m_model->getResolution();
607 573
608 if (!m_editingCommand) { 574 if (!m_editingCommand) {
609 m_editingCommand = new SparseOneDimensionalModel::EditCommand(m_model, 575 m_editingCommand = new ChangeEventsCommand(m_model, tr("Drag Point"));
610 tr("Drag Point")); 576 }
611 } 577
612 578 m_editingCommand->remove(m_editingPoint);
613 m_editingCommand->deletePoint(m_editingPoint); 579 m_editingPoint = m_editingPoint.withFrame(frame);
614 m_editingPoint.frame = frame; 580 m_editingCommand->add(m_editingPoint);
615 m_editingCommand->addPoint(m_editingPoint);
616 } 581 }
617 582
618 void 583 void
619 TimeInstantLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) 584 TimeInstantLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
620 { 585 {
622 cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << endl; 587 cerr << "TimeInstantLayer::editEnd(" << e->x() << ")" << endl;
623 #endif 588 #endif
624 if (!m_model || !m_editing) return; 589 if (!m_model || !m_editing) return;
625 if (m_editingCommand) { 590 if (m_editingCommand) {
626 QString newName = tr("Move Point to %1 s") 591 QString newName = tr("Move Point to %1 s")
627 .arg(RealTime::frame2RealTime(m_editingPoint.frame, 592 .arg(RealTime::frame2RealTime(m_editingPoint.getFrame(),
628 m_model->getSampleRate()) 593 m_model->getSampleRate())
629 .toText(false).c_str()); 594 .toText(false).c_str());
630 m_editingCommand->setName(newName); 595 m_editingCommand->setName(newName);
631 finish(m_editingCommand); 596 finish(m_editingCommand);
632 } 597 }
637 bool 602 bool
638 TimeInstantLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) 603 TimeInstantLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
639 { 604 {
640 if (!m_model) return false; 605 if (!m_model) return false;
641 606
642 SparseOneDimensionalModel::PointList points = getLocalPoints(v, e->x()); 607 EventVector points = getLocalPoints(v, e->x());
643 if (points.empty()) return false; 608 if (points.empty()) return false;
644 609
645 SparseOneDimensionalModel::Point point = *points.begin(); 610 Event point = *points.begin();
646 611
647 ItemEditDialog *dialog = new ItemEditDialog 612 ItemEditDialog *dialog = new ItemEditDialog
648 (m_model->getSampleRate(), 613 (m_model->getSampleRate(),
649 ItemEditDialog::ShowTime | 614 ItemEditDialog::ShowTime |
650 ItemEditDialog::ShowText); 615 ItemEditDialog::ShowText);
651 616
652 dialog->setFrameTime(point.frame); 617 dialog->setFrameTime(point.getFrame());
653 dialog->setText(point.label); 618 dialog->setText(point.getLabel());
654 619
655 if (dialog->exec() == QDialog::Accepted) { 620 if (dialog->exec() == QDialog::Accepted) {
656 621
657 SparseOneDimensionalModel::Point newPoint = point; 622 Event newPoint = point
658 newPoint.frame = dialog->getFrameTime(); 623 .withFrame(dialog->getFrameTime())
659 newPoint.label = dialog->getText(); 624 .withLabel(dialog->getText());
660 625
661 SparseOneDimensionalModel::EditCommand *command = 626 ChangeEventsCommand *command =
662 new SparseOneDimensionalModel::EditCommand(m_model, tr("Edit Point")); 627 new ChangeEventsCommand(m_model, tr("Edit Point"));
663 command->deletePoint(point); 628 command->remove(point);
664 command->addPoint(newPoint); 629 command->add(newPoint);
665 finish(command); 630 finish(command);
666 } 631 }
667 632
668 delete dialog; 633 delete dialog;
669 return true; 634 return true;
672 void 637 void
673 TimeInstantLayer::moveSelection(Selection s, sv_frame_t newStartFrame) 638 TimeInstantLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
674 { 639 {
675 if (!m_model) return; 640 if (!m_model) return;
676 641
677 SparseOneDimensionalModel::EditCommand *command = 642 ChangeEventsCommand *command =
678 new SparseOneDimensionalModel::EditCommand(m_model, 643 new ChangeEventsCommand(m_model, tr("Drag Selection"));
679 tr("Drag Selection")); 644
680 645 EventVector points =
681 SparseOneDimensionalModel::PointList points = 646 m_model->getEventsWithin(s.getStartFrame(), s.getDuration());
682 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 647
683 648 for (auto p: points) {
684 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 649 Event newPoint = p
685 i != points.end(); ++i) { 650 .withFrame(p.getFrame() + newStartFrame - s.getStartFrame());
686 651 command->remove(p);
687 if (s.contains(i->frame)) { 652 command->add(newPoint);
688 SparseOneDimensionalModel::Point newPoint(*i);
689 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
690 command->deletePoint(*i);
691 command->addPoint(newPoint);
692 }
693 } 653 }
694 654
695 finish(command); 655 finish(command);
696 } 656 }
697 657
698 void 658 void
699 TimeInstantLayer::resizeSelection(Selection s, Selection newSize) 659 TimeInstantLayer::resizeSelection(Selection s, Selection newSize)
700 { 660 {
701 if (!m_model) return; 661 if (!m_model) return;
702 662
703 SparseOneDimensionalModel::EditCommand *command = 663 ChangeEventsCommand *command =
704 new SparseOneDimensionalModel::EditCommand(m_model, 664 new ChangeEventsCommand(m_model, tr("Resize Selection"));
705 tr("Resize Selection")); 665
706 666 EventVector points =
707 SparseOneDimensionalModel::PointList points = 667 m_model->getEventsWithin(s.getStartFrame(), s.getDuration());
708 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 668
709 669 double ratio = double(newSize.getDuration()) / double(s.getDuration());
710 double ratio = 670 double oldStart = double(s.getStartFrame());
711 double(newSize.getEndFrame() - newSize.getStartFrame()) / 671 double newStart = double(newSize.getStartFrame());
712 double(s.getEndFrame() - s.getStartFrame()); 672
713 673 for (auto p: points) {
714 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 674
715 i != points.end(); ++i) { 675 double newFrame = (double(p.getFrame()) - oldStart) * ratio + newStart;
716 676
717 if (s.contains(i->frame)) { 677 Event newPoint = p
718 678 .withFrame(lrint(newFrame));
719 double target = double(i->frame); 679 command->remove(p);
720 target = double(newSize.getStartFrame()) + 680 command->add(newPoint);
721 target - double(s.getStartFrame()) * ratio;
722
723 SparseOneDimensionalModel::Point newPoint(*i);
724 newPoint.frame = lrint(target);
725 command->deletePoint(*i);
726 command->addPoint(newPoint);
727 }
728 } 681 }
729 682
730 finish(command); 683 finish(command);
731 } 684 }
732 685
733 void 686 void
734 TimeInstantLayer::deleteSelection(Selection s) 687 TimeInstantLayer::deleteSelection(Selection s)
735 { 688 {
736 if (!m_model) return; 689 if (!m_model) return;
737 690
738 SparseOneDimensionalModel::EditCommand *command = 691 ChangeEventsCommand *command =
739 new SparseOneDimensionalModel::EditCommand(m_model, 692 new ChangeEventsCommand(m_model, tr("Delete Selection"));
740 tr("Delete Selection")); 693
741 694 EventVector points =
742 SparseOneDimensionalModel::PointList points = 695 m_model->getEventsWithin(s.getStartFrame(), s.getDuration());
743 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 696
744 697 for (auto p: points) {
745 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 698 command->remove(p);
746 i != points.end(); ++i) {
747 if (s.contains(i->frame)) command->deletePoint(*i);
748 } 699 }
749 700
750 finish(command); 701 finish(command);
751 } 702 }
752 703
753 void 704 void
754 TimeInstantLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) 705 TimeInstantLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
755 { 706 {
756 if (!m_model) return; 707 if (!m_model) return;
757 708
758 SparseOneDimensionalModel::PointList points = 709 EventVector points =
759 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 710 m_model->getEventsWithin(s.getStartFrame(), s.getDuration());
760 711
761 for (SparseOneDimensionalModel::PointList::iterator i = points.begin(); 712 for (auto p: points) {
762 i != points.end(); ++i) { 713 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame())));
763 if (s.contains(i->frame)) {
764 Event point(i->frame, i->label);
765 to.addPoint(point.withReferenceFrame(alignToReference(v, i->frame)));
766 }
767 } 714 }
768 } 715 }
769 716
770 bool 717 bool
771 TimeInstantLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool) 718 TimeInstantLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t frameOffset, bool)
772 { 719 {
773 if (!m_model) return false; 720 if (!m_model) return false;
774 721
775 const EventVector &points = from.getPoints(); 722 EventVector points = from.getPoints();
776 723
777 bool realign = false; 724 bool realign = false;
778 725
779 if (clipboardHasDifferentAlignment(v, from)) { 726 if (clipboardHasDifferentAlignment(v, from)) {
780 727
791 if (button == QMessageBox::Yes) { 738 if (button == QMessageBox::Yes) {
792 realign = true; 739 realign = true;
793 } 740 }
794 } 741 }
795 742
796 SparseOneDimensionalModel::EditCommand *command = 743 ChangeEventsCommand *command =
797 new SparseOneDimensionalModel::EditCommand(m_model, tr("Paste")); 744 new ChangeEventsCommand(m_model, tr("Paste"));
798 745
799 for (EventVector::const_iterator i = points.begin(); 746 for (EventVector::const_iterator i = points.begin();
800 i != points.end(); ++i) { 747 i != points.end(); ++i) {
801 748
802 sv_frame_t frame = 0; 749 sv_frame_t frame = 0;
819 else if (frameOffset < 0) { 766 else if (frameOffset < 0) {
820 if (frame > -frameOffset) frame += frameOffset; 767 if (frame > -frameOffset) frame += frameOffset;
821 else frame = 0; 768 else frame = 0;
822 } 769 }
823 770
824 SparseOneDimensionalModel::Point newPoint(frame); 771 Event newPoint = *i;
825 if (i->hasLabel()) { 772 if (!i->hasLabel() && i->hasValue()) {
826 newPoint.label = i->getLabel(); 773 newPoint = newPoint.withLabel(QString("%1").arg(i->getValue()));
827 } else if (i->hasValue()) {
828 newPoint.label = QString("%1").arg(i->getValue());
829 } 774 }
830 775
831 command->addPoint(newPoint); 776 command->add(newPoint);
832 } 777 }
833 778
834 finish(command); 779 finish(command);
835 return true; 780 return true;
836 } 781 }