comparison layer/RegionLayer.cpp @ 1428:c9fa16e41664 single-point

Update RegionLayer to updated RegionModel
author Chris Cannam
date Fri, 15 Mar 2019 14:24:22 +0000
parents 62e908518c71
children 8a7c82282fbc
comparison
equal deleted inserted replaced
1427:f792a5001d80 1428:c9fa16e41664
259 m_distributionMap.clear(); 259 m_distributionMap.clear();
260 if (!m_model) return; 260 if (!m_model) return;
261 261
262 // SVDEBUG << "RegionLayer::recalcSpacing" << endl; 262 // SVDEBUG << "RegionLayer::recalcSpacing" << endl;
263 263
264 for (RegionModel::PointList::const_iterator i = m_model->getPoints().begin(); 264 EventVector allEvents = m_model->getAllEvents();
265 i != m_model->getPoints().end(); ++i) { 265 for (const Event &e: allEvents) {
266 m_distributionMap[i->value]++; 266 m_distributionMap[e.getValue()]++;
267 // SVDEBUG << "RegionLayer::recalcSpacing: value found: " << i->value << " (now have " << m_distributionMap[i->value] << " of this value)" << endl; 267 // SVDEBUG << "RegionLayer::recalcSpacing: value found: " << e.getValue() << " (now have " << m_distributionMap[e.getValue()] << " of this value)" << endl;
268 } 268 }
269 269
270 int n = 0; 270 int n = 0;
271 271
272 for (SpacingMap::const_iterator i = m_distributionMap.begin(); 272 for (SpacingMap::const_iterator i = m_distributionMap.begin();
301 max = m_model->getValueMaximum(); 301 max = m_model->getValueMaximum();
302 302
303 return true; 303 return true;
304 } 304 }
305 305
306 RegionModel::PointList 306 EventVector
307 RegionLayer::getLocalPoints(LayerGeometryProvider *v, int x) const 307 RegionLayer::getLocalPoints(LayerGeometryProvider *v, int x) const
308 { 308 {
309 if (!m_model) return RegionModel::PointList(); 309 if (!m_model) return EventVector();
310 310
311 sv_frame_t frame = v->getFrameForX(x); 311 sv_frame_t frame = v->getFrameForX(x);
312 312
313 RegionModel::PointList onPoints = 313 EventVector local = m_model->getEventsCovering(frame);
314 m_model->getPoints(frame); 314 if (!local.empty()) return local;
315 315
316 if (!onPoints.empty()) { 316 int fuzz = ViewManager::scalePixelSize(2);
317 return onPoints; 317 sv_frame_t start = v->getFrameForX(x - fuzz);
318 } 318 sv_frame_t end = v->getFrameForX(x + fuzz);
319 319
320 RegionModel::PointList prevPoints = 320 local = m_model->getEventsStartingWithin(frame, end - frame);
321 m_model->getPreviousPoints(frame); 321 if (!local.empty()) return local;
322 RegionModel::PointList nextPoints = 322
323 m_model->getNextPoints(frame); 323 local = m_model->getEventsSpanning(start, frame - start);
324 324 if (!local.empty()) return local;
325 RegionModel::PointList usePoints = prevPoints; 325
326 326 return {};
327 if (prevPoints.empty()) {
328 usePoints = nextPoints;
329 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
330 !(nextPoints.begin()->frame > v->getEndFrame())) {
331 usePoints = nextPoints;
332 } else if (long(nextPoints.begin()->frame) - frame <
333 frame - long(prevPoints.begin()->frame)) {
334 usePoints = nextPoints;
335 }
336
337 if (!usePoints.empty()) {
338 int fuzz = ViewManager::scalePixelSize(2);
339 int px = v->getXForFrame(usePoints.begin()->frame);
340 if ((px > x && px - x > fuzz) ||
341 (px < x && x - px > fuzz + 1)) {
342 usePoints.clear();
343 }
344 }
345
346 return usePoints;
347 } 327 }
348 328
349 bool 329 bool
350 RegionLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, RegionModel::Point &p) const 330 RegionLayer::getPointToDrag(LayerGeometryProvider *v, int x, int y, Event &point) const
351 { 331 {
352 if (!m_model) return false; 332 if (!m_model) return false;
353 333
354 sv_frame_t frame = v->getFrameForX(x); 334 sv_frame_t frame = v->getFrameForX(x);
355 335
356 RegionModel::PointList onPoints = m_model->getPoints(frame); 336 EventVector onPoints = m_model->getEventsCovering(frame);
357 if (onPoints.empty()) return false; 337 if (onPoints.empty()) return false;
358 338
359 int nearestDistance = -1; 339 int nearestDistance = -1;
360 340 for (const auto &p: onPoints) {
361 for (RegionModel::PointList::const_iterator i = onPoints.begin(); 341 int distance = getYForValue(v, p.getValue()) - y;
362 i != onPoints.end(); ++i) {
363
364 int distance = getYForValue(v, (*i).value) - y;
365 if (distance < 0) distance = -distance; 342 if (distance < 0) distance = -distance;
366 if (nearestDistance == -1 || distance < nearestDistance) { 343 if (nearestDistance == -1 || distance < nearestDistance) {
367 nearestDistance = distance; 344 nearestDistance = distance;
368 p = *i; 345 point = p;
369 } 346 }
370 } 347 }
371 348
372 return true; 349 return true;
373 } 350 }
374 351
375 QString 352 QString
376 RegionLayer::getLabelPreceding(sv_frame_t frame) const 353 RegionLayer::getLabelPreceding(sv_frame_t frame) const
377 { 354 {
378 if (!m_model) return ""; 355 if (!m_model) return "";
379 RegionModel::PointList points = m_model->getPreviousPoints(frame); 356 EventVector points = m_model->getEventsStartingWithin
380 for (RegionModel::PointList::const_iterator i = points.begin(); 357 (m_model->getStartFrame(), frame - m_model->getStartFrame());
381 i != points.end(); ++i) { 358 if (!points.empty()) {
382 if (i->label != "") return i->label; 359 for (auto i = points.rbegin(); i != points.rend(); ++i) {
383 } 360 if (i->getLabel() != QString()) {
384 return ""; 361 return i->getLabel();
362 }
363 }
364 }
365 return QString();
385 } 366 }
386 367
387 QString 368 QString
388 RegionLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const 369 RegionLayer::getFeatureDescription(LayerGeometryProvider *v, QPoint &pos) const
389 { 370 {
390 int x = pos.x(); 371 int x = pos.x();
391 372
392 if (!m_model || !m_model->getSampleRate()) return ""; 373 if (!m_model || !m_model->getSampleRate()) return "";
393 374
394 RegionModel::PointList points = getLocalPoints(v, x); 375 EventVector points = getLocalPoints(v, x);
395 376
396 if (points.empty()) { 377 if (points.empty()) {
397 if (!m_model->isReady()) { 378 if (!m_model->isReady()) {
398 return tr("In progress"); 379 return tr("In progress");
399 } else { 380 } else {
400 return tr("No local points"); 381 return tr("No local points");
401 } 382 }
402 } 383 }
403 384
404 RegionRec region(0); 385 Event region;
405 RegionModel::PointList::iterator i; 386 EventVector::iterator i;
406 387
407 //!!! harmonise with whatever decision is made about point y 388 //!!! harmonise with whatever decision is made about point y
408 //!!! coords in paint method 389 //!!! coords in paint method
409 390
410 for (i = points.begin(); i != points.end(); ++i) { 391 for (i = points.begin(); i != points.end(); ++i) {
411 392
412 int y = getYForValue(v, i->value); 393 int y = getYForValue(v, i->getValue());
413 int h = 3; 394 int h = 3;
414 395
415 if (m_model->getValueQuantization() != 0.0) { 396 if (m_model->getValueQuantization() != 0.0) {
416 h = y - getYForValue(v, i->value + m_model->getValueQuantization()); 397 h = y - getYForValue
398 (v, i->getValue() + m_model->getValueQuantization());
417 if (h < 3) h = 3; 399 if (h < 3) h = 3;
418 } 400 }
419 401
420 if (pos.y() >= y - h && pos.y() <= y) { 402 if (pos.y() >= y - h && pos.y() <= y) {
421 region = *i; 403 region = *i;
423 } 405 }
424 } 406 }
425 407
426 if (i == points.end()) return tr("No local points"); 408 if (i == points.end()) return tr("No local points");
427 409
428 RealTime rt = RealTime::frame2RealTime(region.frame, 410 RealTime rt = RealTime::frame2RealTime(region.getFrame(),
429 m_model->getSampleRate()); 411 m_model->getSampleRate());
430 RealTime rd = RealTime::frame2RealTime(region.duration, 412 RealTime rd = RealTime::frame2RealTime(region.getDuration(),
431 m_model->getSampleRate()); 413 m_model->getSampleRate());
432 414
433 QString valueText; 415 QString valueText;
434 416
435 valueText = tr("%1 %2").arg(region.value).arg(getScaleUnits()); 417 valueText = tr("%1 %2").arg(region.getValue()).arg(getScaleUnits());
436 418
437 QString text; 419 QString text;
438 420
439 if (region.label == "") { 421 if (region.getLabel() == "") {
440 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label")) 422 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nNo label"))
441 .arg(rt.toText(true).c_str()) 423 .arg(rt.toText(true).c_str())
442 .arg(valueText) 424 .arg(valueText)
443 .arg(rd.toText(true).c_str()); 425 .arg(rd.toText(true).c_str());
444 } else { 426 } else {
445 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4")) 427 text = QString(tr("Time:\t%1\nValue:\t%2\nDuration:\t%3\nLabel:\t%4"))
446 .arg(rt.toText(true).c_str()) 428 .arg(rt.toText(true).c_str())
447 .arg(valueText) 429 .arg(valueText)
448 .arg(rd.toText(true).c_str()) 430 .arg(rd.toText(true).c_str())
449 .arg(region.label); 431 .arg(region.getLabel());
450 } 432 }
451 433
452 pos = QPoint(v->getXForFrame(region.frame), 434 pos = QPoint(v->getXForFrame(region.getFrame()),
453 getYForValue(v, region.value)); 435 getYForValue(v, region.getValue()));
454 return text; 436 return text;
455 } 437 }
456 438
457 bool 439 bool
458 RegionLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame, 440 RegionLayer::snapToFeatureFrame(LayerGeometryProvider *v, sv_frame_t &frame,
462 if (!m_model) { 444 if (!m_model) {
463 return Layer::snapToFeatureFrame(v, frame, resolution, snap); 445 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
464 } 446 }
465 447
466 resolution = m_model->getResolution(); 448 resolution = m_model->getResolution();
467 RegionModel::PointList points; 449 EventVector points;
468 450
469 if (snap == SnapNeighbouring) { 451 if (snap == SnapNeighbouring) {
470 452
471 points = getLocalPoints(v, v->getXForFrame(frame)); 453 points = getLocalPoints(v, v->getXForFrame(frame));
472 if (points.empty()) return false; 454 if (points.empty()) return false;
473 frame = points.begin()->frame; 455 frame = points.begin()->getFrame();
474 return true; 456 return true;
475 } 457 }
476 458
477 points = m_model->getPoints(frame, frame); 459 //!!! I think this is not quite right - we want to be able to snap
460 //!!! to events that are nearby but not covering the given frame,
461 //!!! and I think that worked with the old code. Compare and
462 //!!! revise.
463
464 points = m_model->getEventsCovering(frame);
478 sv_frame_t snapped = frame; 465 sv_frame_t snapped = frame;
479 bool found = false; 466 bool found = false;
480 467
481 for (RegionModel::PointList::const_iterator i = points.begin(); 468 for (EventVector::const_iterator i = points.begin();
482 i != points.end(); ++i) { 469 i != points.end(); ++i) {
483 470
484 if (snap == SnapRight) { 471 if (snap == SnapRight) {
485 472
486 // The best frame to snap to is the end frame of whichever 473 // The best frame to snap to is the end frame of whichever
487 // feature we would have snapped to the start frame of if 474 // feature we would have snapped to the start frame of if
488 // we had been snapping left. 475 // we had been snapping left.
489 476
490 if (i->frame <= frame) { 477 if (i->getFrame() <= frame) {
491 if (i->frame + i->duration > frame) { 478 if (i->getFrame() + i->getDuration() > frame) {
492 snapped = i->frame + i->duration; 479 snapped = i->getFrame() + i->getDuration();
493 found = true; // don't break, as the next may be better 480 found = true; // don't break, as the next may be better
494 } 481 }
495 } else { 482 } else {
496 if (!found) { 483 if (!found) {
497 snapped = i->frame; 484 snapped = i->getFrame();
498 found = true; 485 found = true;
499 } 486 }
500 break; 487 break;
501 } 488 }
502 489
503 } else if (snap == SnapLeft) { 490 } else if (snap == SnapLeft) {
504 491
505 if (i->frame <= frame) { 492 if (i->getFrame() <= frame) {
506 snapped = i->frame; 493 snapped = i->getFrame();
507 found = true; // don't break, as the next may be better 494 found = true; // don't break, as the next may be better
508 } else { 495 } else {
509 break; 496 break;
510 } 497 }
511 498
512 } else { // nearest 499 } else { // nearest
513 500
514 RegionModel::PointList::const_iterator j = i; 501 EventVector::const_iterator j = i;
515 ++j; 502 ++j;
516 503
517 if (j == points.end()) { 504 if (j == points.end()) {
518 505
519 snapped = i->frame; 506 snapped = i->getFrame();
520 found = true; 507 found = true;
521 break; 508 break;
522 509
523 } else if (j->frame >= frame) { 510 } else if (j->getFrame() >= frame) {
524 511
525 if (j->frame - frame < frame - i->frame) { 512 if (j->getFrame() - frame < frame - i->getFrame()) {
526 snapped = j->frame; 513 snapped = j->getFrame();
527 } else { 514 } else {
528 snapped = i->frame; 515 snapped = i->getFrame();
529 } 516 }
530 found = true; 517 found = true;
531 break; 518 break;
532 } 519 }
533 } 520 }
546 return Layer::snapToSimilarFeature(v, frame, resolution, snap); 533 return Layer::snapToSimilarFeature(v, frame, resolution, snap);
547 } 534 }
548 535
549 resolution = m_model->getResolution(); 536 resolution = m_model->getResolution();
550 537
551 const RegionModel::PointList &points = m_model->getPoints(); 538 /*!!! todo: overhaul the logic of this function (and supporting
552 RegionModel::PointList close = m_model->getPoints(frame, frame); 539 apis in EventSeries / RegionModel)
553 540
554 RegionModel::PointList::const_iterator i; 541 const EventVector &points = m_model->getPoints();
542 EventVector close = m_model->getPoints(frame, frame);
543 */
544 EventVector points = m_model->getAllEvents();
545 EventVector close = {};
546
547 EventVector::const_iterator i;
555 548
556 sv_frame_t matchframe = frame; 549 sv_frame_t matchframe = frame;
557 double matchvalue = 0.f; 550 double matchvalue = 0.f;
558 551
559 for (i = close.begin(); i != close.end(); ++i) { 552 for (i = close.begin(); i != close.end(); ++i) {
560 if (i->frame > frame) break; 553 if (i->getFrame() > frame) break;
561 matchvalue = i->value; 554 matchvalue = i->getValue();
562 matchframe = i->frame; 555 matchframe = i->getFrame();
563 } 556 }
564 557
565 sv_frame_t snapped = frame; 558 sv_frame_t snapped = frame;
566 bool found = false; 559 bool found = false;
567 bool distant = false; 560 bool distant = false;
587 } 580 }
588 } 581 }
589 582
590 if (snap == SnapRight) { 583 if (snap == SnapRight) {
591 584
592 if (i->frame > matchframe && 585 if (i->getFrame() > matchframe &&
593 fabs(i->value - matchvalue) < epsilon) { 586 fabs(i->getValue() - matchvalue) < epsilon) {
594 snapped = i->frame; 587 snapped = i->getFrame();
595 found = true; 588 found = true;
596 break; 589 break;
597 } 590 }
598 591
599 } else if (snap == SnapLeft) { 592 } else if (snap == SnapLeft) {
600 593
601 if (i->frame < matchframe) { 594 if (i->getFrame() < matchframe) {
602 if (fabs(i->value - matchvalue) < epsilon) { 595 if (fabs(i->getValue() - matchvalue) < epsilon) {
603 snapped = i->frame; 596 snapped = i->getFrame();
604 found = true; // don't break, as the next may be better 597 found = true; // don't break, as the next may be better
605 } 598 }
606 } else if (found || distant) { 599 } else if (found || distant) {
607 break; 600 break;
608 } 601 }
880 int x0 = rect.left() - 40, x1 = rect.right(); 873 int x0 = rect.left() - 40, x1 = rect.right();
881 874
882 sv_frame_t wholeFrame0 = v->getFrameForX(0); 875 sv_frame_t wholeFrame0 = v->getFrameForX(0);
883 sv_frame_t wholeFrame1 = v->getFrameForX(v->getPaintWidth()); 876 sv_frame_t wholeFrame1 = v->getFrameForX(v->getPaintWidth());
884 877
885 RegionModel::PointList points(m_model->getPoints(wholeFrame0, wholeFrame1)); 878 EventVector points(m_model->getEventsSpanning(wholeFrame0,
879 wholeFrame1 - wholeFrame0));
886 if (points.empty()) return; 880 if (points.empty()) return;
887 881
888 paint.setPen(getBaseQColor()); 882 paint.setPen(getBaseQColor());
889 883
890 QColor brushColour(getBaseQColor()); 884 QColor brushColour(getBaseQColor());
896 double min = m_model->getValueMinimum(); 890 double min = m_model->getValueMinimum();
897 double max = m_model->getValueMaximum(); 891 double max = m_model->getValueMaximum();
898 if (max == min) max = min + 1.0; 892 if (max == min) max = min + 1.0;
899 893
900 QPoint localPos; 894 QPoint localPos;
901 RegionModel::Point illuminatePoint(0); 895 Event illuminatePoint(0);
902 bool shouldIlluminate = false; 896 bool shouldIlluminate = false;
903 897
904 if (v->shouldIlluminateLocalFeatures(this, localPos)) { 898 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
905 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(), 899 shouldIlluminate = getPointToDrag(v, localPos.x(), localPos.y(),
906 illuminatePoint); 900 illuminatePoint);
915 //!!! if it does have distinct values, we should still ensure y 909 //!!! if it does have distinct values, we should still ensure y
916 //!!! coord is never completely flat on the top or bottom 910 //!!! coord is never completely flat on the top or bottom
917 911
918 int fontHeight = paint.fontMetrics().height(); 912 int fontHeight = paint.fontMetrics().height();
919 913
920 for (RegionModel::PointList::const_iterator i = points.begin(); 914 for (EventVector::const_iterator i = points.begin();
921 i != points.end(); ++i) { 915 i != points.end(); ++i) {
922 916
923 const RegionModel::Point &p(*i); 917 const Event &p(*i);
924 918
925 int x = v->getXForFrame(p.frame); 919 int x = v->getXForFrame(p.getFrame());
926 int w = v->getXForFrame(p.frame + p.duration) - x; 920 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
927 int y = getYForValue(v, p.value); 921 int y = getYForValue(v, p.getValue());
928 int h = 9; 922 int h = 9;
929 int ex = x + w; 923 int ex = x + w;
930 924
931 int gap = v->scalePixelSize(2); 925 int gap = v->scalePixelSize(2);
932 926
933 RegionModel::PointList::const_iterator j = i; 927 EventVector::const_iterator j = i;
934 ++j; 928 ++j;
935 929
936 if (j != points.end()) { 930 if (j != points.end()) {
937 const RegionModel::Point &q(*j); 931 const Event &q(*j);
938 int nx = v->getXForFrame(q.frame); 932 int nx = v->getXForFrame(q.getFrame());
939 if (nx < ex) ex = nx; 933 if (nx < ex) ex = nx;
940 } 934 }
941 935
942 if (m_model->getValueQuantization() != 0.0) { 936 if (m_model->getValueQuantization() != 0.0) {
943 h = y - getYForValue(v, p.value + m_model->getValueQuantization()); 937 h = y - getYForValue
938 (v, p.getValue() + m_model->getValueQuantization());
944 if (h < 3) h = 3; 939 if (h < 3) h = 3;
945 } 940 }
946 941
947 if (w < 1) w = 1; 942 if (w < 1) w = 1;
948 943
949 if (m_plotStyle == PlotSegmentation) { 944 if (m_plotStyle == PlotSegmentation) {
950 paint.setPen(getForegroundQColor(v->getView())); 945 paint.setPen(getForegroundQColor(v->getView()));
951 paint.setBrush(getColourForValue(v, p.value)); 946 paint.setBrush(getColourForValue(v, p.getValue()));
952 } else { 947 } else {
953 paint.setPen(getBaseQColor()); 948 paint.setPen(getBaseQColor());
954 paint.setBrush(brushColour); 949 paint.setBrush(brushColour);
955 } 950 }
956 951
957 if (m_plotStyle == PlotSegmentation) { 952 if (m_plotStyle == PlotSegmentation) {
958 953
959 if (ex <= x) continue; 954 if (ex <= x) continue;
960 955
961 if (!shouldIlluminate || 956 if (!shouldIlluminate || illuminatePoint != p) {
962 // "illuminatePoint != p"
963 RegionModel::Point::Comparator()(illuminatePoint, p) ||
964 RegionModel::Point::Comparator()(p, illuminatePoint)) {
965 957
966 paint.setPen(QPen(getForegroundQColor(v->getView()), 1)); 958 paint.setPen(QPen(getForegroundQColor(v->getView()), 1));
967 paint.drawLine(x, 0, x, v->getPaintHeight()); 959 paint.drawLine(x, 0, x, v->getPaintHeight());
968 paint.setPen(Qt::NoPen); 960 paint.setPen(Qt::NoPen);
969 961
973 965
974 paint.drawRect(x, -1, ex - x, v->getPaintHeight() + gap); 966 paint.drawRect(x, -1, ex - x, v->getPaintHeight() + gap);
975 967
976 } else { 968 } else {
977 969
978 if (shouldIlluminate && 970 if (shouldIlluminate && illuminatePoint == p) {
979 // "illuminatePoint == p"
980 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
981 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
982 971
983 paint.setPen(v->getForeground()); 972 paint.setPen(v->getForeground());
984 paint.setBrush(v->getForeground()); 973 paint.setBrush(v->getForeground());
985 974
986 QString vlabel = QString("%1%2").arg(p.value).arg(getScaleUnits()); 975 QString vlabel =
976 QString("%1%2").arg(p.getValue()).arg(getScaleUnits());
987 PaintAssistant::drawVisibleText(v, paint, 977 PaintAssistant::drawVisibleText(v, paint,
988 x - paint.fontMetrics().width(vlabel) - gap, 978 x - paint.fontMetrics().width(vlabel) - gap,
989 y + paint.fontMetrics().height()/2 979 y + paint.fontMetrics().height()/2
990 - paint.fontMetrics().descent(), 980 - paint.fontMetrics().descent(),
991 vlabel, PaintAssistant::OutlinedText); 981 vlabel, PaintAssistant::OutlinedText);
992 982
993 QString hlabel = RealTime::frame2RealTime 983 QString hlabel = RealTime::frame2RealTime
994 (p.frame, m_model->getSampleRate()).toText(true).c_str(); 984 (p.getFrame(), m_model->getSampleRate()).toText(true).c_str();
995 PaintAssistant::drawVisibleText(v, paint, 985 PaintAssistant::drawVisibleText(v, paint,
996 x, 986 x,
997 y - h/2 - paint.fontMetrics().descent() - gap, 987 y - h/2 - paint.fontMetrics().descent() - gap,
998 hlabel, PaintAssistant::OutlinedText); 988 hlabel, PaintAssistant::OutlinedText);
999 } 989 }
1006 } 996 }
1007 997
1008 int nextLabelMinX = -100; 998 int nextLabelMinX = -100;
1009 int lastLabelY = 0; 999 int lastLabelY = 0;
1010 1000
1011 for (RegionModel::PointList::const_iterator i = points.begin(); 1001 for (EventVector::const_iterator i = points.begin();
1012 i != points.end(); ++i) { 1002 i != points.end(); ++i) {
1013 1003
1014 const RegionModel::Point &p(*i); 1004 const Event &p(*i);
1015 1005
1016 int x = v->getXForFrame(p.frame); 1006 int x = v->getXForFrame(p.getFrame());
1017 int w = v->getXForFrame(p.frame + p.duration) - x; 1007 int w = v->getXForFrame(p.getFrame() + p.getDuration()) - x;
1018 int y = getYForValue(v, p.value); 1008 int y = getYForValue(v, p.getValue());
1019 1009
1020 QString label = p.label; 1010 QString label = p.getLabel();
1021 if (label == "") { 1011 if (label == "") {
1022 label = QString("%1%2").arg(p.value).arg(getScaleUnits()); 1012 label = QString("%1%2").arg(p.getValue()).arg(getScaleUnits());
1023 } 1013 }
1024 int labelWidth = paint.fontMetrics().width(label); 1014 int labelWidth = paint.fontMetrics().width(label);
1025 1015
1026 int gap = v->scalePixelSize(2); 1016 int gap = v->scalePixelSize(2);
1027 1017
1036 } 1026 }
1037 1027
1038 bool illuminated = false; 1028 bool illuminated = false;
1039 1029
1040 if (m_plotStyle != PlotSegmentation) { 1030 if (m_plotStyle != PlotSegmentation) {
1041 1031 if (shouldIlluminate && illuminatePoint == p) {
1042 if (shouldIlluminate &&
1043 // "illuminatePoint == p"
1044 !RegionModel::Point::Comparator()(illuminatePoint, p) &&
1045 !RegionModel::Point::Comparator()(p, illuminatePoint)) {
1046
1047 illuminated = true; 1032 illuminated = true;
1048 } 1033 }
1049 } 1034 }
1050 1035
1051 if (!illuminated) { 1036 if (!illuminated) {
1099 } 1084 }
1100 1085
1101 void 1086 void
1102 RegionLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const 1087 RegionLayer::paintVerticalScale(LayerGeometryProvider *v, bool, QPainter &paint, QRect) const
1103 { 1088 {
1104 if (!m_model || m_model->getPoints().empty()) return; 1089 if (!m_model || m_model->isEmpty()) return;
1105 1090
1106 QString unit; 1091 QString unit;
1107 double min, max; 1092 double min, max;
1108 bool logarithmic; 1093 bool logarithmic;
1109 1094
1150 if (frame < 0) frame = 0; 1135 if (frame < 0) frame = 0;
1151 frame = frame / m_model->getResolution() * m_model->getResolution(); 1136 frame = frame / m_model->getResolution() * m_model->getResolution();
1152 1137
1153 double value = getValueForY(v, e->y()); 1138 double value = getValueForY(v, e->y());
1154 1139
1155 m_editingPoint = RegionModel::Point(frame, float(value), 0, ""); 1140 m_editingPoint = Event(frame, float(value), 0, "");
1156 m_originalPoint = m_editingPoint; 1141 m_originalPoint = m_editingPoint;
1157 1142
1158 if (m_editingCommand) finish(m_editingCommand); 1143 if (m_editingCommand) finish(m_editingCommand);
1159 m_editingCommand = new RegionModel::EditCommand(m_model, 1144 m_editingCommand = new ChangeEventsCommand(m_model,
1160 tr("Draw Region")); 1145 tr("Draw Region"));
1161 m_editingCommand->addPoint(m_editingPoint); 1146 m_editingCommand->add(m_editingPoint);
1162 1147
1163 recalcSpacing(); 1148 recalcSpacing();
1164 1149
1165 m_editing = true; 1150 m_editing = true;
1166 } 1151 }
1172 1157
1173 sv_frame_t frame = v->getFrameForX(e->x()); 1158 sv_frame_t frame = v->getFrameForX(e->x());
1174 if (frame < 0) frame = 0; 1159 if (frame < 0) frame = 0;
1175 frame = frame / m_model->getResolution() * m_model->getResolution(); 1160 frame = frame / m_model->getResolution() * m_model->getResolution();
1176 1161
1177 double newValue = m_editingPoint.value; 1162 double newValue = m_editingPoint.getValue();
1178 if (m_verticalScale != EqualSpaced) newValue = getValueForY(v, e->y()); 1163 if (m_verticalScale != EqualSpaced) newValue = getValueForY(v, e->y());
1179 1164
1180 sv_frame_t newFrame = m_editingPoint.frame; 1165 sv_frame_t newFrame = m_editingPoint.getFrame();
1181 sv_frame_t newDuration = frame - newFrame; 1166 sv_frame_t newDuration = frame - newFrame;
1182 if (newDuration < 0) { 1167 if (newDuration < 0) {
1183 newFrame = frame; 1168 newFrame = frame;
1184 newDuration = -newDuration; 1169 newDuration = -newDuration;
1185 } else if (newDuration == 0) { 1170 } else if (newDuration == 0) {
1186 newDuration = 1; 1171 newDuration = 1;
1187 } 1172 }
1188 1173
1189 m_editingCommand->deletePoint(m_editingPoint); 1174 m_editingCommand->remove(m_editingPoint);
1190 m_editingPoint.frame = newFrame; 1175 m_editingPoint = m_editingPoint
1191 m_editingPoint.value = float(newValue); 1176 .withFrame(newFrame)
1192 m_editingPoint.duration = newDuration; 1177 .withValue(float(newValue))
1193 m_editingCommand->addPoint(m_editingPoint); 1178 .withDuration(newDuration);
1179 m_editingCommand->add(m_editingPoint);
1194 1180
1195 recalcSpacing(); 1181 recalcSpacing();
1196 } 1182 }
1197 1183
1198 void 1184 void
1232 { 1218 {
1233 if (!m_model || !m_editing) return; 1219 if (!m_model || !m_editing) return;
1234 1220
1235 m_editing = false; 1221 m_editing = false;
1236 1222
1237 RegionModel::Point p(0); 1223 Event p(0);
1238 if (!getPointToDrag(v, e->x(), e->y(), p)) return; 1224 if (!getPointToDrag(v, e->x(), e->y(), p)) return;
1239 if (p.frame != m_editingPoint.frame || p.value != m_editingPoint.value) return; 1225 if (p.getFrame() != m_editingPoint.getFrame() ||
1240 1226 p.getValue() != m_editingPoint.getValue()) return;
1241 m_editingCommand = new RegionModel::EditCommand 1227
1228 m_editingCommand = new ChangeEventsCommand
1242 (m_model, tr("Erase Region")); 1229 (m_model, tr("Erase Region"));
1243 1230
1244 m_editingCommand->deletePoint(m_editingPoint); 1231 m_editingCommand->remove(m_editingPoint);
1245 1232
1246 finish(m_editingCommand); 1233 finish(m_editingCommand);
1247 m_editingCommand = nullptr; 1234 m_editingCommand = nullptr;
1248 m_editing = false; 1235 m_editing = false;
1249 recalcSpacing(); 1236 recalcSpacing();
1256 1243
1257 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) { 1244 if (!getPointToDrag(v, e->x(), e->y(), m_editingPoint)) {
1258 return; 1245 return;
1259 } 1246 }
1260 1247
1261 m_dragPointX = v->getXForFrame(m_editingPoint.frame); 1248 m_dragPointX = v->getXForFrame(m_editingPoint.getFrame());
1262 m_dragPointY = getYForValue(v, m_editingPoint.value); 1249 m_dragPointY = getYForValue(v, m_editingPoint.getValue());
1263 1250
1264 m_originalPoint = m_editingPoint; 1251 m_originalPoint = m_editingPoint;
1265 1252
1266 if (m_editingCommand) { 1253 if (m_editingCommand) {
1267 finish(m_editingCommand); 1254 finish(m_editingCommand);
1288 if (frame < 0) frame = 0; 1275 if (frame < 0) frame = 0;
1289 frame = frame / m_model->getResolution() * m_model->getResolution(); 1276 frame = frame / m_model->getResolution() * m_model->getResolution();
1290 1277
1291 // Do not bisect between two values, if one of those values is 1278 // Do not bisect between two values, if one of those values is
1292 // that of the point we're actually moving ... 1279 // that of the point we're actually moving ...
1293 int avoid = m_spacingMap[m_editingPoint.value]; 1280 int avoid = m_spacingMap[m_editingPoint.getValue()];
1294 1281
1295 // ... unless there are other points with the same value 1282 // ... unless there are other points with the same value
1296 if (m_distributionMap[m_editingPoint.value] > 1) avoid = -1; 1283 if (m_distributionMap[m_editingPoint.getValue()] > 1) avoid = -1;
1297 1284
1298 double value = getValueForY(v, newy, avoid); 1285 double value = getValueForY(v, newy, avoid);
1299 1286
1300 if (!m_editingCommand) { 1287 if (!m_editingCommand) {
1301 m_editingCommand = new RegionModel::EditCommand(m_model, 1288 m_editingCommand = new ChangeEventsCommand(m_model,
1302 tr("Drag Region")); 1289 tr("Drag Region"));
1303 } 1290 }
1304 1291
1305 m_editingCommand->deletePoint(m_editingPoint); 1292 m_editingCommand->remove(m_editingPoint);
1306 m_editingPoint.frame = frame; 1293 m_editingPoint = m_editingPoint
1307 m_editingPoint.value = float(value); 1294 .withFrame(frame)
1308 m_editingCommand->addPoint(m_editingPoint); 1295 .withValue(float(value));
1296 m_editingCommand->add(m_editingPoint);
1309 recalcSpacing(); 1297 recalcSpacing();
1310 } 1298 }
1311 1299
1312 void 1300 void
1313 RegionLayer::editEnd(LayerGeometryProvider *, QMouseEvent *) 1301 RegionLayer::editEnd(LayerGeometryProvider *, QMouseEvent *)
1316 1304
1317 if (m_editingCommand) { 1305 if (m_editingCommand) {
1318 1306
1319 QString newName = m_editingCommand->getName(); 1307 QString newName = m_editingCommand->getName();
1320 1308
1321 if (m_editingPoint.frame != m_originalPoint.frame) { 1309 if (m_editingPoint.getFrame() != m_originalPoint.getFrame()) {
1322 if (m_editingPoint.value != m_originalPoint.value) { 1310 if (m_editingPoint.getValue() != m_originalPoint.getValue()) {
1323 newName = tr("Edit Region"); 1311 newName = tr("Edit Region");
1324 } else { 1312 } else {
1325 newName = tr("Relocate Region"); 1313 newName = tr("Relocate Region");
1326 } 1314 }
1327 } else { 1315 } else {
1340 bool 1328 bool
1341 RegionLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e) 1329 RegionLayer::editOpen(LayerGeometryProvider *v, QMouseEvent *e)
1342 { 1330 {
1343 if (!m_model) return false; 1331 if (!m_model) return false;
1344 1332
1345 RegionModel::Point region(0); 1333 Event region(0);
1346 if (!getPointToDrag(v, e->x(), e->y(), region)) return false; 1334 if (!getPointToDrag(v, e->x(), e->y(), region)) return false;
1347 1335
1348 ItemEditDialog *dialog = new ItemEditDialog 1336 ItemEditDialog *dialog = new ItemEditDialog
1349 (m_model->getSampleRate(), 1337 (m_model->getSampleRate(),
1350 ItemEditDialog::ShowTime | 1338 ItemEditDialog::ShowTime |
1351 ItemEditDialog::ShowDuration | 1339 ItemEditDialog::ShowDuration |
1352 ItemEditDialog::ShowValue | 1340 ItemEditDialog::ShowValue |
1353 ItemEditDialog::ShowText, 1341 ItemEditDialog::ShowText,
1354 getScaleUnits()); 1342 getScaleUnits());
1355 1343
1356 dialog->setFrameTime(region.frame); 1344 dialog->setFrameTime(region.getFrame());
1357 dialog->setValue(region.value); 1345 dialog->setValue(region.getValue());
1358 dialog->setFrameDuration(region.duration); 1346 dialog->setFrameDuration(region.getDuration());
1359 dialog->setText(region.label); 1347 dialog->setText(region.getLabel());
1360 1348
1361 if (dialog->exec() == QDialog::Accepted) { 1349 if (dialog->exec() == QDialog::Accepted) {
1362 1350
1363 RegionModel::Point newRegion = region; 1351 Event newRegion = region
1364 newRegion.frame = dialog->getFrameTime(); 1352 .withFrame(dialog->getFrameTime())
1365 newRegion.value = dialog->getValue(); 1353 .withValue(dialog->getValue())
1366 newRegion.duration = dialog->getFrameDuration(); 1354 .withDuration(dialog->getFrameDuration())
1367 newRegion.label = dialog->getText(); 1355 .withLabel(dialog->getText());
1368 1356
1369 RegionModel::EditCommand *command = new RegionModel::EditCommand 1357 ChangeEventsCommand *command = new ChangeEventsCommand
1370 (m_model, tr("Edit Region")); 1358 (m_model, tr("Edit Region"));
1371 command->deletePoint(region); 1359 command->remove(region);
1372 command->addPoint(newRegion); 1360 command->add(newRegion);
1373 finish(command); 1361 finish(command);
1374 } 1362 }
1375 1363
1376 delete dialog; 1364 delete dialog;
1377 recalcSpacing(); 1365 recalcSpacing();
1381 void 1369 void
1382 RegionLayer::moveSelection(Selection s, sv_frame_t newStartFrame) 1370 RegionLayer::moveSelection(Selection s, sv_frame_t newStartFrame)
1383 { 1371 {
1384 if (!m_model) return; 1372 if (!m_model) return;
1385 1373
1386 RegionModel::EditCommand *command = 1374 ChangeEventsCommand *command =
1387 new RegionModel::EditCommand(m_model, tr("Drag Selection")); 1375 new ChangeEventsCommand(m_model, tr("Drag Selection"));
1388 1376
1389 RegionModel::PointList points = 1377 EventVector points =
1390 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 1378 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
1391 1379
1392 for (RegionModel::PointList::iterator i = points.begin(); 1380 for (EventVector::iterator i = points.begin();
1393 i != points.end(); ++i) { 1381 i != points.end(); ++i) {
1394 1382
1395 if (s.contains(i->frame)) { 1383 if (s.contains(i->getFrame())) {
1396 RegionModel::Point newPoint(*i); 1384 Event newPoint = (*i)
1397 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); 1385 .withFrame(i->getFrame() + newStartFrame - s.getStartFrame());
1398 command->deletePoint(*i); 1386 command->remove(*i);
1399 command->addPoint(newPoint); 1387 command->add(newPoint);
1400 } 1388 }
1401 } 1389 }
1402 1390
1403 finish(command); 1391 finish(command);
1404 recalcSpacing(); 1392 recalcSpacing();
1405 } 1393 }
1406 1394
1407 void 1395 void
1408 RegionLayer::resizeSelection(Selection s, Selection newSize) 1396 RegionLayer::resizeSelection(Selection s, Selection newSize)
1409 { 1397 {
1410 if (!m_model) return; 1398 if (!m_model || !s.getDuration()) return;
1411 1399
1412 RegionModel::EditCommand *command = 1400 ChangeEventsCommand *command =
1413 new RegionModel::EditCommand(m_model, tr("Resize Selection")); 1401 new ChangeEventsCommand(m_model, tr("Resize Selection"));
1414 1402
1415 RegionModel::PointList points = 1403 EventVector points =
1416 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 1404 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
1417 1405
1418 double ratio = 1406 double ratio = double(newSize.getDuration()) / double(s.getDuration());
1419 double(newSize.getEndFrame() - newSize.getStartFrame()) / 1407 double oldStart = double(s.getStartFrame());
1420 double(s.getEndFrame() - s.getStartFrame()); 1408 double newStart = double(newSize.getStartFrame());
1421 1409
1422 for (RegionModel::PointList::iterator i = points.begin(); 1410 for (Event p: points) {
1423 i != points.end(); ++i) { 1411
1424 1412 double newFrame = (double(p.getFrame()) - oldStart) * ratio + newStart;
1425 if (s.contains(i->frame)) { 1413 double newDuration = double(p.getDuration()) * ratio;
1426 1414
1427 double targetStart = double(i->frame); 1415 Event newPoint = p
1428 targetStart = double(newSize.getStartFrame()) + 1416 .withFrame(lrint(newFrame))
1429 targetStart - double(s.getStartFrame()) * ratio; 1417 .withDuration(lrint(newDuration));
1430 1418 command->remove(p);
1431 double targetEnd = double(i->frame + i->duration); 1419 command->add(newPoint);
1432 targetEnd = double(newSize.getStartFrame()) +
1433 targetEnd - double(s.getStartFrame()) * ratio;
1434
1435 RegionModel::Point newPoint(*i);
1436 newPoint.frame = lrint(targetStart);
1437 newPoint.duration = lrint(targetEnd - targetStart);
1438 command->deletePoint(*i);
1439 command->addPoint(newPoint);
1440 }
1441 } 1420 }
1442 1421
1443 finish(command); 1422 finish(command);
1444 recalcSpacing(); 1423 recalcSpacing();
1445 } 1424 }
1447 void 1426 void
1448 RegionLayer::deleteSelection(Selection s) 1427 RegionLayer::deleteSelection(Selection s)
1449 { 1428 {
1450 if (!m_model) return; 1429 if (!m_model) return;
1451 1430
1452 RegionModel::EditCommand *command = 1431 ChangeEventsCommand *command =
1453 new RegionModel::EditCommand(m_model, tr("Delete Selected Points")); 1432 new ChangeEventsCommand(m_model, tr("Delete Selected Points"));
1454 1433
1455 RegionModel::PointList points = 1434 EventVector points =
1456 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 1435 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
1457 1436
1458 for (RegionModel::PointList::iterator i = points.begin(); 1437 for (EventVector::iterator i = points.begin();
1459 i != points.end(); ++i) { 1438 i != points.end(); ++i) {
1460 1439
1461 if (s.contains(i->frame)) { 1440 if (s.contains(i->getFrame())) {
1462 command->deletePoint(*i); 1441 command->remove(*i);
1463 } 1442 }
1464 } 1443 }
1465 1444
1466 finish(command); 1445 finish(command);
1467 recalcSpacing(); 1446 recalcSpacing();
1470 void 1449 void
1471 RegionLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to) 1450 RegionLayer::copy(LayerGeometryProvider *v, Selection s, Clipboard &to)
1472 { 1451 {
1473 if (!m_model) return; 1452 if (!m_model) return;
1474 1453
1475 RegionModel::PointList points = 1454 EventVector points =
1476 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); 1455 m_model->getEventsStartingWithin(s.getStartFrame(), s.getDuration());
1477 1456
1478 for (RegionModel::PointList::iterator i = points.begin(); 1457 for (Event p: points) {
1479 i != points.end(); ++i) { 1458 to.addPoint(p.withReferenceFrame(alignToReference(v, p.getFrame())));
1480 if (s.contains(i->frame)) {
1481 Event point(i->frame, i->value, i->duration, i->label);
1482 to.addPoint(point.withReferenceFrame(alignToReference(v, i->frame)));
1483 }
1484 } 1459 }
1485 } 1460 }
1486 1461
1487 bool 1462 bool
1488 RegionLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */) 1463 RegionLayer::paste(LayerGeometryProvider *v, const Clipboard &from, sv_frame_t /* frameOffset */, bool /* interactive */)
1508 if (button == QMessageBox::Yes) { 1483 if (button == QMessageBox::Yes) {
1509 realign = true; 1484 realign = true;
1510 } 1485 }
1511 } 1486 }
1512 1487
1513 RegionModel::EditCommand *command = 1488 ChangeEventsCommand *command =
1514 new RegionModel::EditCommand(m_model, tr("Paste")); 1489 new ChangeEventsCommand(m_model, tr("Paste"));
1515 1490
1516 for (EventVector::const_iterator i = points.begin(); 1491 for (EventVector::const_iterator i = points.begin();
1517 i != points.end(); ++i) { 1492 i != points.end(); ++i) {
1518 1493
1519 sv_frame_t frame = 0; 1494 sv_frame_t frame = 0;
1530 } else { 1505 } else {
1531 frame = i->getFrame(); 1506 frame = i->getFrame();
1532 } 1507 }
1533 } 1508 }
1534 1509
1535 RegionModel::Point newPoint(frame); 1510 Event p = *i;
1536 1511 Event newPoint = p;
1537 if (i->hasLabel()) newPoint.label = i->getLabel(); 1512 if (!p.hasValue()) {
1538 if (i->hasValue()) newPoint.value = i->getValue(); 1513 newPoint = newPoint.withValue((m_model->getValueMinimum() +
1539 else newPoint.value = (m_model->getValueMinimum() + 1514 m_model->getValueMaximum()) / 2);
1540 m_model->getValueMaximum()) / 2; 1515 }
1541 if (i->hasDuration()) newPoint.duration = i->getDuration(); 1516 if (!p.hasDuration()) {
1542 else {
1543 sv_frame_t nextFrame = frame; 1517 sv_frame_t nextFrame = frame;
1544 EventVector::const_iterator j = i; 1518 EventVector::const_iterator j = i;
1545 for (; j != points.end(); ++j) { 1519 for (; j != points.end(); ++j) {
1546 if (j != i) break; 1520 if (j != i) break;
1547 } 1521 }
1548 if (j != points.end()) { 1522 if (j != points.end()) {
1549 nextFrame = j->getFrame(); 1523 nextFrame = j->getFrame();
1550 } 1524 }
1551 if (nextFrame == frame) { 1525 if (nextFrame == frame) {
1552 newPoint.duration = m_model->getResolution(); 1526 newPoint = newPoint.withDuration(m_model->getResolution());
1553 } else { 1527 } else {
1554 newPoint.duration = nextFrame - frame; 1528 newPoint = newPoint.withDuration(nextFrame - frame);
1555 } 1529 }
1556 } 1530 }
1557 1531
1558 command->addPoint(newPoint); 1532 command->add(newPoint);
1559 } 1533 }
1560 1534
1561 finish(command); 1535 finish(command);
1562 recalcSpacing(); 1536 recalcSpacing();
1563 return true; 1537 return true;