Mercurial > hg > svgui
comparison layer/TimeValueLayer.cpp @ 101:0f36cdf407a6 sv1-v0.9rc1
* Make vertical scale alignment modes work in note layer as well as time-value
layer, and several significant fixes to it
* Make it possible to draw notes properly on the note layer
* Show units (and frequencies etc in note layer's case) in the time-value and
note layer description boxes
* Minor fix to item edit dialog layout
* Some minor menu rearrangement
* Comment out a lot of debug output
* Add SV website and reference URLs to Help menu, and add code to (attempt to)
open them in the user's preferred browser
author | Chris Cannam |
---|---|
date | Fri, 12 May 2006 14:40:43 +0000 |
parents | 0db5e7492ce8 |
children | 999ae0f7d10c |
comparison
equal
deleted
inserted
replaced
100:0db5e7492ce8 | 101:0f36cdf407a6 |
---|---|
40 m_originalPoint(0, 0.0, tr("New Point")), | 40 m_originalPoint(0, 0.0, tr("New Point")), |
41 m_editingPoint(0, 0.0, tr("New Point")), | 41 m_editingPoint(0, 0.0, tr("New Point")), |
42 m_editingCommand(0), | 42 m_editingCommand(0), |
43 m_colour(Qt::darkGreen), | 43 m_colour(Qt::darkGreen), |
44 m_plotStyle(PlotConnectedPoints), | 44 m_plotStyle(PlotConnectedPoints), |
45 m_verticalScale(LinearScale) | 45 m_verticalScale(AutoAlignScale) |
46 { | 46 { |
47 | 47 |
48 } | 48 } |
49 | 49 |
50 void | 50 void |
58 this, SIGNAL(modelChanged(size_t, size_t))); | 58 this, SIGNAL(modelChanged(size_t, size_t))); |
59 | 59 |
60 connect(m_model, SIGNAL(completionChanged()), | 60 connect(m_model, SIGNAL(completionChanged()), |
61 this, SIGNAL(modelCompletionChanged())); | 61 this, SIGNAL(modelCompletionChanged())); |
62 | 62 |
63 std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl; | 63 // std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl; |
64 | 64 |
65 emit modelReplaced(); | 65 emit modelReplaced(); |
66 } | 66 } |
67 | 67 |
68 Layer::PropertyList | 68 Layer::PropertyList |
167 case 5: return tr("Segmentation"); | 167 case 5: return tr("Segmentation"); |
168 } | 168 } |
169 } else if (name == "Vertical Scale") { | 169 } else if (name == "Vertical Scale") { |
170 switch (value) { | 170 switch (value) { |
171 default: | 171 default: |
172 case 0: return tr("Linear Scale"); | 172 case 0: return tr("Auto-Align"); |
173 case 1: return tr("Log Scale"); | 173 case 1: return tr("Linear Scale"); |
174 case 2: return tr("+/-1 Scale"); | 174 case 2: return tr("Log Scale"); |
175 case 3: return tr("Frequency Scale"); | 175 case 3: return tr("+/-1 Scale"); |
176 } | 176 } |
177 } | 177 } |
178 return tr("<unknown>"); | 178 return tr("<unknown>"); |
179 } | 179 } |
180 | 180 |
240 QPoint discard; | 240 QPoint discard; |
241 return !v->shouldIlluminateLocalFeatures(this, discard); | 241 return !v->shouldIlluminateLocalFeatures(this, discard); |
242 } | 242 } |
243 | 243 |
244 bool | 244 bool |
245 TimeValueLayer::getValueExtents(float &min, float &max, QString &unit) const | 245 TimeValueLayer::getValueExtents(float &min, float &max, |
246 { | 246 bool &logarithmic, QString &unit) const |
247 { | |
248 if (!m_model) return false; | |
247 min = m_model->getValueMinimum(); | 249 min = m_model->getValueMinimum(); |
248 max = m_model->getValueMaximum(); | 250 max = m_model->getValueMaximum(); |
251 logarithmic = (m_verticalScale == LogScale); | |
249 unit = m_model->getScaleUnits(); | 252 unit = m_model->getScaleUnits(); |
253 return true; | |
254 } | |
255 | |
256 bool | |
257 TimeValueLayer::getDisplayExtents(float &min, float &max) const | |
258 { | |
259 if (!m_model || m_verticalScale == AutoAlignScale) return false; | |
260 | |
261 min = m_model->getValueMinimum(); | |
262 max = m_model->getValueMaximum(); | |
250 return true; | 263 return true; |
251 } | 264 } |
252 | 265 |
253 SparseTimeValueModel::PointList | 266 SparseTimeValueModel::PointList |
254 TimeValueLayer::getLocalPoints(View *v, int x) const | 267 TimeValueLayer::getLocalPoints(View *v, int x) const |
313 long useFrame = points.begin()->frame; | 326 long useFrame = points.begin()->frame; |
314 | 327 |
315 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | 328 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); |
316 | 329 |
317 QString text; | 330 QString text; |
331 QString unit = m_model->getScaleUnits(); | |
332 if (unit != "") unit = " " + unit; | |
318 | 333 |
319 if (points.begin()->label == "") { | 334 if (points.begin()->label == "") { |
320 text = QString(tr("Time:\t%1\nValue:\t%2\nNo label")) | 335 text = QString(tr("Time:\t%1\nValue:\t%2%3\nNo label")) |
321 .arg(rt.toText(true).c_str()) | |
322 .arg(points.begin()->value); | |
323 } else { | |
324 text = QString(tr("Time:\t%1\nValue:\t%2\nLabel:\t%3")) | |
325 .arg(rt.toText(true).c_str()) | 336 .arg(rt.toText(true).c_str()) |
326 .arg(points.begin()->value) | 337 .arg(points.begin()->value) |
338 .arg(unit); | |
339 } else { | |
340 text = QString(tr("Time:\t%1\nValue:\t%2%3\nLabel:\t%4")) | |
341 .arg(rt.toText(true).c_str()) | |
342 .arg(points.begin()->value) | |
343 .arg(unit) | |
327 .arg(points.begin()->label); | 344 .arg(points.begin()->label); |
328 } | 345 } |
329 | 346 |
330 pos = QPoint(v->getXForFrame(useFrame), | 347 pos = QPoint(v->getXForFrame(useFrame), |
331 getYForValue(v, points.begin()->value)); | 348 getYForValue(v, points.begin()->value)); |
402 | 419 |
403 frame = snapped; | 420 frame = snapped; |
404 return found; | 421 return found; |
405 } | 422 } |
406 | 423 |
424 void | |
425 TimeValueLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const | |
426 { | |
427 min = 0.0; | |
428 max = 0.0; | |
429 log = false; | |
430 | |
431 if (m_verticalScale == AutoAlignScale) { | |
432 | |
433 if (!v->getValueExtents(m_model->getScaleUnits(), min, max, log)) { | |
434 min = m_model->getValueMinimum(); | |
435 max = m_model->getValueMaximum(); | |
436 } else if (log) { | |
437 min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min); | |
438 max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max); | |
439 } | |
440 | |
441 } else if (m_verticalScale == PlusMinusOneScale) { | |
442 | |
443 min = -1.0; | |
444 max = 1.0; | |
445 | |
446 } else { | |
447 | |
448 min = m_model->getValueMinimum(); | |
449 max = m_model->getValueMaximum(); | |
450 | |
451 if (m_verticalScale == LogScale) { | |
452 min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min); | |
453 max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max); | |
454 log = true; | |
455 } | |
456 } | |
457 | |
458 if (max == min) max = min + 1.0; | |
459 } | |
460 | |
407 int | 461 int |
408 TimeValueLayer::getYForValue(View *v, float val) const | 462 TimeValueLayer::getYForValue(View *v, float val) const |
409 { | 463 { |
410 float min = 0.0, max = 0.0; | 464 float min = 0.0, max = 0.0; |
465 bool logarithmic = false; | |
411 int h = v->height(); | 466 int h = v->height(); |
412 | 467 |
413 if (!v->getValueExtents(m_model->getScaleUnits(), min, max)) { | 468 getScaleExtents(v, min, max, logarithmic); |
414 min = m_model->getValueMinimum(); | 469 |
415 max = m_model->getValueMaximum(); | 470 // std::cerr << "getYForValue(" << val << "): min " << min << ", max " |
416 } | 471 // << max << ", log " << logarithmic << std::endl; |
417 | 472 |
418 if (max == min) max = min + 1.0; | 473 if (logarithmic) { |
419 | |
420 /*!!! | |
421 float min = m_model->getValueMinimum(); | |
422 float max = m_model->getValueMaximum(); | |
423 if (max == min) max = min + 1.0; | |
424 | |
425 int h = v->height(); | |
426 | |
427 if (m_verticalScale == FrequencyScale || m_verticalScale == LogScale) { | |
428 | |
429 if (m_verticalScale == FrequencyScale) { | |
430 // If we have a spectrogram layer on the same view as us, align | |
431 // ourselves with it... | |
432 for (int i = 0; i < v->getLayerCount(); ++i) { | |
433 SpectrogramLayer *spectrogram = dynamic_cast<SpectrogramLayer *> | |
434 (v->getLayer(i)); | |
435 if (spectrogram) { | |
436 return spectrogram->getYForFrequency(v, val); | |
437 } | |
438 } | |
439 } | |
440 | |
441 min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min); | |
442 max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max); | |
443 val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val); | 474 val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val); |
444 | 475 } |
445 } else if (m_verticalScale == PlusMinusOneScale) { | |
446 min = -1.0; | |
447 max = 1.0; | |
448 } | |
449 */ | |
450 | 476 |
451 return int(h - ((val - min) * h) / (max - min)); | 477 return int(h - ((val - min) * h) / (max - min)); |
452 } | 478 } |
453 | 479 |
454 float | 480 float |
455 TimeValueLayer::getValueForY(View *v, int y) const | 481 TimeValueLayer::getValueForY(View *v, int y) const |
456 { | 482 { |
457 //!!! | 483 float min = 0.0, max = 0.0; |
458 | 484 bool logarithmic = false; |
459 float min = m_model->getValueMinimum(); | |
460 float max = m_model->getValueMaximum(); | |
461 if (max == min) max = min + 1.0; | |
462 | |
463 int h = v->height(); | 485 int h = v->height(); |
464 | 486 |
465 return min + (float(h - y) * float(max - min)) / h; | 487 getScaleExtents(v, min, max, logarithmic); |
488 | |
489 float val = min + (float(h - y) * float(max - min)) / h; | |
490 | |
491 if (logarithmic) { | |
492 val = pow(10, val); | |
493 } | |
494 | |
495 return val; | |
466 } | 496 } |
467 | 497 |
468 QColor | 498 QColor |
469 TimeValueLayer::getColourForValue(float val) const | 499 TimeValueLayer::getColourForValue(View *v, float val) const |
470 { | 500 { |
471 float min = m_model->getValueMinimum(); | 501 float min, max; |
472 float max = m_model->getValueMaximum(); | 502 bool log; |
473 if (max == min) max = min + 1.0; | 503 getScaleExtents(v, min, max, log); |
474 | 504 |
475 if (m_verticalScale == FrequencyScale || m_verticalScale == LogScale) { | 505 if (log) { |
476 min = (min < 0.0) ? -log10(-min) : (min == 0.0) ? 0.0 : log10(min); | |
477 max = (max < 0.0) ? -log10(-max) : (max == 0.0) ? 0.0 : log10(max); | |
478 val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val); | 506 val = (val < 0.0) ? -log10(-val) : (val == 0.0) ? 0.0 : log10(val); |
479 } else if (m_verticalScale == PlusMinusOneScale) { | |
480 min = -1.0; | |
481 max = 1.0; | |
482 } | 507 } |
483 | 508 |
484 int iv = ((val - min) / (max - min)) * 255.999; | 509 int iv = ((val - min) / (max - min)) * 255.999; |
485 | 510 |
486 QColor colour = QColor::fromHsv(256 - iv, iv / 2 + 128, iv); | 511 QColor colour = QColor::fromHsv(256 - iv, iv / 2 + 128, iv); |
579 | 604 |
580 if (w < 1) w = 1; | 605 if (w < 1) w = 1; |
581 paint.setPen(m_colour); | 606 paint.setPen(m_colour); |
582 | 607 |
583 if (m_plotStyle == PlotSegmentation) { | 608 if (m_plotStyle == PlotSegmentation) { |
584 paint.setBrush(getColourForValue(p.value)); | 609 paint.setBrush(getColourForValue(v, p.value)); |
585 labelY = v->height(); | 610 labelY = v->height(); |
586 } else if (m_plotStyle == PlotLines || | 611 } else if (m_plotStyle == PlotLines || |
587 m_plotStyle == PlotCurve) { | 612 m_plotStyle == PlotCurve) { |
588 paint.setBrush(Qt::NoBrush); | 613 paint.setBrush(Qt::NoBrush); |
589 } else { | 614 } else { |
742 | 767 |
743 if (m_plotStyle == PlotSegmentation) { | 768 if (m_plotStyle == PlotSegmentation) { |
744 paint.save(); | 769 paint.save(); |
745 for (int y = 0; y < boxh; ++y) { | 770 for (int y = 0; y < boxh; ++y) { |
746 float val = ((boxh - y) * (max - min)) / boxh + min; | 771 float val = ((boxh - y) * (max - min)) / boxh + min; |
747 paint.setPen(getColourForValue(val)); | 772 paint.setPen(getColourForValue(v, val)); |
748 paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1); | 773 paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1); |
749 } | 774 } |
750 paint.restore(); | 775 paint.restore(); |
751 } | 776 } |
752 | 777 |
787 } | 812 } |
788 | 813 |
789 void | 814 void |
790 TimeValueLayer::drawStart(View *v, QMouseEvent *e) | 815 TimeValueLayer::drawStart(View *v, QMouseEvent *e) |
791 { | 816 { |
792 std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; | 817 // std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; |
793 | 818 |
794 if (!m_model) return; | 819 if (!m_model) return; |
795 | 820 |
796 long frame = v->getFrameForX(e->x()); | 821 long frame = v->getFrameForX(e->x()); |
797 long resolution = m_model->getResolution(); | 822 long resolution = m_model->getResolution(); |
805 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); | 830 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); |
806 if (!points.empty()) { | 831 if (!points.empty()) { |
807 for (SparseTimeValueModel::PointList::iterator i = points.begin(); | 832 for (SparseTimeValueModel::PointList::iterator i = points.begin(); |
808 i != points.end(); ++i) { | 833 i != points.end(); ++i) { |
809 if (((i->frame / resolution) * resolution) != frame) { | 834 if (((i->frame / resolution) * resolution) != frame) { |
810 std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl; | 835 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl; |
811 continue; | 836 continue; |
812 } | 837 } |
813 m_editingPoint = *i; | 838 m_editingPoint = *i; |
814 havePoint = true; | 839 havePoint = true; |
815 } | 840 } |
833 } | 858 } |
834 | 859 |
835 void | 860 void |
836 TimeValueLayer::drawDrag(View *v, QMouseEvent *e) | 861 TimeValueLayer::drawDrag(View *v, QMouseEvent *e) |
837 { | 862 { |
838 std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; | 863 // std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; |
839 | 864 |
840 if (!m_model || !m_editing) return; | 865 if (!m_model || !m_editing) return; |
841 | 866 |
842 long frame = v->getFrameForX(e->x()); | 867 long frame = v->getFrameForX(e->x()); |
843 long resolution = m_model->getResolution(); | 868 long resolution = m_model->getResolution(); |
846 | 871 |
847 float value = getValueForY(v, e->y()); | 872 float value = getValueForY(v, e->y()); |
848 | 873 |
849 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); | 874 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); |
850 | 875 |
851 std::cerr << points.size() << " points" << std::endl; | 876 // std::cerr << points.size() << " points" << std::endl; |
852 | 877 |
853 bool havePoint = false; | 878 bool havePoint = false; |
854 | 879 |
855 if (!points.empty()) { | 880 if (!points.empty()) { |
856 for (SparseTimeValueModel::PointList::iterator i = points.begin(); | 881 for (SparseTimeValueModel::PointList::iterator i = points.begin(); |
857 i != points.end(); ++i) { | 882 i != points.end(); ++i) { |
858 if (i->frame == m_editingPoint.frame && | 883 if (i->frame == m_editingPoint.frame && |
859 i->value == m_editingPoint.value) { | 884 i->value == m_editingPoint.value) { |
860 std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl; | 885 // std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl; |
861 continue; | 886 continue; |
862 } | 887 } |
863 if (((i->frame / resolution) * resolution) != frame) { | 888 if (((i->frame / resolution) * resolution) != frame) { |
864 std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl; | 889 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl; |
865 continue; | 890 continue; |
866 } | 891 } |
867 std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl; | 892 // std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl; |
868 m_editingPoint = *i; | 893 m_editingPoint = *i; |
869 m_originalPoint = m_editingPoint; | 894 m_originalPoint = m_editingPoint; |
870 m_editingCommand->deletePoint(m_editingPoint); | 895 m_editingCommand->deletePoint(m_editingPoint); |
871 havePoint = true; | 896 havePoint = true; |
872 } | 897 } |
885 } | 910 } |
886 | 911 |
887 void | 912 void |
888 TimeValueLayer::drawEnd(View *v, QMouseEvent *e) | 913 TimeValueLayer::drawEnd(View *v, QMouseEvent *e) |
889 { | 914 { |
890 std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; | 915 // std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; |
891 if (!m_model || !m_editing) return; | 916 if (!m_model || !m_editing) return; |
892 m_editingCommand->finish(); | 917 m_editingCommand->finish(); |
893 m_editingCommand = 0; | 918 m_editingCommand = 0; |
894 m_editing = false; | 919 m_editing = false; |
895 } | 920 } |
896 | 921 |
897 void | 922 void |
898 TimeValueLayer::editStart(View *v, QMouseEvent *e) | 923 TimeValueLayer::editStart(View *v, QMouseEvent *e) |
899 { | 924 { |
900 std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; | 925 // std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; |
901 | 926 |
902 if (!m_model) return; | 927 if (!m_model) return; |
903 | 928 |
904 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); | 929 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x()); |
905 if (points.empty()) return; | 930 if (points.empty()) return; |
916 } | 941 } |
917 | 942 |
918 void | 943 void |
919 TimeValueLayer::editDrag(View *v, QMouseEvent *e) | 944 TimeValueLayer::editDrag(View *v, QMouseEvent *e) |
920 { | 945 { |
921 std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl; | 946 // std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl; |
922 | 947 |
923 if (!m_model || !m_editing) return; | 948 if (!m_model || !m_editing) return; |
924 | 949 |
925 long frame = v->getFrameForX(e->x()); | 950 long frame = v->getFrameForX(e->x()); |
926 if (frame < 0) frame = 0; | 951 if (frame < 0) frame = 0; |
940 } | 965 } |
941 | 966 |
942 void | 967 void |
943 TimeValueLayer::editEnd(View *v, QMouseEvent *e) | 968 TimeValueLayer::editEnd(View *v, QMouseEvent *e) |
944 { | 969 { |
945 std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; | 970 // std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; |
946 if (!m_model || !m_editing) return; | 971 if (!m_model || !m_editing) return; |
947 | 972 |
948 if (m_editingCommand) { | 973 if (m_editingCommand) { |
949 | 974 |
950 QString newName = m_editingCommand->getName(); | 975 QString newName = m_editingCommand->getName(); |