00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "TimeValueLayer.h"
00017
00018 #include "data/model/Model.h"
00019 #include "base/RealTime.h"
00020 #include "base/Profiler.h"
00021 #include "base/LogRange.h"
00022 #include "base/ColourDatabase.h"
00023 #include "view/View.h"
00024
00025 #include "data/model/SparseTimeValueModel.h"
00026 #include "data/model/Labeller.h"
00027
00028 #include "widgets/ItemEditDialog.h"
00029 #include "widgets/ListInputDialog.h"
00030
00031 #include "SpectrogramLayer.h"
00032 #include "base/ColourMapper.h"
00033
00034 #include <QPainter>
00035 #include <QPainterPath>
00036 #include <QMouseEvent>
00037 #include <QRegExp>
00038 #include <QTextStream>
00039 #include <QMessageBox>
00040 #include <QInputDialog>
00041
00042 #include <iostream>
00043 #include <cmath>
00044
00045 TimeValueLayer::TimeValueLayer() :
00046 SingleColourLayer(),
00047 m_model(0),
00048 m_editing(false),
00049 m_originalPoint(0, 0.0, tr("New Point")),
00050 m_editingPoint(0, 0.0, tr("New Point")),
00051 m_editingCommand(0),
00052 m_colourMap(0),
00053 m_plotStyle(PlotConnectedPoints),
00054 m_verticalScale(AutoAlignScale)
00055 {
00056
00057 }
00058
00059 void
00060 TimeValueLayer::setModel(SparseTimeValueModel *model)
00061 {
00062 if (m_model == model) return;
00063 m_model = model;
00064
00065 connectSignals(m_model);
00066
00067
00068
00069 emit modelReplaced();
00070 }
00071
00072 Layer::PropertyList
00073 TimeValueLayer::getProperties() const
00074 {
00075 PropertyList list = SingleColourLayer::getProperties();
00076 list.push_back("Plot Type");
00077 list.push_back("Vertical Scale");
00078 list.push_back("Scale Units");
00079 return list;
00080 }
00081
00082 QString
00083 TimeValueLayer::getPropertyLabel(const PropertyName &name) const
00084 {
00085 if (name == "Plot Type") return tr("Plot Type");
00086 if (name == "Vertical Scale") return tr("Vertical Scale");
00087 if (name == "Scale Units") return tr("Scale Units");
00088 return SingleColourLayer::getPropertyLabel(name);
00089 }
00090
00091 Layer::PropertyType
00092 TimeValueLayer::getPropertyType(const PropertyName &name) const
00093 {
00094 if (name == "Plot Type") return ValueProperty;
00095 if (name == "Vertical Scale") return ValueProperty;
00096 if (name == "Scale Units") return UnitsProperty;
00097 if (name == "Colour" && m_plotStyle == PlotSegmentation) return ValueProperty;
00098 return SingleColourLayer::getPropertyType(name);
00099 }
00100
00101 QString
00102 TimeValueLayer::getPropertyGroupName(const PropertyName &name) const
00103 {
00104 if (name == "Vertical Scale" || name == "Scale Units") {
00105 return tr("Scale");
00106 }
00107 return SingleColourLayer::getPropertyGroupName(name);
00108 }
00109
00110 int
00111 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
00112 int *min, int *max, int *deflt) const
00113 {
00114 int val = 0;
00115
00116 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
00117
00118 if (min) *min = 0;
00119 if (max) *max = ColourMapper::getColourMapCount() - 1;
00120 if (deflt) *deflt = 0;
00121
00122 val = m_colourMap;
00123
00124 } else if (name == "Plot Type") {
00125
00126 if (min) *min = 0;
00127 if (max) *max = 5;
00128 if (deflt) *deflt = int(PlotConnectedPoints);
00129
00130 val = int(m_plotStyle);
00131
00132 } else if (name == "Vertical Scale") {
00133
00134 if (min) *min = 0;
00135 if (max) *max = 3;
00136 if (deflt) *deflt = int(AutoAlignScale);
00137
00138 val = int(m_verticalScale);
00139
00140 } else if (name == "Scale Units") {
00141
00142 if (deflt) *deflt = 0;
00143 if (m_model) {
00144 val = UnitDatabase::getInstance()->getUnitId
00145 (m_model->getScaleUnits());
00146 }
00147
00148 } else {
00149
00150 val = SingleColourLayer::getPropertyRangeAndValue(name, min, max, deflt);
00151 }
00152
00153 return val;
00154 }
00155
00156 QString
00157 TimeValueLayer::getPropertyValueLabel(const PropertyName &name,
00158 int value) const
00159 {
00160 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
00161 return ColourMapper::getColourMapName(value);
00162 } else if (name == "Plot Type") {
00163 switch (value) {
00164 default:
00165 case 0: return tr("Points");
00166 case 1: return tr("Stems");
00167 case 2: return tr("Connected Points");
00168 case 3: return tr("Lines");
00169 case 4: return tr("Curve");
00170 case 5: return tr("Segmentation");
00171 }
00172 } else if (name == "Vertical Scale") {
00173 switch (value) {
00174 default:
00175 case 0: return tr("Auto-Align");
00176 case 1: return tr("Linear");
00177 case 2: return tr("Log");
00178 case 3: return tr("+/-1");
00179 }
00180 }
00181 return SingleColourLayer::getPropertyValueLabel(name, value);
00182 }
00183
00184 void
00185 TimeValueLayer::setProperty(const PropertyName &name, int value)
00186 {
00187 if (name == "Colour" && m_plotStyle == PlotSegmentation) {
00188 setFillColourMap(value);
00189 } else if (name == "Plot Type") {
00190 setPlotStyle(PlotStyle(value));
00191 } else if (name == "Vertical Scale") {
00192 setVerticalScale(VerticalScale(value));
00193 } else if (name == "Scale Units") {
00194 if (m_model) {
00195 m_model->setScaleUnits
00196 (UnitDatabase::getInstance()->getUnitById(value));
00197 emit modelChanged();
00198 }
00199 } else {
00200 SingleColourLayer::setProperty(name, value);
00201 }
00202 }
00203
00204 void
00205 TimeValueLayer::setFillColourMap(int map)
00206 {
00207 if (m_colourMap == map) return;
00208 m_colourMap = map;
00209 emit layerParametersChanged();
00210 }
00211
00212 void
00213 TimeValueLayer::setPlotStyle(PlotStyle style)
00214 {
00215 if (m_plotStyle == style) return;
00216 bool colourTypeChanged = (style == PlotSegmentation ||
00217 m_plotStyle == PlotSegmentation);
00218 m_plotStyle = style;
00219 if (colourTypeChanged) {
00220 emit layerParameterRangesChanged();
00221 }
00222 emit layerParametersChanged();
00223 }
00224
00225 void
00226 TimeValueLayer::setVerticalScale(VerticalScale scale)
00227 {
00228 if (m_verticalScale == scale) return;
00229 m_verticalScale = scale;
00230 emit layerParametersChanged();
00231 }
00232
00233 bool
00234 TimeValueLayer::isLayerScrollable(const View *v) const
00235 {
00236
00237
00238
00239 if (m_plotStyle == PlotLines ||
00240 m_plotStyle == PlotCurve) return true;
00241
00242 QPoint discard;
00243 return !v->shouldIlluminateLocalFeatures(this, discard);
00244 }
00245
00246 bool
00247 TimeValueLayer::getValueExtents(float &min, float &max,
00248 bool &logarithmic, QString &unit) const
00249 {
00250 if (!m_model) return false;
00251 min = m_model->getValueMinimum();
00252 max = m_model->getValueMaximum();
00253 logarithmic = (m_verticalScale == LogScale);
00254 unit = m_model->getScaleUnits();
00255 return true;
00256 }
00257
00258 bool
00259 TimeValueLayer::getDisplayExtents(float &min, float &max) const
00260 {
00261 if (!m_model || shouldAutoAlign()) return false;
00262
00263 min = m_model->getValueMinimum();
00264 max = m_model->getValueMaximum();
00265 return true;
00266 }
00267
00268 SparseTimeValueModel::PointList
00269 TimeValueLayer::getLocalPoints(View *v, int x) const
00270 {
00271 if (!m_model) return SparseTimeValueModel::PointList();
00272
00273 long frame = v->getFrameForX(x);
00274
00275 SparseTimeValueModel::PointList onPoints =
00276 m_model->getPoints(frame);
00277
00278 if (!onPoints.empty()) {
00279 return onPoints;
00280 }
00281
00282 SparseTimeValueModel::PointList prevPoints =
00283 m_model->getPreviousPoints(frame);
00284 SparseTimeValueModel::PointList nextPoints =
00285 m_model->getNextPoints(frame);
00286
00287 SparseTimeValueModel::PointList usePoints = prevPoints;
00288
00289 if (prevPoints.empty()) {
00290 usePoints = nextPoints;
00291 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
00292 !(nextPoints.begin()->frame > v->getEndFrame())) {
00293 usePoints = nextPoints;
00294 } else if (nextPoints.begin()->frame - frame <
00295 frame - prevPoints.begin()->frame) {
00296 usePoints = nextPoints;
00297 }
00298
00299 if (!usePoints.empty()) {
00300 int fuzz = 2;
00301 int px = v->getXForFrame(usePoints.begin()->frame);
00302 if ((px > x && px - x > fuzz) ||
00303 (px < x && x - px > fuzz + 1)) {
00304 usePoints.clear();
00305 }
00306 }
00307
00308 return usePoints;
00309 }
00310
00311 QString
00312 TimeValueLayer::getFeatureDescription(View *v, QPoint &pos) const
00313 {
00314 int x = pos.x();
00315
00316 if (!m_model || !m_model->getSampleRate()) return "";
00317
00318 SparseTimeValueModel::PointList points = getLocalPoints(v, x);
00319
00320 if (points.empty()) {
00321 if (!m_model->isReady()) {
00322 return tr("In progress");
00323 } else {
00324 return tr("No local points");
00325 }
00326 }
00327
00328 long useFrame = points.begin()->frame;
00329
00330 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
00331
00332 QString text;
00333 QString unit = m_model->getScaleUnits();
00334 if (unit != "") unit = " " + unit;
00335
00336 if (points.begin()->label == "") {
00337 text = QString(tr("Time:\t%1\nValue:\t%2%3\nNo label"))
00338 .arg(rt.toText(true).c_str())
00339 .arg(points.begin()->value)
00340 .arg(unit);
00341 } else {
00342 text = QString(tr("Time:\t%1\nValue:\t%2%3\nLabel:\t%4"))
00343 .arg(rt.toText(true).c_str())
00344 .arg(points.begin()->value)
00345 .arg(unit)
00346 .arg(points.begin()->label);
00347 }
00348
00349 pos = QPoint(v->getXForFrame(useFrame),
00350 getYForValue(v, points.begin()->value));
00351 return text;
00352 }
00353
00354 bool
00355 TimeValueLayer::snapToFeatureFrame(View *v, int &frame,
00356 size_t &resolution,
00357 SnapType snap) const
00358 {
00359 if (!m_model) {
00360 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
00361 }
00362
00363 resolution = m_model->getResolution();
00364 SparseTimeValueModel::PointList points;
00365
00366 if (snap == SnapNeighbouring) {
00367
00368 points = getLocalPoints(v, v->getXForFrame(frame));
00369 if (points.empty()) return false;
00370 frame = points.begin()->frame;
00371 return true;
00372 }
00373
00374 points = m_model->getPoints(frame, frame);
00375 int snapped = frame;
00376 bool found = false;
00377
00378 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
00379 i != points.end(); ++i) {
00380
00381 if (snap == SnapRight) {
00382
00383 if (i->frame > frame) {
00384 snapped = i->frame;
00385 found = true;
00386 break;
00387 }
00388
00389 } else if (snap == SnapLeft) {
00390
00391 if (i->frame <= frame) {
00392 snapped = i->frame;
00393 found = true;
00394 } else {
00395 break;
00396 }
00397
00398 } else {
00399
00400 SparseTimeValueModel::PointList::const_iterator j = i;
00401 ++j;
00402
00403 if (j == points.end()) {
00404
00405 snapped = i->frame;
00406 found = true;
00407 break;
00408
00409 } else if (j->frame >= frame) {
00410
00411 if (j->frame - frame < frame - i->frame) {
00412 snapped = j->frame;
00413 } else {
00414 snapped = i->frame;
00415 }
00416 found = true;
00417 break;
00418 }
00419 }
00420 }
00421
00422 frame = snapped;
00423 return found;
00424 }
00425
00426 void
00427 TimeValueLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
00428 {
00429 min = 0.0;
00430 max = 0.0;
00431 log = false;
00432
00433 if (shouldAutoAlign()) {
00434
00435 if (!v->getValueExtents(m_model->getScaleUnits(), min, max, log)) {
00436 min = m_model->getValueMinimum();
00437 max = m_model->getValueMaximum();
00438 } else if (log) {
00439 LogRange::mapRange(min, max);
00440 }
00441
00442 } else if (m_verticalScale == PlusMinusOneScale) {
00443
00444 min = -1.0;
00445 max = 1.0;
00446
00447 } else {
00448
00449 min = m_model->getValueMinimum();
00450 max = m_model->getValueMaximum();
00451
00452 if (m_verticalScale == LogScale) {
00453 LogRange::mapRange(min, max);
00454 log = true;
00455 }
00456 }
00457
00458 if (max == min) max = min + 1.0;
00459 }
00460
00461 int
00462 TimeValueLayer::getYForValue(View *v, float val) const
00463 {
00464 float min = 0.0, max = 0.0;
00465 bool logarithmic = false;
00466 int h = v->height();
00467
00468 getScaleExtents(v, min, max, logarithmic);
00469
00470
00471
00472
00473 if (logarithmic) {
00474 val = LogRange::map(val);
00475 }
00476
00477 return int(h - ((val - min) * h) / (max - min));
00478 }
00479
00480 float
00481 TimeValueLayer::getValueForY(View *v, int y) const
00482 {
00483 float min = 0.0, max = 0.0;
00484 bool logarithmic = false;
00485 int h = v->height();
00486
00487 getScaleExtents(v, min, max, logarithmic);
00488
00489 float val = min + (float(h - y) * float(max - min)) / h;
00490
00491 if (logarithmic) {
00492 val = powf(10.f, val);
00493 }
00494
00495 return val;
00496 }
00497
00498 bool
00499 TimeValueLayer::shouldAutoAlign() const
00500 {
00501 if (!m_model) return false;
00502 QString unit = m_model->getScaleUnits();
00503 return (m_verticalScale == AutoAlignScale && unit != "");
00504 }
00505
00506 QColor
00507 TimeValueLayer::getColourForValue(View *v, float val) const
00508 {
00509 float min, max;
00510 bool log;
00511 getScaleExtents(v, min, max, log);
00512
00513 if (min > max) std::swap(min, max);
00514 if (max == min) max = min + 1;
00515
00516 if (log) {
00517 LogRange::mapRange(min, max);
00518 val = LogRange::map(val);
00519 }
00520
00521
00522
00523
00524 QColor solid = ColourMapper(m_colourMap, min, max).map(val);
00525 return QColor(solid.red(), solid.green(), solid.blue(), 120);
00526 }
00527
00528 int
00529 TimeValueLayer::getDefaultColourHint(bool darkbg, bool &impose)
00530 {
00531 impose = false;
00532 return ColourDatabase::getInstance()->getColourIndex
00533 (QString(darkbg ? "Bright Green" : "Green"));
00534 }
00535
00536 void
00537 TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const
00538 {
00539 if (!m_model || !m_model->isOK()) return;
00540
00541 int sampleRate = m_model->getSampleRate();
00542 if (!sampleRate) return;
00543
00544 paint.setRenderHint(QPainter::Antialiasing, false);
00545
00546
00547
00548 int x0 = rect.left(), x1 = rect.right();
00549 long frame0 = v->getFrameForX(x0);
00550 long frame1 = v->getFrameForX(x1);
00551
00552 SparseTimeValueModel::PointList points(m_model->getPoints
00553 (frame0, frame1));
00554 if (points.empty()) return;
00555
00556 paint.setPen(getBaseQColor());
00557
00558 QColor brushColour(getBaseQColor());
00559 brushColour.setAlpha(80);
00560 paint.setBrush(brushColour);
00561
00562
00563
00564
00565 float min = m_model->getValueMinimum();
00566 float max = m_model->getValueMaximum();
00567 if (max == min) max = min + 1.0;
00568
00569 int origin = int(nearbyint(v->height() -
00570 (-min * v->height()) / (max - min)));
00571
00572 QPoint localPos;
00573 long illuminateFrame = -1;
00574
00575 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
00576 SparseTimeValueModel::PointList localPoints =
00577 getLocalPoints(v, localPos.x());
00578
00579 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
00580 }
00581
00582 int w =
00583 v->getXForFrame(frame0 + m_model->getResolution()) -
00584 v->getXForFrame(frame0);
00585
00586 paint.save();
00587
00588 QPainterPath path;
00589 int pointCount = 0;
00590
00591 int textY = 0;
00592 if (m_plotStyle == PlotSegmentation) {
00593 textY = v->getTextLabelHeight(this, paint);
00594 }
00595
00596 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
00597 i != points.end(); ++i) {
00598
00599 const SparseTimeValueModel::Point &p(*i);
00600
00601 int x = v->getXForFrame(p.frame);
00602 int y = getYForValue(v, p.value);
00603
00604 if (m_plotStyle != PlotSegmentation) {
00605 textY = y - paint.fontMetrics().height()
00606 + paint.fontMetrics().ascent();
00607 if (textY < paint.fontMetrics().ascent() + 1) {
00608 textY = paint.fontMetrics().ascent() + 1;
00609 }
00610 }
00611
00612 bool haveNext = false;
00613 int nx = v->getXForFrame(v->getModelsEndFrame());
00614
00615 int ny = y;
00616
00617 SparseTimeValueModel::PointList::const_iterator j = i;
00618 ++j;
00619
00620 if (j != points.end()) {
00621 const SparseTimeValueModel::Point &q(*j);
00622 nx = v->getXForFrame(q.frame);
00623 ny = getYForValue(v, q.value);
00624 haveNext = true;
00625 }
00626
00627
00628
00629
00630 int labelY = y;
00631
00632 if (w < 1) w = 1;
00633 paint.setPen(getBaseQColor());
00634
00635 if (m_plotStyle == PlotSegmentation) {
00636 paint.setPen(getForegroundQColor(v));
00637 paint.setBrush(getColourForValue(v, p.value));
00638 labelY = v->height();
00639 } else if (m_plotStyle == PlotLines ||
00640 m_plotStyle == PlotCurve) {
00641 paint.setBrush(Qt::NoBrush);
00642 } else {
00643 paint.setBrush(brushColour);
00644 }
00645
00646 if (m_plotStyle == PlotStems) {
00647 paint.setPen(brushColour);
00648 if (y < origin - 1) {
00649 paint.drawRect(x + w/2, y + 1, 1, origin - y);
00650 } else if (y > origin + 1) {
00651 paint.drawRect(x + w/2, origin, 1, y - origin - 1);
00652 }
00653 paint.setPen(getBaseQColor());
00654 }
00655
00656 if (illuminateFrame == p.frame) {
00657
00659
00660
00661
00663
00664
00665 if (m_plotStyle != PlotCurve &&
00666 m_plotStyle != PlotLines) {
00667 paint.setPen(getForegroundQColor(v));
00668 }
00669 }
00670
00671 if (m_plotStyle != PlotLines &&
00672 m_plotStyle != PlotCurve &&
00673 m_plotStyle != PlotSegmentation) {
00674 if (m_plotStyle != PlotStems ||
00675 w > 1) {
00676 paint.drawRect(x, y - 1, w, 2);
00677 }
00678 }
00679
00680 if (m_plotStyle == PlotConnectedPoints ||
00681 m_plotStyle == PlotLines ||
00682 m_plotStyle == PlotCurve) {
00683
00684 if (haveNext) {
00685
00686 if (m_plotStyle == PlotConnectedPoints) {
00687
00688 paint.save();
00689 paint.setPen(brushColour);
00690 paint.drawLine(x + w, y, nx, ny);
00691 paint.restore();
00692
00693 } else if (m_plotStyle == PlotLines) {
00694
00695 paint.drawLine(x + w/2, y, nx + w/2, ny);
00696
00697 } else {
00698
00699 float x0 = x + float(w)/2;
00700 float x1 = nx + float(w)/2;
00701
00702 float y0 = y;
00703 float y1 = ny;
00704
00705 if (pointCount == 0) {
00706 path.moveTo((x0 + x1) / 2, (y0 + y1) / 2);
00707 }
00708 ++pointCount;
00709
00710 if (nx - x > 5) {
00711 path.cubicTo(x0, y0,
00712 x0, y0,
00713 (x0 + x1) / 2, (y0 + y1) / 2);
00714
00715
00716
00717
00718 } else {
00719 path.lineTo((x0 + x1) / 2, (y0 + y1) / 2);
00720 }
00721 }
00722 }
00723 }
00724
00725 if (m_plotStyle == PlotSegmentation) {
00726
00727
00728
00729 if (nx <= x) continue;
00730
00731 if (illuminateFrame != p.frame &&
00732 (nx < x + 5 || x >= v->width() - 1)) {
00733 paint.setPen(Qt::NoPen);
00734 }
00735
00736 paint.drawRect(x, -1, nx - x, v->height() + 1);
00737 }
00738
00739 if (p.label != "") {
00740 if (!haveNext || nx > x + 6 + paint.fontMetrics().width(p.label)) {
00741 paint.drawText(x + 5, textY, p.label);
00742 }
00743 }
00744 }
00745
00746 if (m_plotStyle == PlotCurve && !path.isEmpty()) {
00747 paint.setRenderHint(QPainter::Antialiasing, pointCount <= v->width());
00748 paint.drawPath(path);
00749 }
00750
00751 paint.restore();
00752
00753
00754 paint.setRenderHint(QPainter::Antialiasing, false);
00755 }
00756
00757 int
00758 TimeValueLayer::getVerticalScaleWidth(View *, QPainter &paint) const
00759 {
00760 int w = paint.fontMetrics().width("-000.000");
00761 if (m_plotStyle == PlotSegmentation) return w + 20;
00762 else return w + 10;
00763 }
00764
00765 void
00766 TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect) const
00767 {
00768 if (!m_model) return;
00769
00770 int h = v->height();
00771
00772 int n = 10;
00773
00774 float max = m_model->getValueMaximum();
00775 float min = m_model->getValueMinimum();
00776 float val = min;
00777 float inc = (max - val) / n;
00778
00779 char buffer[40];
00780
00781 int w = getVerticalScaleWidth(v, paint);
00782
00783 int tx = 5;
00784
00785 int boxx = 5, boxy = 5;
00786 if (m_model->getScaleUnits() != "") {
00787 boxy += paint.fontMetrics().height();
00788 }
00789 int boxw = 10, boxh = h - boxy - 5;
00790
00791 if (m_plotStyle == PlotSegmentation) {
00792 tx += boxx + boxw;
00793 paint.drawRect(boxx, boxy, boxw, boxh);
00794 }
00795
00796 if (m_plotStyle == PlotSegmentation) {
00797 paint.save();
00798 for (int y = 0; y < boxh; ++y) {
00799 float val = ((boxh - y) * (max - min)) / boxh + min;
00800 paint.setPen(getColourForValue(v, val));
00801 paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1);
00802 }
00803 paint.restore();
00804 }
00805
00806 for (int i = 0; i < n; ++i) {
00807
00808 int y, ty;
00809 bool drawText = true;
00810
00811 if (m_plotStyle == PlotSegmentation) {
00812 y = boxy + int(boxh - ((val - min) * boxh) / (max - min));
00813 ty = y;
00814 } else {
00815 if (i == n-1) {
00816 if (m_model->getScaleUnits() != "") drawText = false;
00817 }
00818 y = getYForValue(v, val);
00819 ty = y - paint.fontMetrics().height() +
00820 paint.fontMetrics().ascent();
00821 }
00822
00823 sprintf(buffer, "%.3f", val);
00824 QString label = QString(buffer);
00825
00826 if (m_plotStyle != PlotSegmentation) {
00827 paint.drawLine(w - 5, y, w, y);
00828 } else {
00829 paint.drawLine(boxx + boxw - boxw/3, y, boxx + boxw, y);
00830 }
00831
00832 if (drawText) paint.drawText(tx, ty, label);
00833 val += inc;
00834 }
00835
00836 if (m_model->getScaleUnits() != "") {
00837 paint.drawText(5, 5 + paint.fontMetrics().ascent(),
00838 m_model->getScaleUnits());
00839 }
00840 }
00841
00842 void
00843 TimeValueLayer::drawStart(View *v, QMouseEvent *e)
00844 {
00845
00846
00847 if (!m_model) return;
00848
00849 long frame = v->getFrameForX(e->x());
00850 long resolution = m_model->getResolution();
00851 if (frame < 0) frame = 0;
00852 frame = (frame / resolution) * resolution;
00853
00854 float value = getValueForY(v, e->y());
00855
00856 bool havePoint = false;
00857
00858 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
00859 if (!points.empty()) {
00860 for (SparseTimeValueModel::PointList::iterator i = points.begin();
00861 i != points.end(); ++i) {
00862 if (((i->frame / resolution) * resolution) != frame) {
00863
00864 continue;
00865 }
00866 m_editingPoint = *i;
00867 havePoint = true;
00868 }
00869 }
00870
00871 if (!havePoint) {
00872 m_editingPoint = SparseTimeValueModel::Point
00873 (frame, value, tr("New Point"));
00874 }
00875
00876 m_originalPoint = m_editingPoint;
00877
00878 if (m_editingCommand) m_editingCommand->finish();
00879 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
00880 tr("Draw Point"));
00881 if (!havePoint) {
00882 m_editingCommand->addPoint(m_editingPoint);
00883 }
00884
00885 m_editing = true;
00886 }
00887
00888 void
00889 TimeValueLayer::drawDrag(View *v, QMouseEvent *e)
00890 {
00891
00892
00893 if (!m_model || !m_editing) return;
00894
00895 long frame = v->getFrameForX(e->x());
00896 long resolution = m_model->getResolution();
00897 if (frame < 0) frame = 0;
00898 frame = (frame / resolution) * resolution;
00899
00900 float value = getValueForY(v, e->y());
00901
00902 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
00903
00904
00905
00906 bool havePoint = false;
00907
00908 if (!points.empty()) {
00909 for (SparseTimeValueModel::PointList::iterator i = points.begin();
00910 i != points.end(); ++i) {
00911 if (i->frame == m_editingPoint.frame &&
00912 i->value == m_editingPoint.value) {
00913
00914 continue;
00915 }
00916 if (((i->frame / resolution) * resolution) != frame) {
00917
00918 continue;
00919 }
00920
00921 m_editingPoint = *i;
00922 m_originalPoint = m_editingPoint;
00923 m_editingCommand->deletePoint(m_editingPoint);
00924 havePoint = true;
00925 }
00926 }
00927
00928 if (!havePoint) {
00929 if (frame == m_editingPoint.frame) {
00930 m_editingCommand->deletePoint(m_editingPoint);
00931 }
00932 }
00933
00934
00935 m_editingPoint.frame = frame;
00936 m_editingPoint.value = value;
00937 m_editingCommand->addPoint(m_editingPoint);
00938 }
00939
00940 void
00941 TimeValueLayer::drawEnd(View *, QMouseEvent *)
00942 {
00943
00944 if (!m_model || !m_editing) return;
00945 m_editingCommand->finish();
00946 m_editingCommand = 0;
00947 m_editing = false;
00948 }
00949
00950 void
00951 TimeValueLayer::eraseStart(View *v, QMouseEvent *e)
00952 {
00953 if (!m_model) return;
00954
00955 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
00956 if (points.empty()) return;
00957
00958 m_editingPoint = *points.begin();
00959
00960 if (m_editingCommand) {
00961 m_editingCommand->finish();
00962 m_editingCommand = 0;
00963 }
00964
00965 m_editing = true;
00966 }
00967
00968 void
00969 TimeValueLayer::eraseDrag(View *v, QMouseEvent *e)
00970 {
00971 }
00972
00973 void
00974 TimeValueLayer::eraseEnd(View *v, QMouseEvent *e)
00975 {
00976 if (!m_model || !m_editing) return;
00977
00978 m_editing = false;
00979
00980 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
00981 if (points.empty()) return;
00982 if (points.begin()->frame != m_editingPoint.frame ||
00983 points.begin()->value != m_editingPoint.value) return;
00984
00985 m_editingCommand = new SparseTimeValueModel::EditCommand
00986 (m_model, tr("Erase Point"));
00987
00988 m_editingCommand->deletePoint(m_editingPoint);
00989
00990 m_editingCommand->finish();
00991 m_editingCommand = 0;
00992 m_editing = false;
00993 }
00994
00995 void
00996 TimeValueLayer::editStart(View *v, QMouseEvent *e)
00997 {
00998
00999
01000 if (!m_model) return;
01001
01002 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
01003 if (points.empty()) return;
01004
01005 m_editingPoint = *points.begin();
01006 m_originalPoint = m_editingPoint;
01007
01008 if (m_editingCommand) {
01009 m_editingCommand->finish();
01010 m_editingCommand = 0;
01011 }
01012
01013 m_editing = true;
01014 }
01015
01016 void
01017 TimeValueLayer::editDrag(View *v, QMouseEvent *e)
01018 {
01019
01020
01021 if (!m_model || !m_editing) return;
01022
01023 long frame = v->getFrameForX(e->x());
01024 if (frame < 0) frame = 0;
01025 frame = frame / m_model->getResolution() * m_model->getResolution();
01026
01027 float value = getValueForY(v, e->y());
01028
01029 if (!m_editingCommand) {
01030 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
01031 tr("Drag Point"));
01032 }
01033
01034 m_editingCommand->deletePoint(m_editingPoint);
01035 m_editingPoint.frame = frame;
01036 m_editingPoint.value = value;
01037 m_editingCommand->addPoint(m_editingPoint);
01038 }
01039
01040 void
01041 TimeValueLayer::editEnd(View *, QMouseEvent *)
01042 {
01043
01044 if (!m_model || !m_editing) return;
01045
01046 if (m_editingCommand) {
01047
01048 QString newName = m_editingCommand->getName();
01049
01050 if (m_editingPoint.frame != m_originalPoint.frame) {
01051 if (m_editingPoint.value != m_originalPoint.value) {
01052 newName = tr("Edit Point");
01053 } else {
01054 newName = tr("Relocate Point");
01055 }
01056 } else {
01057 newName = tr("Change Point Value");
01058 }
01059
01060 m_editingCommand->setName(newName);
01061 m_editingCommand->finish();
01062 }
01063
01064 m_editingCommand = 0;
01065 m_editing = false;
01066 }
01067
01068 bool
01069 TimeValueLayer::editOpen(View *v, QMouseEvent *e)
01070 {
01071 if (!m_model) return false;
01072
01073 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
01074 if (points.empty()) return false;
01075
01076 SparseTimeValueModel::Point point = *points.begin();
01077
01078 ItemEditDialog *dialog = new ItemEditDialog
01079 (m_model->getSampleRate(),
01080 ItemEditDialog::ShowTime |
01081 ItemEditDialog::ShowValue |
01082 ItemEditDialog::ShowText,
01083 m_model->getScaleUnits());
01084
01085 dialog->setFrameTime(point.frame);
01086 dialog->setValue(point.value);
01087 dialog->setText(point.label);
01088
01089 if (dialog->exec() == QDialog::Accepted) {
01090
01091 SparseTimeValueModel::Point newPoint = point;
01092 newPoint.frame = dialog->getFrameTime();
01093 newPoint.value = dialog->getValue();
01094 newPoint.label = dialog->getText();
01095
01096 SparseTimeValueModel::EditCommand *command =
01097 new SparseTimeValueModel::EditCommand(m_model, tr("Edit Point"));
01098 command->deletePoint(point);
01099 command->addPoint(newPoint);
01100 command->finish();
01101 }
01102
01103 delete dialog;
01104 return true;
01105 }
01106
01107 void
01108 TimeValueLayer::moveSelection(Selection s, size_t newStartFrame)
01109 {
01110 if (!m_model) return;
01111
01112 SparseTimeValueModel::EditCommand *command =
01113 new SparseTimeValueModel::EditCommand(m_model,
01114 tr("Drag Selection"));
01115
01116 SparseTimeValueModel::PointList points =
01117 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
01118
01119 for (SparseTimeValueModel::PointList::iterator i = points.begin();
01120 i != points.end(); ++i) {
01121
01122 if (s.contains(i->frame)) {
01123 SparseTimeValueModel::Point newPoint(*i);
01124 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
01125 command->deletePoint(*i);
01126 command->addPoint(newPoint);
01127 }
01128 }
01129
01130 command->finish();
01131 }
01132
01133 void
01134 TimeValueLayer::resizeSelection(Selection s, Selection newSize)
01135 {
01136 if (!m_model) return;
01137
01138 SparseTimeValueModel::EditCommand *command =
01139 new SparseTimeValueModel::EditCommand(m_model,
01140 tr("Resize Selection"));
01141
01142 SparseTimeValueModel::PointList points =
01143 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
01144
01145 double ratio =
01146 double(newSize.getEndFrame() - newSize.getStartFrame()) /
01147 double(s.getEndFrame() - s.getStartFrame());
01148
01149 for (SparseTimeValueModel::PointList::iterator i = points.begin();
01150 i != points.end(); ++i) {
01151
01152 if (s.contains(i->frame)) {
01153
01154 double target = i->frame;
01155 target = newSize.getStartFrame() +
01156 double(target - s.getStartFrame()) * ratio;
01157
01158 SparseTimeValueModel::Point newPoint(*i);
01159 newPoint.frame = lrint(target);
01160 command->deletePoint(*i);
01161 command->addPoint(newPoint);
01162 }
01163 }
01164
01165 command->finish();
01166 }
01167
01168 void
01169 TimeValueLayer::deleteSelection(Selection s)
01170 {
01171 if (!m_model) return;
01172
01173 SparseTimeValueModel::EditCommand *command =
01174 new SparseTimeValueModel::EditCommand(m_model,
01175 tr("Delete Selected Points"));
01176
01177 SparseTimeValueModel::PointList points =
01178 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
01179
01180 for (SparseTimeValueModel::PointList::iterator i = points.begin();
01181 i != points.end(); ++i) {
01182
01183 if (s.contains(i->frame)) {
01184 command->deletePoint(*i);
01185 }
01186 }
01187
01188 command->finish();
01189 }
01190
01191 void
01192 TimeValueLayer::copy(View *v, Selection s, Clipboard &to)
01193 {
01194 if (!m_model) return;
01195
01196 SparseTimeValueModel::PointList points =
01197 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
01198
01199 for (SparseTimeValueModel::PointList::iterator i = points.begin();
01200 i != points.end(); ++i) {
01201 if (s.contains(i->frame)) {
01202 Clipboard::Point point(i->frame, i->value, i->label);
01203 point.setReferenceFrame(alignToReference(v, i->frame));
01204 to.addPoint(point);
01205 }
01206 }
01207 }
01208
01209 bool
01210 TimeValueLayer::paste(View *v, const Clipboard &from, int frameOffset,
01211 bool interactive)
01212 {
01213 if (!m_model) return false;
01214
01215 const Clipboard::PointList &points = from.getPoints();
01216
01217 bool realign = false;
01218
01219 if (clipboardHasDifferentAlignment(v, from)) {
01220
01221 QMessageBox::StandardButton button =
01222 QMessageBox::question(v, tr("Re-align pasted items?"),
01223 tr("The items you are pasting came from a layer with different source material from this one. Do you want to re-align them in time, to match the source material for this layer?"),
01224 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
01225 QMessageBox::Yes);
01226
01227 if (button == QMessageBox::Cancel) {
01228 return false;
01229 }
01230
01231 if (button == QMessageBox::Yes) {
01232 realign = true;
01233 }
01234 }
01235
01236 SparseTimeValueModel::EditCommand *command =
01237 new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
01238
01239 enum ValueAvailability {
01240 UnknownAvailability,
01241 NoValues,
01242 SomeValues,
01243 AllValues
01244 };
01245
01246 Labeller::ValueType generation = Labeller::ValueNone;
01247
01248 bool haveUsableLabels = false;
01249 bool haveExistingItems = !(m_model->isEmpty());
01250 Labeller labeller;
01251 labeller.setSampleRate(m_model->getSampleRate());
01252
01253 if (interactive) {
01254
01255 ValueAvailability availability = UnknownAvailability;
01256
01257 for (Clipboard::PointList::const_iterator i = points.begin();
01258 i != points.end(); ++i) {
01259
01260 if (!i->haveFrame()) continue;
01261
01262 if (availability == UnknownAvailability) {
01263 if (i->haveValue()) availability = AllValues;
01264 else availability = NoValues;
01265 continue;
01266 }
01267
01268 if (i->haveValue()) {
01269 if (availability == NoValues) {
01270 availability = SomeValues;
01271 }
01272 } else {
01273 if (availability == AllValues) {
01274 availability = SomeValues;
01275 }
01276 }
01277
01278 if (!haveUsableLabels) {
01279 if (i->haveLabel()) {
01280 if (i->getLabel().contains(QRegExp("[0-9]"))) {
01281 haveUsableLabels = true;
01282 }
01283 }
01284 }
01285
01286 if (availability == SomeValues && haveUsableLabels) break;
01287 }
01288
01289 if (availability == NoValues || availability == SomeValues) {
01290
01291 QString text;
01292 if (availability == NoValues) {
01293 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
01294 } else {
01295 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
01296 }
01297
01298 Labeller::TypeNameMap names = labeller.getTypeNames();
01299
01300 QStringList options;
01301 std::vector<Labeller::ValueType> genopts;
01302
01303 for (Labeller::TypeNameMap::const_iterator i = names.begin();
01304 i != names.end(); ++i) {
01305 if (i->first == Labeller::ValueNone) options << tr("Zero for all items");
01306 else options << i->second;
01307 genopts.push_back(i->first);
01308 }
01309
01310 static int prevSelection = 0;
01311
01312 bool ok = false;
01313 QString selected = ListInputDialog::getItem
01314 (0, tr("Choose value calculation"),
01315 text, options, prevSelection, &ok);
01316
01317 if (!ok) return false;
01318 int selection = 0;
01319 generation = Labeller::ValueNone;
01320
01321 for (QStringList::const_iterator i = options.begin();
01322 i != options.end(); ++i) {
01323 if (selected == *i) {
01324 generation = genopts[selection];
01325 break;
01326 }
01327 ++selection;
01328 }
01329
01330 labeller.setType(generation);
01331
01332 if (generation == Labeller::ValueFromCyclicalCounter ||
01333 generation == Labeller::ValueFromTwoLevelCounter) {
01334 int cycleSize = QInputDialog::getInteger
01335 (0, tr("Select cycle size"),
01336 tr("Cycle size:"), 4, 2, 16, 1);
01337 labeller.setCounterCycleSize(cycleSize);
01338 }
01339
01340 prevSelection = selection;
01341 }
01342 }
01343
01344 SparseTimeValueModel::Point prevPoint(0);
01345
01346 for (Clipboard::PointList::const_iterator i = points.begin();
01347 i != points.end(); ++i) {
01348
01349 if (!i->haveFrame()) continue;
01350
01351 size_t frame = 0;
01352
01353 if (!realign) {
01354
01355 frame = i->getFrame();
01356
01357 } else {
01358
01359 if (i->haveReferenceFrame()) {
01360 frame = i->getReferenceFrame();
01361 frame = alignFromReference(v, frame);
01362 } else {
01363 frame = i->getFrame();
01364 }
01365 }
01366
01367 SparseTimeValueModel::Point newPoint(frame);
01368
01369 if (i->haveLabel()) {
01370 newPoint.label = i->getLabel();
01371 } else if (i->haveValue()) {
01372 newPoint.label = QString("%1").arg(i->getValue());
01373 }
01374
01375 bool usePrev = false;
01376 SparseTimeValueModel::Point formerPrevPoint = prevPoint;
01377
01378 if (i->haveValue()) {
01379 newPoint.value = i->getValue();
01380 } else {
01381
01382
01383
01384
01385
01386
01387 labeller.setValue<SparseTimeValueModel::Point>
01388 (newPoint, (i == points.begin()) ? 0 : &prevPoint);
01389
01390 if (labeller.actingOnPrevPoint() && i != points.begin()) {
01391 usePrev = true;
01392 }
01393 }
01394
01395 if (usePrev) {
01396 command->deletePoint(formerPrevPoint);
01397 command->addPoint(prevPoint);
01398 }
01399
01400 prevPoint = newPoint;
01401 command->addPoint(newPoint);
01402 }
01403
01404 command->finish();
01405 return true;
01406 }
01407
01408 void
01409 TimeValueLayer::toXml(QTextStream &stream,
01410 QString indent, QString extraAttributes) const
01411 {
01412 SingleColourLayer::toXml(stream, indent,
01413 extraAttributes +
01414 QString(" colourMap=\"%1\" plotStyle=\"%2\" verticalScale=\"%3\"")
01415 .arg(m_colourMap)
01416 .arg(m_plotStyle)
01417 .arg(m_verticalScale));
01418 }
01419
01420 void
01421 TimeValueLayer::setProperties(const QXmlAttributes &attributes)
01422 {
01423 SingleColourLayer::setProperties(attributes);
01424
01425 bool ok;
01426
01427 int cmap = attributes.value("colourMap").toInt(&ok);
01428 if (ok) setFillColourMap(cmap);
01429
01430 PlotStyle style = (PlotStyle)
01431 attributes.value("plotStyle").toInt(&ok);
01432 if (ok) setPlotStyle(style);
01433
01434 VerticalScale scale = (VerticalScale)
01435 attributes.value("verticalScale").toInt(&ok);
01436 if (ok) setVerticalScale(scale);
01437 }
01438