TimeValueLayer.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
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" // for optional frequency alignment
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 //    std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl;
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     // We don't illuminate sections in the line or curve modes, so
00237     // they're always scrollable
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; // don't break, as the next may be better
00394             } else {
00395                 break;
00396             }
00397 
00398         } else { // nearest
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 //    std::cerr << "getYForValue(" << val << "): min " << min << ", max "
00471 //              << max << ", log " << logarithmic << std::endl;
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 //    std::cerr << "TimeValueLayer::getColourForValue: min " << min << ", max "
00522 //              << max << ", log " << log << ", value " << val << std::endl;
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 //    Profiler profiler("TimeValueLayer::paint", true);
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 //    std::cerr << "TimeValueLayer::paint: resolution is "
00563 //            << m_model->getResolution() << " frames" << std::endl;
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 //        std::cerr << "TimeValueLayer: " << localPoints.size() << " local points" << std::endl;
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 // m_model->getEndFrame());
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 //        std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext 
00628 //                  << ", nx = " << nx << std::endl;
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             //better to save the highlighted rects and draw them at
00660             //the end perhaps
00661 
00663             //or curve mode
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                         // // or
00716                         // path.quadTo(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
00717 
00718                     } else {
00719                         path.lineTo((x0 + x1) / 2, (y0 + y1) / 2);
00720                     }
00721                 }
00722             }
00723         }
00724 
00725         if (m_plotStyle == PlotSegmentation) {
00726 
00727 //            std::cerr << "drawing rect" << std::endl;
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     // looks like save/restore doesn't deal with this:
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 //    std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
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 //                std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
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 //    std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
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 //    std::cerr << points.size() << " points" << std::endl;
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             //    std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl;
00914                 continue;
00915             }
00916             if (((i->frame / resolution) * resolution) != frame) {
00917             //    std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
00918                 continue;
00919             }
00920         //    std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl;
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 //    m_editingCommand->deletePoint(m_editingPoint);
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 //    std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
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 //    std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
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 //    std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
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 //    std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
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 //            std::cerr << "Setting value on point at " << newPoint.frame << " from labeller";
01382 //            if (i == points.begin()) {
01383 //                std::cerr << ", no prev point" << std::endl;
01384 //            } else {
01385 //                std::cerr << ", prev point is at " << prevPoint.frame << std::endl;
01386 //            }
01387             labeller.setValue<SparseTimeValueModel::Point>
01388                 (newPoint, (i == points.begin()) ? 0 : &prevPoint);
01389 //            std::cerr << "New point value = " << newPoint.value << std::endl;
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 

Generated on Wed Feb 20 15:45:29 2008 for SonicVisualiser by  doxygen 1.5.1