annotate layer/TimeValueLayer.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents 0387f53242b2
children
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7 This file copyright 2006 Chris Cannam.
lbajardsilogic@0 8
lbajardsilogic@0 9 This program is free software; you can redistribute it and/or
lbajardsilogic@0 10 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 11 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 12 License, or (at your option) any later version. See the file
lbajardsilogic@0 13 COPYING included with this distribution for more information.
lbajardsilogic@0 14 */
lbajardsilogic@0 15
lbajardsilogic@0 16 #include "TimeValueLayer.h"
lbajardsilogic@0 17
lbajardsilogic@0 18 #include "system/System.h"
lbajardsilogic@0 19 #include "data/model/Model.h"
lbajardsilogic@0 20 #include "base/RealTime.h"
lbajardsilogic@0 21 #include "base/Profiler.h"
lbajardsilogic@0 22 #include "base/LogRange.h"
lbajardsilogic@0 23 #include "view/View.h"
lbajardsilogic@0 24
lbajardsilogic@0 25 #include "data/model/SparseTimeValueModel.h"
lbajardsilogic@0 26
lbajardsilogic@0 27 #include "widgets/ItemEditDialog.h"
lbajardsilogic@0 28 #include "widgets/ListInputDialog.h"
lbajardsilogic@0 29
lbajardsilogic@0 30 #include "SpectrogramLayer.h" // for optional frequency alignment
lbajardsilogic@0 31 #include "ColourMapper.h"
lbajardsilogic@0 32
lbajardsilogic@0 33 #include <QPainter>
lbajardsilogic@0 34 #include <QPainterPath>
lbajardsilogic@0 35 #include <QMouseEvent>
lbajardsilogic@0 36 #include <QRegExp>
lbajardsilogic@0 37
lbajardsilogic@0 38 #include <iostream>
lbajardsilogic@0 39 #include <cmath>
lbajardsilogic@0 40
lbajardsilogic@0 41 TimeValueLayer::TimeValueLayer() :
lbajardsilogic@0 42 Layer(),
lbajardsilogic@0 43 m_model(0),
lbajardsilogic@0 44 m_editing(false),
lbajardsilogic@0 45 m_originalPoint(0, 0.0, tr("New Point")),
lbajardsilogic@0 46 m_editingPoint(0, 0.0, tr("New Point")),
lbajardsilogic@0 47 m_editingCommand(0),
lbajardsilogic@0 48 m_colour(Qt::darkGreen),
lbajardsilogic@0 49 m_colourMap(0),
lbajardsilogic@0 50 m_plotStyle(PlotConnectedPoints),
lbajardsilogic@0 51 m_verticalScale(AutoAlignScale)
lbajardsilogic@0 52 {
lbajardsilogic@0 53
lbajardsilogic@0 54 }
lbajardsilogic@0 55
lbajardsilogic@0 56 void
lbajardsilogic@0 57 TimeValueLayer::setModel(SparseTimeValueModel *model)
lbajardsilogic@0 58 {
lbajardsilogic@0 59 if (m_model == model) return;
lbajardsilogic@0 60 m_model = model;
lbajardsilogic@0 61
lbajardsilogic@0 62 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged()));
lbajardsilogic@0 63 connect(m_model, SIGNAL(modelChanged(size_t, size_t)),
lbajardsilogic@0 64 this, SIGNAL(modelChanged(size_t, size_t)));
lbajardsilogic@0 65
lbajardsilogic@0 66 connect(m_model, SIGNAL(completionChanged()),
lbajardsilogic@0 67 this, SIGNAL(modelCompletionChanged()));
lbajardsilogic@0 68
lbajardsilogic@0 69 // std::cerr << "TimeValueLayer::setModel(" << model << ")" << std::endl;
lbajardsilogic@0 70
lbajardsilogic@0 71 emit modelReplaced();
lbajardsilogic@0 72 }
lbajardsilogic@0 73
lbajardsilogic@0 74 Layer::PropertyList
lbajardsilogic@0 75 TimeValueLayer::getProperties() const
lbajardsilogic@0 76 {
lbajardsilogic@0 77 PropertyList list;
lbajardsilogic@0 78 list.push_back("Colour");
lbajardsilogic@0 79 list.push_back("Plot Type");
lbajardsilogic@0 80 list.push_back("Vertical Scale");
lbajardsilogic@0 81 list.push_back("Scale Units");
lbajardsilogic@0 82 return list;
lbajardsilogic@0 83 }
lbajardsilogic@0 84
lbajardsilogic@0 85 QString
lbajardsilogic@0 86 TimeValueLayer::getPropertyLabel(const PropertyName &name) const
lbajardsilogic@0 87 {
lbajardsilogic@0 88 if (name == "Colour") return tr("Colour");
lbajardsilogic@0 89 if (name == "Plot Type") return tr("Plot Type");
lbajardsilogic@0 90 if (name == "Vertical Scale") return tr("Vertical Scale");
lbajardsilogic@0 91 if (name == "Scale Units") return tr("Scale Units");
lbajardsilogic@0 92 return "";
lbajardsilogic@0 93 }
lbajardsilogic@0 94
lbajardsilogic@0 95 Layer::PropertyType
lbajardsilogic@0 96 TimeValueLayer::getPropertyType(const PropertyName &name) const
lbajardsilogic@0 97 {
lbajardsilogic@0 98 if (name == "Scale Units") return UnitsProperty;
lbajardsilogic@0 99 else return ValueProperty;
lbajardsilogic@0 100 }
lbajardsilogic@0 101
lbajardsilogic@0 102 QString
lbajardsilogic@0 103 TimeValueLayer::getPropertyGroupName(const PropertyName &name) const
lbajardsilogic@0 104 {
lbajardsilogic@0 105 if (name == "Vertical Scale" || name == "Scale Units") {
lbajardsilogic@0 106 return tr("Scale");
lbajardsilogic@0 107 }
lbajardsilogic@0 108 return QString();
lbajardsilogic@0 109 }
lbajardsilogic@0 110
lbajardsilogic@0 111 int
lbajardsilogic@0 112 TimeValueLayer::getPropertyRangeAndValue(const PropertyName &name,
lbajardsilogic@0 113 int *min, int *max, int *deflt) const
lbajardsilogic@0 114 {
lbajardsilogic@0 115 //!!! factor this colour handling stuff out into a colour manager class
lbajardsilogic@0 116
lbajardsilogic@0 117 int val = 0;
lbajardsilogic@0 118
lbajardsilogic@0 119 if (name == "Colour") {
lbajardsilogic@0 120
lbajardsilogic@0 121 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 122
lbajardsilogic@0 123 if (min) *min = 0;
lbajardsilogic@0 124 if (max) *max = ColourMapper::getColourMapCount() - 1;
lbajardsilogic@0 125 if (deflt) *deflt = 0;
lbajardsilogic@0 126
lbajardsilogic@0 127 val = m_colourMap;
lbajardsilogic@0 128
lbajardsilogic@0 129 } else {
lbajardsilogic@0 130
lbajardsilogic@0 131 if (min) *min = 0;
lbajardsilogic@0 132 if (max) *max = 5;
lbajardsilogic@0 133 if (deflt) *deflt = 0;
lbajardsilogic@0 134
lbajardsilogic@0 135 if (m_colour == Qt::black) val = 0;
lbajardsilogic@0 136 else if (m_colour == Qt::darkRed) val = 1;
lbajardsilogic@0 137 else if (m_colour == Qt::darkBlue) val = 2;
lbajardsilogic@0 138 else if (m_colour == Qt::darkGreen) val = 3;
lbajardsilogic@0 139 else if (m_colour == QColor(200, 50, 255)) val = 4;
lbajardsilogic@0 140 else if (m_colour == QColor(255, 150, 50)) val = 5;
lbajardsilogic@0 141 }
lbajardsilogic@0 142
lbajardsilogic@0 143 } else if (name == "Plot Type") {
lbajardsilogic@0 144
lbajardsilogic@0 145 if (min) *min = 0;
lbajardsilogic@0 146 if (max) *max = 5;
lbajardsilogic@0 147 if (deflt) *deflt = int(PlotConnectedPoints);
lbajardsilogic@0 148
lbajardsilogic@0 149 val = int(m_plotStyle);
lbajardsilogic@0 150
lbajardsilogic@0 151 } else if (name == "Vertical Scale") {
lbajardsilogic@0 152
lbajardsilogic@0 153 if (min) *min = 0;
lbajardsilogic@0 154 if (max) *max = 3;
lbajardsilogic@0 155 if (deflt) *deflt = int(AutoAlignScale);
lbajardsilogic@0 156
lbajardsilogic@0 157 val = int(m_verticalScale);
lbajardsilogic@0 158
lbajardsilogic@0 159 } else if (name == "Scale Units") {
lbajardsilogic@0 160
lbajardsilogic@0 161 if (deflt) *deflt = 0;
lbajardsilogic@0 162 if (m_model) {
lbajardsilogic@0 163 val = UnitDatabase::getInstance()->getUnitId
lbajardsilogic@0 164 (m_model->getScaleUnits());
lbajardsilogic@0 165 }
lbajardsilogic@0 166
lbajardsilogic@0 167 } else {
lbajardsilogic@0 168
lbajardsilogic@0 169 val = Layer::getPropertyRangeAndValue(name, min, max, deflt);
lbajardsilogic@0 170 }
lbajardsilogic@0 171
lbajardsilogic@0 172 return val;
lbajardsilogic@0 173 }
lbajardsilogic@0 174
lbajardsilogic@0 175 QString
lbajardsilogic@0 176 TimeValueLayer::getPropertyValueLabel(const PropertyName &name,
lbajardsilogic@0 177 int value) const
lbajardsilogic@0 178 {
lbajardsilogic@0 179 if (name == "Colour") {
lbajardsilogic@0 180 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 181 return ColourMapper::getColourMapName(value);
lbajardsilogic@0 182 } else {
lbajardsilogic@0 183 switch (value) {
lbajardsilogic@0 184 default:
lbajardsilogic@0 185 case 0: return tr("Black");
lbajardsilogic@0 186 case 1: return tr("Red");
lbajardsilogic@0 187 case 2: return tr("Blue");
lbajardsilogic@0 188 case 3: return tr("Green");
lbajardsilogic@0 189 case 4: return tr("Purple");
lbajardsilogic@0 190 case 5: return tr("Orange");
lbajardsilogic@0 191 }
lbajardsilogic@0 192 }
lbajardsilogic@0 193 } else if (name == "Plot Type") {
lbajardsilogic@0 194 switch (value) {
lbajardsilogic@0 195 default:
lbajardsilogic@0 196 case 0: return tr("Points");
lbajardsilogic@0 197 case 1: return tr("Stems");
lbajardsilogic@0 198 case 2: return tr("Connected Points");
lbajardsilogic@0 199 case 3: return tr("Lines");
lbajardsilogic@0 200 case 4: return tr("Curve");
lbajardsilogic@0 201 case 5: return tr("Segmentation");
lbajardsilogic@0 202 }
lbajardsilogic@0 203 } else if (name == "Vertical Scale") {
lbajardsilogic@0 204 switch (value) {
lbajardsilogic@0 205 default:
lbajardsilogic@0 206 case 0: return tr("Auto-Align");
lbajardsilogic@0 207 case 1: return tr("Linear");
lbajardsilogic@0 208 case 2: return tr("Log");
lbajardsilogic@0 209 case 3: return tr("+/-1");
lbajardsilogic@0 210 }
lbajardsilogic@0 211 }
lbajardsilogic@0 212 return tr("<unknown>");
lbajardsilogic@0 213 }
lbajardsilogic@0 214
lbajardsilogic@0 215 void
lbajardsilogic@0 216 TimeValueLayer::setProperty(const PropertyName &name, int value)
lbajardsilogic@0 217 {
lbajardsilogic@0 218 if (name == "Colour") {
lbajardsilogic@0 219 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 220 setFillColourMap(value);
lbajardsilogic@0 221 } else {
lbajardsilogic@0 222 switch (value) {
lbajardsilogic@0 223 default:
lbajardsilogic@0 224 case 0: setBaseColour(Qt::black); break;
lbajardsilogic@0 225 case 1: setBaseColour(Qt::darkRed); break;
lbajardsilogic@0 226 case 2: setBaseColour(Qt::darkBlue); break;
lbajardsilogic@0 227 case 3: setBaseColour(Qt::darkGreen); break;
lbajardsilogic@0 228 case 4: setBaseColour(QColor(200, 50, 255)); break;
lbajardsilogic@0 229 case 5: setBaseColour(QColor(255, 150, 50)); break;
lbajardsilogic@0 230 }
lbajardsilogic@0 231 }
lbajardsilogic@0 232 } else if (name == "Plot Type") {
lbajardsilogic@0 233 setPlotStyle(PlotStyle(value));
lbajardsilogic@0 234 } else if (name == "Vertical Scale") {
lbajardsilogic@0 235 setVerticalScale(VerticalScale(value));
lbajardsilogic@0 236 } else if (name == "Scale Units") {
lbajardsilogic@0 237 if (m_model) {
lbajardsilogic@0 238 m_model->setScaleUnits
lbajardsilogic@0 239 (UnitDatabase::getInstance()->getUnitById(value));
lbajardsilogic@0 240 emit modelChanged();
lbajardsilogic@0 241 }
lbajardsilogic@0 242 }
lbajardsilogic@0 243 }
lbajardsilogic@0 244
benoitrigolleau@61 245 void
lbajardsilogic@0 246 TimeValueLayer::setBaseColour(QColor colour)
lbajardsilogic@0 247 {
lbajardsilogic@0 248 if (m_colour == colour) return;
lbajardsilogic@0 249 m_colour = colour;
lbajardsilogic@0 250 emit layerParametersChanged();
lbajardsilogic@0 251 }
lbajardsilogic@0 252
lbajardsilogic@0 253 void
lbajardsilogic@0 254 TimeValueLayer::setFillColourMap(int map)
lbajardsilogic@0 255 {
lbajardsilogic@0 256 if (m_colourMap == map) return;
lbajardsilogic@0 257 m_colourMap = map;
lbajardsilogic@0 258 emit layerParametersChanged();
lbajardsilogic@0 259 }
lbajardsilogic@0 260
lbajardsilogic@0 261 void
lbajardsilogic@0 262 TimeValueLayer::setPlotStyle(PlotStyle style)
lbajardsilogic@0 263 {
lbajardsilogic@0 264 if (m_plotStyle == style) return;
lbajardsilogic@0 265 bool colourTypeChanged = (style == PlotSegmentation ||
lbajardsilogic@0 266 m_plotStyle == PlotSegmentation);
lbajardsilogic@0 267 m_plotStyle = style;
lbajardsilogic@0 268 if (colourTypeChanged) {
lbajardsilogic@0 269 emit layerParameterRangesChanged();
lbajardsilogic@0 270 }
lbajardsilogic@0 271 emit layerParametersChanged();
lbajardsilogic@0 272 }
lbajardsilogic@0 273
lbajardsilogic@0 274 void
lbajardsilogic@0 275 TimeValueLayer::setVerticalScale(VerticalScale scale)
lbajardsilogic@0 276 {
lbajardsilogic@0 277 if (m_verticalScale == scale) return;
lbajardsilogic@0 278 m_verticalScale = scale;
lbajardsilogic@0 279 emit layerParametersChanged();
lbajardsilogic@0 280 }
lbajardsilogic@0 281
lbajardsilogic@0 282 bool
lbajardsilogic@0 283 TimeValueLayer::isLayerScrollable(const View *v) const
lbajardsilogic@0 284 {
lbajardsilogic@0 285 // We don't illuminate sections in the line or curve modes, so
lbajardsilogic@0 286 // they're always scrollable
lbajardsilogic@0 287
lbajardsilogic@0 288 if (m_plotStyle == PlotLines ||
lbajardsilogic@0 289 m_plotStyle == PlotCurve) return true;
lbajardsilogic@0 290
lbajardsilogic@0 291 QPoint discard;
lbajardsilogic@0 292 return !v->shouldIlluminateLocalFeatures(this, discard);
lbajardsilogic@0 293 }
lbajardsilogic@0 294
lbajardsilogic@0 295 bool
lbajardsilogic@0 296 TimeValueLayer::getValueExtents(float &min, float &max,
lbajardsilogic@0 297 bool &logarithmic, QString &unit) const
lbajardsilogic@0 298 {
lbajardsilogic@0 299 if (!m_model) return false;
lbajardsilogic@0 300 min = m_model->getValueMinimum();
lbajardsilogic@0 301 max = m_model->getValueMaximum();
lbajardsilogic@0 302 logarithmic = (m_verticalScale == LogScale);
lbajardsilogic@0 303 unit = m_model->getScaleUnits();
lbajardsilogic@0 304 return true;
lbajardsilogic@0 305 }
lbajardsilogic@0 306
lbajardsilogic@0 307 bool
lbajardsilogic@0 308 TimeValueLayer::getDisplayExtents(float &min, float &max) const
lbajardsilogic@0 309 {
lbajardsilogic@0 310 if (!m_model || m_verticalScale == AutoAlignScale) return false;
lbajardsilogic@0 311
lbajardsilogic@0 312 min = m_model->getValueMinimum();
lbajardsilogic@0 313 max = m_model->getValueMaximum();
lbajardsilogic@0 314 return true;
lbajardsilogic@0 315 }
lbajardsilogic@0 316
lbajardsilogic@0 317 SparseTimeValueModel::PointList
lbajardsilogic@0 318 TimeValueLayer::getLocalPoints(View *v, int x) const
lbajardsilogic@0 319 {
lbajardsilogic@0 320 if (!m_model) return SparseTimeValueModel::PointList();
lbajardsilogic@0 321
lbajardsilogic@0 322 long frame = v->getFrameForX(x);
lbajardsilogic@0 323
lbajardsilogic@0 324 SparseTimeValueModel::PointList onPoints =
lbajardsilogic@0 325 m_model->getPoints(frame);
lbajardsilogic@0 326
lbajardsilogic@0 327 if (!onPoints.empty()) {
lbajardsilogic@0 328 return onPoints;
lbajardsilogic@0 329 }
lbajardsilogic@0 330
lbajardsilogic@0 331 SparseTimeValueModel::PointList prevPoints =
lbajardsilogic@0 332 m_model->getPreviousPoints(frame);
lbajardsilogic@0 333 SparseTimeValueModel::PointList nextPoints =
lbajardsilogic@0 334 m_model->getNextPoints(frame);
lbajardsilogic@0 335
lbajardsilogic@0 336 SparseTimeValueModel::PointList usePoints = prevPoints;
lbajardsilogic@0 337
lbajardsilogic@34 338 if (! nextPoints.empty())
lbajardsilogic@34 339 {
lbajardsilogic@34 340 if (prevPoints.empty()) {
lbajardsilogic@34 341 usePoints = nextPoints;
lbajardsilogic@34 342 } else if (long(prevPoints.begin()->frame) < v->getStartFrame() &&
lbajardsilogic@34 343 !(nextPoints.begin()->frame > v->getEndFrame())) {
lbajardsilogic@34 344 usePoints = nextPoints;
lbajardsilogic@34 345 } else if (nextPoints.begin()->frame - frame <
lbajardsilogic@34 346 frame - prevPoints.begin()->frame) {
lbajardsilogic@34 347 usePoints = nextPoints;
lbajardsilogic@34 348 }
lbajardsilogic@34 349 }
lbajardsilogic@0 350
lbajardsilogic@0 351 if (!usePoints.empty()) {
lbajardsilogic@0 352 int fuzz = 2;
lbajardsilogic@0 353 int px = v->getXForFrame(usePoints.begin()->frame);
lbajardsilogic@0 354 if ((px > x && px - x > fuzz) ||
lbajardsilogic@0 355 (px < x && x - px > fuzz + 1)) {
lbajardsilogic@0 356 usePoints.clear();
lbajardsilogic@0 357 }
lbajardsilogic@0 358 }
lbajardsilogic@0 359
lbajardsilogic@0 360 return usePoints;
lbajardsilogic@0 361 }
lbajardsilogic@0 362
lbajardsilogic@0 363 QString
lbajardsilogic@0 364 TimeValueLayer::getFeatureDescription(View *v, QPoint &pos) const
lbajardsilogic@0 365 {
lbajardsilogic@0 366 int x = pos.x();
lbajardsilogic@0 367
lbajardsilogic@0 368 if (!m_model || !m_model->getSampleRate()) return "";
lbajardsilogic@0 369
lbajardsilogic@0 370 SparseTimeValueModel::PointList points = getLocalPoints(v, x);
lbajardsilogic@0 371
lbajardsilogic@0 372 if (points.empty()) {
lbajardsilogic@0 373 if (!m_model->isReady()) {
lbajardsilogic@0 374 return tr("In progress");
lbajardsilogic@0 375 } else {
lbajardsilogic@0 376 return tr("No local points");
lbajardsilogic@0 377 }
lbajardsilogic@0 378 }
lbajardsilogic@0 379
lbajardsilogic@0 380 long useFrame = points.begin()->frame;
lbajardsilogic@0 381
lbajardsilogic@0 382 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate());
lbajardsilogic@0 383
lbajardsilogic@0 384 QString text;
lbajardsilogic@0 385 QString unit = m_model->getScaleUnits();
lbajardsilogic@0 386 if (unit != "") unit = " " + unit;
lbajardsilogic@0 387
lbajardsilogic@0 388 if (points.begin()->label == "") {
lbajardsilogic@0 389 text = QString(tr("Time:\t%1\nValue:\t%2%3\nNo label"))
lbajardsilogic@0 390 .arg(rt.toText(true).c_str())
lbajardsilogic@0 391 .arg(points.begin()->value)
lbajardsilogic@0 392 .arg(unit);
lbajardsilogic@0 393 } else {
lbajardsilogic@0 394 text = QString(tr("Time:\t%1\nValue:\t%2%3\nLabel:\t%4"))
lbajardsilogic@0 395 .arg(rt.toText(true).c_str())
lbajardsilogic@0 396 .arg(points.begin()->value)
lbajardsilogic@0 397 .arg(unit)
lbajardsilogic@0 398 .arg(points.begin()->label);
lbajardsilogic@0 399 }
lbajardsilogic@0 400
lbajardsilogic@0 401 pos = QPoint(v->getXForFrame(useFrame),
lbajardsilogic@0 402 getYForValue(v, points.begin()->value));
lbajardsilogic@0 403 return text;
lbajardsilogic@0 404 }
lbajardsilogic@0 405
lbajardsilogic@0 406 bool
lbajardsilogic@0 407 TimeValueLayer::snapToFeatureFrame(View *v, int &frame,
lbajardsilogic@0 408 size_t &resolution,
lbajardsilogic@0 409 SnapType snap) const
lbajardsilogic@0 410 {
lbajardsilogic@0 411 if (!m_model) {
lbajardsilogic@0 412 return Layer::snapToFeatureFrame(v, frame, resolution, snap);
lbajardsilogic@0 413 }
lbajardsilogic@0 414
lbajardsilogic@0 415 resolution = m_model->getResolution();
lbajardsilogic@0 416 SparseTimeValueModel::PointList points;
lbajardsilogic@0 417
lbajardsilogic@0 418 if (snap == SnapNeighbouring) {
lbajardsilogic@0 419
lbajardsilogic@0 420 points = getLocalPoints(v, v->getXForFrame(frame));
lbajardsilogic@0 421 if (points.empty()) return false;
lbajardsilogic@0 422 frame = points.begin()->frame;
lbajardsilogic@0 423 return true;
lbajardsilogic@0 424 }
lbajardsilogic@0 425
lbajardsilogic@0 426 points = m_model->getPoints(frame, frame);
lbajardsilogic@0 427 int snapped = frame;
lbajardsilogic@0 428 bool found = false;
lbajardsilogic@0 429
lbajardsilogic@0 430 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 431 i != points.end(); ++i) {
lbajardsilogic@0 432
lbajardsilogic@0 433 if (snap == SnapRight) {
lbajardsilogic@0 434
lbajardsilogic@0 435 if (i->frame > frame) {
lbajardsilogic@0 436 snapped = i->frame;
lbajardsilogic@0 437 found = true;
lbajardsilogic@0 438 break;
lbajardsilogic@0 439 }
lbajardsilogic@0 440
lbajardsilogic@0 441 } else if (snap == SnapLeft) {
lbajardsilogic@0 442
lbajardsilogic@0 443 if (i->frame <= frame) {
lbajardsilogic@0 444 snapped = i->frame;
lbajardsilogic@0 445 found = true; // don't break, as the next may be better
lbajardsilogic@0 446 } else {
lbajardsilogic@0 447 break;
lbajardsilogic@0 448 }
lbajardsilogic@0 449
lbajardsilogic@0 450 } else { // nearest
lbajardsilogic@0 451
lbajardsilogic@0 452 SparseTimeValueModel::PointList::const_iterator j = i;
lbajardsilogic@0 453 ++j;
lbajardsilogic@0 454
lbajardsilogic@0 455 if (j == points.end()) {
lbajardsilogic@0 456
lbajardsilogic@0 457 snapped = i->frame;
lbajardsilogic@0 458 found = true;
lbajardsilogic@0 459 break;
lbajardsilogic@0 460
lbajardsilogic@0 461 } else if (j->frame >= frame) {
lbajardsilogic@0 462
lbajardsilogic@0 463 if (j->frame - frame < frame - i->frame) {
lbajardsilogic@0 464 snapped = j->frame;
lbajardsilogic@0 465 } else {
lbajardsilogic@0 466 snapped = i->frame;
lbajardsilogic@0 467 }
lbajardsilogic@0 468 found = true;
lbajardsilogic@0 469 break;
lbajardsilogic@0 470 }
lbajardsilogic@0 471 }
lbajardsilogic@0 472 }
lbajardsilogic@0 473
lbajardsilogic@0 474 frame = snapped;
lbajardsilogic@0 475 return found;
lbajardsilogic@0 476 }
lbajardsilogic@0 477
lbajardsilogic@0 478 void
lbajardsilogic@0 479 TimeValueLayer::getScaleExtents(View *v, float &min, float &max, bool &log) const
lbajardsilogic@0 480 {
lbajardsilogic@0 481 min = 0.0;
lbajardsilogic@0 482 max = 0.0;
lbajardsilogic@0 483 log = false;
lbajardsilogic@0 484
lbajardsilogic@0 485 if (m_verticalScale == AutoAlignScale) {
lbajardsilogic@0 486
lbajardsilogic@0 487 if (!v->getValueExtents(m_model->getScaleUnits(), min, max, log)) {
lbajardsilogic@0 488 min = m_model->getValueMinimum();
lbajardsilogic@0 489 max = m_model->getValueMaximum();
lbajardsilogic@0 490 } else if (log) {
lbajardsilogic@0 491 LogRange::mapRange(min, max);
lbajardsilogic@0 492 }
lbajardsilogic@0 493
lbajardsilogic@0 494 } else if (m_verticalScale == PlusMinusOneScale) {
lbajardsilogic@0 495
lbajardsilogic@0 496 min = -1.0;
lbajardsilogic@0 497 max = 1.0;
lbajardsilogic@0 498
lbajardsilogic@0 499 } else {
lbajardsilogic@0 500
lbajardsilogic@0 501 min = m_model->getValueMinimum();
lbajardsilogic@0 502 max = m_model->getValueMaximum();
lbajardsilogic@0 503
lbajardsilogic@0 504 if (m_verticalScale == LogScale) {
lbajardsilogic@0 505 LogRange::mapRange(min, max);
lbajardsilogic@0 506 log = true;
lbajardsilogic@0 507 }
lbajardsilogic@0 508 }
lbajardsilogic@0 509
lbajardsilogic@0 510 if (max == min) max = min + 1.0;
lbajardsilogic@0 511 }
lbajardsilogic@0 512
lbajardsilogic@0 513 int
lbajardsilogic@0 514 TimeValueLayer::getYForValue(View *v, float val) const
lbajardsilogic@0 515 {
lbajardsilogic@0 516 float min = 0.0, max = 0.0;
lbajardsilogic@0 517 bool logarithmic = false;
lbajardsilogic@0 518 int h = v->height();
lbajardsilogic@0 519
lbajardsilogic@0 520 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 521
lbajardsilogic@0 522 // std::cerr << "getYForValue(" << val << "): min " << min << ", max "
lbajardsilogic@0 523 // << max << ", log " << logarithmic << std::endl;
lbajardsilogic@0 524
lbajardsilogic@0 525 if (logarithmic) {
lbajardsilogic@0 526 val = LogRange::map(val);
lbajardsilogic@0 527 }
lbajardsilogic@0 528
lbajardsilogic@0 529 return int(h - ((val - min) * h) / (max - min));
lbajardsilogic@0 530 }
lbajardsilogic@0 531
lbajardsilogic@0 532 float
lbajardsilogic@0 533 TimeValueLayer::getValueForY(View *v, int y) const
lbajardsilogic@0 534 {
lbajardsilogic@0 535 float min = 0.0, max = 0.0;
lbajardsilogic@0 536 bool logarithmic = false;
lbajardsilogic@0 537 int h = v->height();
lbajardsilogic@0 538
lbajardsilogic@0 539 getScaleExtents(v, min, max, logarithmic);
lbajardsilogic@0 540
lbajardsilogic@0 541 float val = min + (float(h - y) * float(max - min)) / h;
lbajardsilogic@0 542
lbajardsilogic@0 543 if (logarithmic) {
lbajardsilogic@0 544 val = powf(10.f, val);
lbajardsilogic@0 545 }
lbajardsilogic@0 546
lbajardsilogic@0 547 return val;
lbajardsilogic@0 548 }
lbajardsilogic@0 549
lbajardsilogic@0 550 QColor
lbajardsilogic@0 551 TimeValueLayer::getColourForValue(View *v, float val) const
lbajardsilogic@0 552 {
lbajardsilogic@0 553 float min, max;
lbajardsilogic@0 554 bool log;
lbajardsilogic@0 555 getScaleExtents(v, min, max, log);
lbajardsilogic@0 556
lbajardsilogic@0 557 if (min > max) std::swap(min, max);
lbajardsilogic@0 558 if (max == min) max = min + 1;
lbajardsilogic@0 559
lbajardsilogic@0 560 if (log) {
lbajardsilogic@0 561 LogRange::mapRange(min, max);
lbajardsilogic@0 562 val = LogRange::map(val);
lbajardsilogic@0 563 }
lbajardsilogic@0 564
lbajardsilogic@0 565 // std::cerr << "TimeValueLayer::getColourForValue: min " << min << ", max "
lbajardsilogic@0 566 // << max << ", log " << log << ", value " << val << std::endl;
lbajardsilogic@0 567
lbajardsilogic@0 568 QColor solid = ColourMapper(m_colourMap, min, max).map(val);
lbajardsilogic@0 569 return QColor(solid.red(), solid.green(), solid.blue(), 120);
lbajardsilogic@0 570 }
lbajardsilogic@0 571
lbajardsilogic@0 572 void
lbajardsilogic@0 573 TimeValueLayer::paint(View *v, QPainter &paint, QRect rect) const
lbajardsilogic@0 574 {
lbajardsilogic@0 575 if (!m_model || !m_model->isOK()) return;
lbajardsilogic@0 576
lbajardsilogic@0 577 int sampleRate = m_model->getSampleRate();
lbajardsilogic@0 578 if (!sampleRate) return;
lbajardsilogic@0 579
lbajardsilogic@0 580 // Profiler profiler("TimeValueLayer::paint", true);
lbajardsilogic@0 581
lbajardsilogic@0 582 int x0 = rect.left(), x1 = rect.right();
lbajardsilogic@0 583 long frame0 = v->getFrameForX(x0);
lbajardsilogic@0 584 long frame1 = v->getFrameForX(x1);
lbajardsilogic@0 585
lbajardsilogic@0 586 SparseTimeValueModel::PointList points(m_model->getPoints
lbajardsilogic@0 587 (frame0, frame1));
lbajardsilogic@0 588 if (points.empty()) return;
lbajardsilogic@0 589
lbajardsilogic@0 590 paint.setPen(m_colour);
lbajardsilogic@0 591
lbajardsilogic@0 592 QColor brushColour(m_colour);
lbajardsilogic@0 593 brushColour.setAlpha(80);
lbajardsilogic@0 594 paint.setBrush(brushColour);
lbajardsilogic@0 595
lbajardsilogic@0 596 // std::cerr << "TimeValueLayer::paint: resolution is "
lbajardsilogic@0 597 // << m_model->getResolution() << " frames" << std::endl;
lbajardsilogic@0 598
lbajardsilogic@0 599 float min = m_model->getValueMinimum();
lbajardsilogic@0 600 float max = m_model->getValueMaximum();
lbajardsilogic@0 601 if (max == min) max = min + 1.0;
lbajardsilogic@0 602
lbajardsilogic@0 603 int origin = int(nearbyint(v->height() -
lbajardsilogic@0 604 (-min * v->height()) / (max - min)));
lbajardsilogic@0 605
lbajardsilogic@0 606 QPoint localPos;
lbajardsilogic@0 607 long illuminateFrame = -1;
lbajardsilogic@0 608
lbajardsilogic@0 609 if (v->shouldIlluminateLocalFeatures(this, localPos)) {
lbajardsilogic@0 610 SparseTimeValueModel::PointList localPoints =
lbajardsilogic@0 611 getLocalPoints(v, localPos.x());
lbajardsilogic@0 612 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame;
lbajardsilogic@0 613 }
lbajardsilogic@0 614
lbajardsilogic@0 615 int w =
lbajardsilogic@0 616 v->getXForFrame(frame0 + m_model->getResolution()) -
lbajardsilogic@0 617 v->getXForFrame(frame0);
lbajardsilogic@0 618
lbajardsilogic@0 619 paint.save();
lbajardsilogic@0 620
lbajardsilogic@0 621 QPainterPath path;
lbajardsilogic@0 622 int pointCount = 0;
lbajardsilogic@0 623
lbajardsilogic@0 624 int textY = 0;
lbajardsilogic@0 625 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 626 textY = v->getTextLabelHeight(this, paint);
lbajardsilogic@0 627 }
lbajardsilogic@0 628
lbajardsilogic@0 629 for (SparseTimeValueModel::PointList::const_iterator i = points.begin();
lbajardsilogic@0 630 i != points.end(); ++i) {
lbajardsilogic@0 631
lbajardsilogic@0 632 const SparseTimeValueModel::Point &p(*i);
lbajardsilogic@0 633
lbajardsilogic@0 634 int x = v->getXForFrame(p.frame);
lbajardsilogic@0 635 int y = getYForValue(v, p.value);
lbajardsilogic@0 636
lbajardsilogic@0 637 if (m_plotStyle != PlotSegmentation) {
lbajardsilogic@0 638 textY = y - paint.fontMetrics().height()
lbajardsilogic@0 639 + paint.fontMetrics().ascent();
lbajardsilogic@0 640 }
lbajardsilogic@0 641
lbajardsilogic@0 642 bool haveNext = false;
lbajardsilogic@0 643 int nx = v->getXForFrame(v->getModelsEndFrame());
lbajardsilogic@0 644 // m_model->getEndFrame());
lbajardsilogic@0 645 int ny = y;
lbajardsilogic@0 646
lbajardsilogic@0 647 SparseTimeValueModel::PointList::const_iterator j = i;
lbajardsilogic@0 648 ++j;
lbajardsilogic@0 649
lbajardsilogic@0 650 if (j != points.end()) {
lbajardsilogic@0 651 const SparseTimeValueModel::Point &q(*j);
lbajardsilogic@0 652 nx = v->getXForFrame(q.frame);
lbajardsilogic@0 653 ny = getYForValue(v, q.value);
lbajardsilogic@0 654 haveNext = true;
lbajardsilogic@0 655 }
lbajardsilogic@0 656
lbajardsilogic@0 657 // std::cout << "frame = " << p.frame << ", x = " << x << ", haveNext = " << haveNext
lbajardsilogic@0 658 // << ", nx = " << nx << std::endl;
lbajardsilogic@0 659
lbajardsilogic@0 660 int labelY = y;
lbajardsilogic@0 661
lbajardsilogic@0 662 if (w < 1) w = 1;
lbajardsilogic@0 663 paint.setPen(m_colour);
lbajardsilogic@0 664
lbajardsilogic@0 665 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 666 paint.setPen(Qt::black);
lbajardsilogic@0 667 paint.setBrush(getColourForValue(v, p.value));
lbajardsilogic@0 668 labelY = v->height();
lbajardsilogic@0 669 } else if (m_plotStyle == PlotLines ||
lbajardsilogic@0 670 m_plotStyle == PlotCurve) {
lbajardsilogic@0 671 paint.setBrush(Qt::NoBrush);
lbajardsilogic@0 672 } else {
lbajardsilogic@0 673 paint.setBrush(brushColour);
lbajardsilogic@0 674 }
lbajardsilogic@0 675
lbajardsilogic@0 676 if (m_plotStyle == PlotStems) {
lbajardsilogic@0 677 paint.setPen(brushColour);
lbajardsilogic@0 678 if (y < origin - 1) {
lbajardsilogic@0 679 paint.drawRect(x + w/2, y + 1, 1, origin - y);
lbajardsilogic@0 680 } else if (y > origin + 1) {
lbajardsilogic@0 681 paint.drawRect(x + w/2, origin, 1, y - origin - 1);
lbajardsilogic@0 682 }
lbajardsilogic@0 683 paint.setPen(m_colour);
lbajardsilogic@0 684 }
lbajardsilogic@0 685
lbajardsilogic@0 686 if (illuminateFrame == p.frame) {
lbajardsilogic@0 687
lbajardsilogic@0 688 //!!! aside from the problem of choosing a colour, it'd be
lbajardsilogic@0 689 //better to save the highlighted rects and draw them at
lbajardsilogic@0 690 //the end perhaps
lbajardsilogic@0 691
lbajardsilogic@0 692 //!!! not equipped to illuminate the right section in line
lbajardsilogic@0 693 //or curve mode
lbajardsilogic@0 694
lbajardsilogic@0 695 if (m_plotStyle != PlotCurve &&
lbajardsilogic@0 696 m_plotStyle != PlotLines) {
lbajardsilogic@0 697 paint.setPen(Qt::black);//!!!
lbajardsilogic@0 698 if (m_plotStyle != PlotSegmentation) {
lbajardsilogic@0 699 paint.setBrush(Qt::black);//!!!
lbajardsilogic@0 700 }
lbajardsilogic@0 701 }
lbajardsilogic@0 702 }
lbajardsilogic@0 703
lbajardsilogic@0 704 if (m_plotStyle != PlotLines &&
lbajardsilogic@0 705 m_plotStyle != PlotCurve &&
lbajardsilogic@0 706 m_plotStyle != PlotSegmentation) {
lbajardsilogic@0 707 paint.drawRect(x, y - 1, w, 2);
lbajardsilogic@0 708 }
lbajardsilogic@0 709
lbajardsilogic@0 710 if (m_plotStyle == PlotConnectedPoints ||
lbajardsilogic@0 711 m_plotStyle == PlotLines ||
lbajardsilogic@0 712 m_plotStyle == PlotCurve) {
lbajardsilogic@0 713
lbajardsilogic@0 714 if (haveNext) {
lbajardsilogic@0 715
lbajardsilogic@0 716 if (m_plotStyle == PlotConnectedPoints) {
lbajardsilogic@0 717
lbajardsilogic@0 718 paint.save();
lbajardsilogic@0 719 paint.setPen(brushColour);
lbajardsilogic@0 720 paint.drawLine(x + w, y, nx, ny);
lbajardsilogic@0 721 paint.restore();
lbajardsilogic@0 722
lbajardsilogic@0 723 } else if (m_plotStyle == PlotLines) {
lbajardsilogic@0 724
lbajardsilogic@0 725 paint.drawLine(x + w/2, y, nx + w/2, ny);
lbajardsilogic@0 726
lbajardsilogic@0 727 } else {
lbajardsilogic@0 728
lbajardsilogic@0 729 float x0 = x + float(w)/2;
lbajardsilogic@0 730 float x1 = nx + float(w)/2;
lbajardsilogic@0 731
lbajardsilogic@0 732 float y0 = y;
lbajardsilogic@0 733 float y1 = ny;
lbajardsilogic@0 734
lbajardsilogic@0 735 if (pointCount == 0) {
lbajardsilogic@0 736 path.moveTo((x0 + x1) / 2, (y0 + y1) / 2);
lbajardsilogic@0 737 }
lbajardsilogic@0 738 ++pointCount;
lbajardsilogic@0 739
lbajardsilogic@0 740 if (nx - x > 5) {
lbajardsilogic@0 741 path.cubicTo(x0, y0,
lbajardsilogic@0 742 x0, y0,
lbajardsilogic@0 743 (x0 + x1) / 2, (y0 + y1) / 2);
lbajardsilogic@0 744
lbajardsilogic@0 745 // // or
lbajardsilogic@0 746 // path.quadTo(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
lbajardsilogic@0 747
lbajardsilogic@0 748 } else {
lbajardsilogic@0 749 path.lineTo((x0 + x1) / 2, (y0 + y1) / 2);
lbajardsilogic@0 750 }
lbajardsilogic@0 751 }
lbajardsilogic@0 752 }
lbajardsilogic@0 753 }
lbajardsilogic@0 754
lbajardsilogic@0 755 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 756
lbajardsilogic@0 757 // std::cerr << "drawing rect" << std::endl;
lbajardsilogic@0 758
lbajardsilogic@0 759 if (nx <= x) continue;
lbajardsilogic@0 760
lbajardsilogic@0 761 if (illuminateFrame != p.frame &&
lbajardsilogic@0 762 (nx < x + 5 || x >= v->width() - 1)) {
lbajardsilogic@0 763 paint.setPen(Qt::NoPen);
lbajardsilogic@0 764 }
lbajardsilogic@0 765
lbajardsilogic@0 766 paint.drawRect(x, -1, nx - x, v->height() + 1);
lbajardsilogic@0 767 }
lbajardsilogic@0 768
lbajardsilogic@0 769 if (p.label != "") {
lbajardsilogic@0 770 if (!haveNext || nx > x + 6 + paint.fontMetrics().width(p.label)) {
lbajardsilogic@0 771 paint.drawText(x + 5, textY, p.label);
lbajardsilogic@0 772 }
lbajardsilogic@0 773 }
lbajardsilogic@0 774 }
lbajardsilogic@0 775
lbajardsilogic@0 776 if (m_plotStyle == PlotCurve && !path.isEmpty()) {
lbajardsilogic@0 777 paint.setRenderHint(QPainter::Antialiasing, pointCount <= v->width());
lbajardsilogic@0 778 paint.drawPath(path);
lbajardsilogic@0 779 }
lbajardsilogic@0 780
lbajardsilogic@0 781 paint.restore();
lbajardsilogic@0 782
lbajardsilogic@0 783 // looks like save/restore doesn't deal with this:
lbajardsilogic@0 784 paint.setRenderHint(QPainter::Antialiasing, false);
lbajardsilogic@0 785 }
lbajardsilogic@0 786
lbajardsilogic@0 787 int
lbajardsilogic@0 788 TimeValueLayer::getVerticalScaleWidth(View *, QPainter &paint) const
lbajardsilogic@0 789 {
lbajardsilogic@0 790 int w = paint.fontMetrics().width("-000.000");
lbajardsilogic@0 791 if (m_plotStyle == PlotSegmentation) return w + 20;
lbajardsilogic@0 792 else return w + 10;
lbajardsilogic@0 793 }
lbajardsilogic@0 794
lbajardsilogic@0 795 void
lbajardsilogic@0 796 TimeValueLayer::paintVerticalScale(View *v, QPainter &paint, QRect) const
lbajardsilogic@0 797 {
lbajardsilogic@0 798 if (!m_model) return;
lbajardsilogic@0 799
lbajardsilogic@0 800 int h = v->height();
lbajardsilogic@0 801
lbajardsilogic@0 802 int n = 10;
lbajardsilogic@0 803
lbajardsilogic@0 804 float max = m_model->getValueMaximum();
lbajardsilogic@0 805 float min = m_model->getValueMinimum();
lbajardsilogic@0 806 float val = min;
lbajardsilogic@0 807 float inc = (max - val) / n;
lbajardsilogic@0 808
lbajardsilogic@0 809 char buffer[40];
lbajardsilogic@0 810
lbajardsilogic@0 811 int w = getVerticalScaleWidth(v, paint);
lbajardsilogic@0 812
lbajardsilogic@0 813 int tx = 5;
lbajardsilogic@0 814
lbajardsilogic@0 815 int boxx = 5, boxy = 5;
lbajardsilogic@0 816 if (m_model->getScaleUnits() != "") {
lbajardsilogic@0 817 boxy += paint.fontMetrics().height();
lbajardsilogic@0 818 }
lbajardsilogic@0 819 int boxw = 10, boxh = h - boxy - 5;
lbajardsilogic@0 820
lbajardsilogic@0 821 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 822 tx += boxx + boxw;
lbajardsilogic@0 823 paint.drawRect(boxx, boxy, boxw, boxh);
lbajardsilogic@0 824 }
lbajardsilogic@0 825
lbajardsilogic@0 826 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 827 paint.save();
lbajardsilogic@0 828 for (int y = 0; y < boxh; ++y) {
lbajardsilogic@0 829 float val = ((boxh - y) * (max - min)) / boxh + min;
lbajardsilogic@0 830 paint.setPen(getColourForValue(v, val));
lbajardsilogic@0 831 paint.drawLine(boxx + 1, y + boxy + 1, boxx + boxw, y + boxy + 1);
lbajardsilogic@0 832 }
lbajardsilogic@0 833 paint.restore();
lbajardsilogic@0 834 }
lbajardsilogic@0 835
lbajardsilogic@0 836 for (int i = 0; i < n; ++i) {
lbajardsilogic@0 837
lbajardsilogic@0 838 int y, ty;
lbajardsilogic@0 839 bool drawText = true;
lbajardsilogic@0 840
lbajardsilogic@0 841 if (m_plotStyle == PlotSegmentation) {
lbajardsilogic@0 842 y = boxy + int(boxh - ((val - min) * boxh) / (max - min));
lbajardsilogic@0 843 ty = y;
lbajardsilogic@0 844 } else {
lbajardsilogic@0 845 if (i == n-1) {
lbajardsilogic@0 846 if (m_model->getScaleUnits() != "") drawText = false;
lbajardsilogic@0 847 }
lbajardsilogic@0 848 y = getYForValue(v, val);
lbajardsilogic@0 849 ty = y - paint.fontMetrics().height() +
lbajardsilogic@0 850 paint.fontMetrics().ascent();
lbajardsilogic@0 851 }
lbajardsilogic@0 852
lbajardsilogic@0 853 sprintf(buffer, "%.3f", val);
lbajardsilogic@0 854 QString label = QString(buffer);
lbajardsilogic@0 855
lbajardsilogic@0 856 if (m_plotStyle != PlotSegmentation) {
lbajardsilogic@0 857 paint.drawLine(w - 5, y, w, y);
lbajardsilogic@0 858 } else {
lbajardsilogic@0 859 paint.drawLine(boxx + boxw - boxw/3, y, boxx + boxw, y);
lbajardsilogic@0 860 }
lbajardsilogic@0 861
lbajardsilogic@0 862 if (drawText) paint.drawText(tx, ty, label);
lbajardsilogic@0 863 val += inc;
lbajardsilogic@0 864 }
lbajardsilogic@0 865
lbajardsilogic@0 866 if (m_model->getScaleUnits() != "") {
lbajardsilogic@0 867 paint.drawText(5, 5 + paint.fontMetrics().ascent(),
lbajardsilogic@0 868 m_model->getScaleUnits());
lbajardsilogic@0 869 }
lbajardsilogic@0 870 }
lbajardsilogic@0 871
lbajardsilogic@0 872 void
lbajardsilogic@0 873 TimeValueLayer::drawStart(View *v, QMouseEvent *e)
lbajardsilogic@0 874 {
lbajardsilogic@0 875 // std::cerr << "TimeValueLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 876
lbajardsilogic@0 877 if (!m_model) return;
lbajardsilogic@0 878
lbajardsilogic@0 879 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 880 long resolution = m_model->getResolution();
lbajardsilogic@0 881 if (frame < 0) frame = 0;
lbajardsilogic@0 882 frame = (frame / resolution) * resolution;
lbajardsilogic@0 883
lbajardsilogic@0 884 float value = getValueForY(v, e->y());
lbajardsilogic@0 885
lbajardsilogic@0 886 bool havePoint = false;
lbajardsilogic@0 887
lbajardsilogic@0 888 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 889 if (!points.empty()) {
lbajardsilogic@0 890 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 891 i != points.end(); ++i) {
lbajardsilogic@0 892 if (((i->frame / resolution) * resolution) != frame) {
lbajardsilogic@0 893 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
lbajardsilogic@0 894 continue;
lbajardsilogic@0 895 }
lbajardsilogic@0 896 m_editingPoint = *i;
lbajardsilogic@0 897 havePoint = true;
lbajardsilogic@0 898 }
lbajardsilogic@0 899 }
lbajardsilogic@0 900
lbajardsilogic@0 901 if (!havePoint) {
lbajardsilogic@0 902 m_editingPoint = SparseTimeValueModel::Point
lbajardsilogic@0 903 (frame, value, tr("New Point"));
lbajardsilogic@0 904 }
lbajardsilogic@0 905
lbajardsilogic@0 906 m_originalPoint = m_editingPoint;
lbajardsilogic@0 907
lbajardsilogic@0 908 if (m_editingCommand) m_editingCommand->finish();
lbajardsilogic@0 909 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
lbajardsilogic@0 910 tr("Draw Point"));
lbajardsilogic@0 911 if (!havePoint) {
lbajardsilogic@0 912 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 913 }
lbajardsilogic@0 914
lbajardsilogic@0 915 m_editing = true;
lbajardsilogic@0 916 }
lbajardsilogic@0 917
lbajardsilogic@0 918 void
lbajardsilogic@0 919 TimeValueLayer::drawDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 920 {
lbajardsilogic@0 921 // std::cerr << "TimeValueLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 922
lbajardsilogic@0 923 if (!m_model || !m_editing) return;
lbajardsilogic@0 924
lbajardsilogic@0 925 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 926 long resolution = m_model->getResolution();
lbajardsilogic@0 927 if (frame < 0) frame = 0;
lbajardsilogic@0 928 frame = (frame / resolution) * resolution;
lbajardsilogic@0 929
lbajardsilogic@0 930 float value = getValueForY(v, e->y());
lbajardsilogic@0 931
lbajardsilogic@0 932 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 933
lbajardsilogic@0 934 // std::cerr << points.size() << " points" << std::endl;
lbajardsilogic@0 935
lbajardsilogic@0 936 bool havePoint = false;
lbajardsilogic@0 937
lbajardsilogic@0 938 if (!points.empty()) {
lbajardsilogic@0 939 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 940 i != points.end(); ++i) {
lbajardsilogic@0 941 if (i->frame == m_editingPoint.frame &&
lbajardsilogic@0 942 i->value == m_editingPoint.value) {
lbajardsilogic@0 943 // std::cerr << "ignoring current editing point at " << i->frame << ", " << i->value << std::endl;
lbajardsilogic@0 944 continue;
lbajardsilogic@0 945 }
lbajardsilogic@0 946 if (((i->frame / resolution) * resolution) != frame) {
lbajardsilogic@0 947 // std::cerr << "ignoring out-of-range frame at " << i->frame << std::endl;
lbajardsilogic@0 948 continue;
lbajardsilogic@0 949 }
lbajardsilogic@0 950 // std::cerr << "adjusting to new point at " << i->frame << ", " << i->value << std::endl;
lbajardsilogic@0 951 m_editingPoint = *i;
lbajardsilogic@0 952 m_originalPoint = m_editingPoint;
lbajardsilogic@0 953 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 954 havePoint = true;
lbajardsilogic@0 955 }
lbajardsilogic@0 956 }
lbajardsilogic@0 957
lbajardsilogic@0 958 if (!havePoint) {
lbajardsilogic@0 959 if (frame == m_editingPoint.frame) {
lbajardsilogic@0 960 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 961 }
lbajardsilogic@0 962 }
lbajardsilogic@0 963
lbajardsilogic@0 964 // m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 965 m_editingPoint.frame = frame;
lbajardsilogic@0 966 m_editingPoint.value = value;
lbajardsilogic@0 967 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 968 }
lbajardsilogic@0 969
lbajardsilogic@0 970 void
lbajardsilogic@0 971 TimeValueLayer::drawEnd(View *, QMouseEvent *)
lbajardsilogic@0 972 {
lbajardsilogic@0 973 // std::cerr << "TimeValueLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 974 if (!m_model || !m_editing) return;
lbajardsilogic@0 975 m_editingCommand->finish();
lbajardsilogic@0 976 m_editingCommand = 0;
lbajardsilogic@0 977 m_editing = false;
lbajardsilogic@0 978 }
lbajardsilogic@0 979
lbajardsilogic@0 980 void
lbajardsilogic@0 981 TimeValueLayer::editStart(View *v, QMouseEvent *e)
lbajardsilogic@0 982 {
lbajardsilogic@0 983 // std::cerr << "TimeValueLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 984
lbajardsilogic@0 985 if (!m_model) return;
lbajardsilogic@0 986
lbajardsilogic@0 987 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 988 if (points.empty()) return;
lbajardsilogic@0 989
lbajardsilogic@0 990 m_editingPoint = *points.begin();
lbajardsilogic@0 991 m_originalPoint = m_editingPoint;
lbajardsilogic@0 992
lbajardsilogic@0 993 if (m_editingCommand) {
lbajardsilogic@0 994 m_editingCommand->finish();
lbajardsilogic@0 995 m_editingCommand = 0;
lbajardsilogic@0 996 }
lbajardsilogic@0 997
lbajardsilogic@0 998 m_editing = true;
lbajardsilogic@0 999 }
lbajardsilogic@0 1000
lbajardsilogic@0 1001 void
lbajardsilogic@0 1002 TimeValueLayer::editDrag(View *v, QMouseEvent *e)
lbajardsilogic@0 1003 {
lbajardsilogic@0 1004 // std::cerr << "TimeValueLayer::editDrag(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 1005
lbajardsilogic@0 1006 if (!m_model || !m_editing) return;
lbajardsilogic@0 1007
lbajardsilogic@0 1008 long frame = v->getFrameForX(e->x());
lbajardsilogic@0 1009 if (frame < 0) frame = 0;
lbajardsilogic@0 1010 frame = frame / m_model->getResolution() * m_model->getResolution();
lbajardsilogic@0 1011
lbajardsilogic@0 1012 float value = getValueForY(v, e->y());
lbajardsilogic@0 1013
lbajardsilogic@0 1014 if (!m_editingCommand) {
lbajardsilogic@0 1015 m_editingCommand = new SparseTimeValueModel::EditCommand(m_model,
lbajardsilogic@0 1016 tr("Drag Point"));
lbajardsilogic@0 1017 }
lbajardsilogic@0 1018
lbajardsilogic@0 1019 m_editingCommand->deletePoint(m_editingPoint);
lbajardsilogic@0 1020 m_editingPoint.frame = frame;
lbajardsilogic@0 1021 m_editingPoint.value = value;
lbajardsilogic@0 1022 m_editingCommand->addPoint(m_editingPoint);
lbajardsilogic@0 1023 }
lbajardsilogic@0 1024
lbajardsilogic@0 1025 void
lbajardsilogic@0 1026 TimeValueLayer::editEnd(View *, QMouseEvent *)
lbajardsilogic@0 1027 {
lbajardsilogic@0 1028 // std::cerr << "TimeValueLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl;
lbajardsilogic@0 1029 if (!m_model || !m_editing) return;
lbajardsilogic@0 1030
lbajardsilogic@0 1031 if (m_editingCommand) {
lbajardsilogic@0 1032
lbajardsilogic@0 1033 QString newName = m_editingCommand->getName();
lbajardsilogic@0 1034
lbajardsilogic@0 1035 if (m_editingPoint.frame != m_originalPoint.frame) {
lbajardsilogic@0 1036 if (m_editingPoint.value != m_originalPoint.value) {
lbajardsilogic@0 1037 newName = tr("Edit Point");
lbajardsilogic@0 1038 } else {
lbajardsilogic@0 1039 newName = tr("Relocate Point");
lbajardsilogic@0 1040 }
lbajardsilogic@0 1041 } else {
lbajardsilogic@0 1042 newName = tr("Change Point Value");
lbajardsilogic@0 1043 }
lbajardsilogic@0 1044
lbajardsilogic@0 1045 m_editingCommand->setName(newName);
lbajardsilogic@0 1046 m_editingCommand->finish();
lbajardsilogic@0 1047 }
lbajardsilogic@0 1048
lbajardsilogic@0 1049 m_editingCommand = 0;
lbajardsilogic@0 1050 m_editing = false;
lbajardsilogic@0 1051 }
lbajardsilogic@0 1052
lbajardsilogic@0 1053 void
lbajardsilogic@0 1054 TimeValueLayer::editOpen(View *v, QMouseEvent *e)
lbajardsilogic@0 1055 {
lbajardsilogic@0 1056 if (!m_model) return;
lbajardsilogic@0 1057
lbajardsilogic@0 1058 SparseTimeValueModel::PointList points = getLocalPoints(v, e->x());
lbajardsilogic@0 1059 if (points.empty()) return;
lbajardsilogic@0 1060
lbajardsilogic@0 1061 SparseTimeValueModel::Point point = *points.begin();
lbajardsilogic@0 1062
lbajardsilogic@0 1063 ItemEditDialog *dialog = new ItemEditDialog
lbajardsilogic@0 1064 (m_model->getSampleRate(),
lbajardsilogic@0 1065 ItemEditDialog::ShowTime |
lbajardsilogic@0 1066 ItemEditDialog::ShowValue |
lbajardsilogic@0 1067 ItemEditDialog::ShowText,
lbajardsilogic@0 1068 m_model->getScaleUnits());
lbajardsilogic@0 1069
lbajardsilogic@0 1070 dialog->setFrameTime(point.frame);
lbajardsilogic@0 1071 dialog->setValue(point.value);
lbajardsilogic@0 1072 dialog->setText(point.label);
lbajardsilogic@0 1073
lbajardsilogic@0 1074 if (dialog->exec() == QDialog::Accepted) {
lbajardsilogic@0 1075
lbajardsilogic@0 1076 SparseTimeValueModel::Point newPoint = point;
lbajardsilogic@0 1077 newPoint.frame = dialog->getFrameTime();
lbajardsilogic@0 1078 newPoint.value = dialog->getValue();
lbajardsilogic@0 1079 newPoint.label = dialog->getText();
lbajardsilogic@0 1080
lbajardsilogic@0 1081 SparseTimeValueModel::EditCommand *command =
lbajardsilogic@0 1082 new SparseTimeValueModel::EditCommand(m_model, tr("Edit Point"));
lbajardsilogic@0 1083 command->deletePoint(point);
lbajardsilogic@0 1084 command->addPoint(newPoint);
lbajardsilogic@0 1085 command->finish();
lbajardsilogic@0 1086 }
lbajardsilogic@0 1087
lbajardsilogic@0 1088 delete dialog;
lbajardsilogic@0 1089 }
lbajardsilogic@0 1090
lbajardsilogic@0 1091 void
lbajardsilogic@0 1092 TimeValueLayer::moveSelection(Selection s, size_t newStartFrame)
lbajardsilogic@0 1093 {
lbajardsilogic@0 1094 if (!m_model) return;
lbajardsilogic@0 1095
lbajardsilogic@0 1096 SparseTimeValueModel::EditCommand *command =
lbajardsilogic@0 1097 new SparseTimeValueModel::EditCommand(m_model,
lbajardsilogic@0 1098 tr("Drag Selection"));
lbajardsilogic@0 1099
lbajardsilogic@0 1100 SparseTimeValueModel::PointList points =
lbajardsilogic@0 1101 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 1102
lbajardsilogic@0 1103 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 1104 i != points.end(); ++i) {
lbajardsilogic@0 1105
lbajardsilogic@0 1106 if (s.contains(i->frame)) {
lbajardsilogic@0 1107 SparseTimeValueModel::Point newPoint(*i);
lbajardsilogic@0 1108 newPoint.frame = i->frame + newStartFrame - s.getStartFrame();
lbajardsilogic@0 1109 command->deletePoint(*i);
lbajardsilogic@0 1110 command->addPoint(newPoint);
lbajardsilogic@0 1111 }
lbajardsilogic@0 1112 }
lbajardsilogic@0 1113
lbajardsilogic@0 1114 command->finish();
lbajardsilogic@0 1115 }
lbajardsilogic@0 1116
lbajardsilogic@0 1117 void
lbajardsilogic@0 1118 TimeValueLayer::resizeSelection(Selection s, Selection newSize)
lbajardsilogic@0 1119 {
lbajardsilogic@0 1120 if (!m_model) return;
lbajardsilogic@0 1121
lbajardsilogic@0 1122 SparseTimeValueModel::EditCommand *command =
lbajardsilogic@0 1123 new SparseTimeValueModel::EditCommand(m_model,
lbajardsilogic@0 1124 tr("Resize Selection"));
lbajardsilogic@0 1125
lbajardsilogic@0 1126 SparseTimeValueModel::PointList points =
lbajardsilogic@0 1127 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 1128
lbajardsilogic@0 1129 double ratio =
lbajardsilogic@0 1130 double(newSize.getEndFrame() - newSize.getStartFrame()) /
lbajardsilogic@0 1131 double(s.getEndFrame() - s.getStartFrame());
lbajardsilogic@0 1132
lbajardsilogic@0 1133 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 1134 i != points.end(); ++i) {
lbajardsilogic@0 1135
lbajardsilogic@0 1136 if (s.contains(i->frame)) {
lbajardsilogic@0 1137
lbajardsilogic@0 1138 double target = i->frame;
lbajardsilogic@0 1139 target = newSize.getStartFrame() +
lbajardsilogic@0 1140 double(target - s.getStartFrame()) * ratio;
lbajardsilogic@0 1141
lbajardsilogic@0 1142 SparseTimeValueModel::Point newPoint(*i);
lbajardsilogic@0 1143 newPoint.frame = lrint(target);
lbajardsilogic@0 1144 command->deletePoint(*i);
lbajardsilogic@0 1145 command->addPoint(newPoint);
lbajardsilogic@0 1146 }
lbajardsilogic@0 1147 }
lbajardsilogic@0 1148
lbajardsilogic@0 1149 command->finish();
lbajardsilogic@0 1150 }
lbajardsilogic@0 1151
lbajardsilogic@0 1152 void
lbajardsilogic@0 1153 TimeValueLayer::deleteSelection(Selection s)
lbajardsilogic@0 1154 {
lbajardsilogic@0 1155 if (!m_model) return;
lbajardsilogic@0 1156
lbajardsilogic@0 1157 SparseTimeValueModel::EditCommand *command =
lbajardsilogic@0 1158 new SparseTimeValueModel::EditCommand(m_model,
lbajardsilogic@0 1159 tr("Delete Selected Points"));
lbajardsilogic@0 1160
lbajardsilogic@0 1161 SparseTimeValueModel::PointList points =
lbajardsilogic@0 1162 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 1163
lbajardsilogic@0 1164 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 1165 i != points.end(); ++i) {
lbajardsilogic@0 1166
lbajardsilogic@0 1167 if (s.contains(i->frame)) {
lbajardsilogic@0 1168 command->deletePoint(*i);
lbajardsilogic@0 1169 }
lbajardsilogic@0 1170 }
lbajardsilogic@0 1171
lbajardsilogic@0 1172 command->finish();
lbajardsilogic@0 1173 }
lbajardsilogic@0 1174
lbajardsilogic@0 1175 void
lbajardsilogic@0 1176 TimeValueLayer::copy(Selection s, Clipboard &to)
lbajardsilogic@0 1177 {
lbajardsilogic@0 1178 if (!m_model) return;
lbajardsilogic@0 1179
lbajardsilogic@0 1180 SparseTimeValueModel::PointList points =
lbajardsilogic@0 1181 m_model->getPoints(s.getStartFrame(), s.getEndFrame());
lbajardsilogic@0 1182
lbajardsilogic@0 1183 for (SparseTimeValueModel::PointList::iterator i = points.begin();
lbajardsilogic@0 1184 i != points.end(); ++i) {
lbajardsilogic@0 1185 if (s.contains(i->frame)) {
lbajardsilogic@0 1186 Clipboard::Point point(i->frame, i->value, i->label);
lbajardsilogic@0 1187 to.addPoint(point);
lbajardsilogic@0 1188 }
lbajardsilogic@0 1189 }
lbajardsilogic@0 1190 }
lbajardsilogic@0 1191
lbajardsilogic@0 1192 bool
lbajardsilogic@0 1193 TimeValueLayer::paste(const Clipboard &from, int frameOffset,
lbajardsilogic@0 1194 bool interactive)
lbajardsilogic@0 1195 {
lbajardsilogic@0 1196 if (!m_model) return false;
lbajardsilogic@0 1197
lbajardsilogic@0 1198 const Clipboard::PointList &points = from.getPoints();
lbajardsilogic@0 1199
lbajardsilogic@0 1200 SparseTimeValueModel::EditCommand *command =
lbajardsilogic@0 1201 new SparseTimeValueModel::EditCommand(m_model, tr("Paste"));
lbajardsilogic@0 1202
lbajardsilogic@0 1203 enum ValueAvailability {
lbajardsilogic@0 1204 UnknownAvailability,
lbajardsilogic@0 1205 NoValues,
lbajardsilogic@0 1206 SomeValues,
lbajardsilogic@0 1207 AllValues
lbajardsilogic@0 1208 };
lbajardsilogic@0 1209 enum ValueGeneration {
lbajardsilogic@0 1210 GenerateNone,
lbajardsilogic@0 1211 GenerateFromCounter,
lbajardsilogic@0 1212 GenerateFromFrameNumber,
lbajardsilogic@0 1213 GenerateFromRealTime,
lbajardsilogic@0 1214 GenerateFromRealTimeDifference,
lbajardsilogic@0 1215 GenerateFromTempo,
lbajardsilogic@0 1216 GenerateFromExistingNeighbour,
lbajardsilogic@0 1217 GenerateFromLabels
lbajardsilogic@0 1218 };
lbajardsilogic@0 1219
lbajardsilogic@0 1220 ValueGeneration generation = GenerateNone;
lbajardsilogic@0 1221
lbajardsilogic@0 1222 bool haveUsableLabels = false;
lbajardsilogic@0 1223 bool haveExistingItems = !(m_model->isEmpty());
lbajardsilogic@0 1224
lbajardsilogic@0 1225 if (interactive) {
lbajardsilogic@0 1226
lbajardsilogic@0 1227 ValueAvailability availability = UnknownAvailability;
lbajardsilogic@0 1228
lbajardsilogic@0 1229 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 1230 i != points.end(); ++i) {
lbajardsilogic@0 1231
lbajardsilogic@0 1232 if (!i->haveFrame()) continue;
lbajardsilogic@0 1233
lbajardsilogic@0 1234 if (availability == UnknownAvailability) {
lbajardsilogic@0 1235 if (i->haveValue()) availability = AllValues;
lbajardsilogic@0 1236 else availability = NoValues;
lbajardsilogic@0 1237 continue;
lbajardsilogic@0 1238 }
lbajardsilogic@0 1239
lbajardsilogic@0 1240 if (i->haveValue()) {
lbajardsilogic@0 1241 if (availability == NoValues) {
lbajardsilogic@0 1242 availability = SomeValues;
lbajardsilogic@0 1243 }
lbajardsilogic@0 1244 } else {
lbajardsilogic@0 1245 if (availability == AllValues) {
lbajardsilogic@0 1246 availability = SomeValues;
lbajardsilogic@0 1247 }
lbajardsilogic@0 1248 }
lbajardsilogic@0 1249
lbajardsilogic@0 1250 if (!haveUsableLabels) {
lbajardsilogic@0 1251 if (i->haveLabel()) {
lbajardsilogic@0 1252 if (i->getLabel().contains(QRegExp("[0-9]"))) {
lbajardsilogic@0 1253 haveUsableLabels = true;
lbajardsilogic@0 1254 }
lbajardsilogic@0 1255 }
lbajardsilogic@0 1256 }
lbajardsilogic@0 1257
lbajardsilogic@0 1258 if (availability == SomeValues && haveUsableLabels) break;
lbajardsilogic@0 1259 }
lbajardsilogic@0 1260
lbajardsilogic@0 1261 if (availability == NoValues || availability == SomeValues) {
lbajardsilogic@0 1262
lbajardsilogic@0 1263 QString text;
lbajardsilogic@0 1264 if (availability == NoValues) {
lbajardsilogic@0 1265 text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?");
lbajardsilogic@0 1266 } else {
lbajardsilogic@0 1267 text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?");
lbajardsilogic@0 1268 }
lbajardsilogic@0 1269
lbajardsilogic@0 1270 QStringList options;
lbajardsilogic@0 1271 std::vector<int> genopts;
lbajardsilogic@0 1272
lbajardsilogic@0 1273 options << tr("Zero for all items");
lbajardsilogic@0 1274 genopts.push_back(int(GenerateNone));
lbajardsilogic@0 1275
lbajardsilogic@0 1276 options << tr("Whole numbers counting from 1");
lbajardsilogic@0 1277 genopts.push_back(int(GenerateFromCounter));
lbajardsilogic@0 1278
lbajardsilogic@0 1279 options << tr("Item's audio sample frame number");
lbajardsilogic@0 1280 genopts.push_back(int(GenerateFromFrameNumber));
lbajardsilogic@0 1281
lbajardsilogic@0 1282 options << tr("Item's time in seconds");
lbajardsilogic@0 1283 genopts.push_back(int(GenerateFromRealTime));
lbajardsilogic@0 1284
lbajardsilogic@0 1285 options << tr("Duration from the item to the following item");
lbajardsilogic@0 1286 genopts.push_back(int(GenerateFromRealTimeDifference));
lbajardsilogic@0 1287
lbajardsilogic@0 1288 options << tr("Tempo in bpm derived from the duration");
lbajardsilogic@0 1289 genopts.push_back(int(GenerateFromTempo));
lbajardsilogic@0 1290
lbajardsilogic@0 1291 if (haveExistingItems) {
lbajardsilogic@0 1292 options << tr("Value of the nearest existing item");
lbajardsilogic@0 1293 genopts.push_back(int(GenerateFromExistingNeighbour));
lbajardsilogic@0 1294 }
lbajardsilogic@0 1295
lbajardsilogic@0 1296 if (haveUsableLabels) {
lbajardsilogic@0 1297 options << tr("Value extracted from the item's label (where possible)");
lbajardsilogic@0 1298 genopts.push_back(int(GenerateFromLabels));
lbajardsilogic@0 1299 }
lbajardsilogic@0 1300
lbajardsilogic@0 1301
lbajardsilogic@0 1302 static int prevSelection = 0;
lbajardsilogic@0 1303
lbajardsilogic@0 1304 bool ok = false;
lbajardsilogic@0 1305 QString selected = ListInputDialog::getItem
lbajardsilogic@0 1306 (0, tr("Choose value calculation"),
lbajardsilogic@0 1307 text, options, prevSelection, &ok);
lbajardsilogic@0 1308
lbajardsilogic@0 1309 if (!ok) return false;
lbajardsilogic@0 1310 int selection = 0;
lbajardsilogic@0 1311 generation = GenerateNone;
lbajardsilogic@0 1312
lbajardsilogic@0 1313 for (QStringList::const_iterator i = options.begin();
lbajardsilogic@0 1314 i != options.end(); ++i) {
lbajardsilogic@0 1315 if (selected == *i) {
lbajardsilogic@0 1316 generation = ValueGeneration(genopts[selection]);
lbajardsilogic@0 1317 break;
lbajardsilogic@0 1318 }
lbajardsilogic@0 1319 ++selection;
lbajardsilogic@0 1320 }
lbajardsilogic@0 1321
lbajardsilogic@0 1322 prevSelection = selection;
lbajardsilogic@0 1323 }
lbajardsilogic@0 1324 }
lbajardsilogic@0 1325
lbajardsilogic@0 1326 int counter = 1;
lbajardsilogic@0 1327 float prevBpm = 120.f;
lbajardsilogic@0 1328
lbajardsilogic@0 1329 for (Clipboard::PointList::const_iterator i = points.begin();
lbajardsilogic@0 1330 i != points.end(); ++i) {
lbajardsilogic@0 1331
lbajardsilogic@0 1332 if (!i->haveFrame()) continue;
lbajardsilogic@0 1333 size_t frame = 0;
lbajardsilogic@0 1334 if (frameOffset > 0 || -frameOffset < i->getFrame()) {
lbajardsilogic@0 1335 frame = i->getFrame() + frameOffset;
lbajardsilogic@0 1336 }
lbajardsilogic@0 1337 SparseTimeValueModel::Point newPoint(frame);
lbajardsilogic@0 1338
lbajardsilogic@0 1339 if (i->haveLabel()) {
lbajardsilogic@0 1340 newPoint.label = i->getLabel();
lbajardsilogic@0 1341 } else if (i->haveValue()) {
lbajardsilogic@0 1342 newPoint.label = QString("%1").arg(i->getValue());
lbajardsilogic@0 1343 }
lbajardsilogic@0 1344
lbajardsilogic@0 1345 if (i->haveValue()) {
lbajardsilogic@0 1346 newPoint.value = i->getValue();
lbajardsilogic@0 1347 } else {
lbajardsilogic@0 1348
lbajardsilogic@0 1349 switch (generation) {
lbajardsilogic@0 1350
lbajardsilogic@0 1351 case GenerateNone:
lbajardsilogic@0 1352 newPoint.value = 0;
lbajardsilogic@0 1353 break;
lbajardsilogic@0 1354
lbajardsilogic@0 1355 case GenerateFromCounter:
lbajardsilogic@0 1356 newPoint.value = counter;
lbajardsilogic@0 1357 break;
lbajardsilogic@0 1358
lbajardsilogic@0 1359 case GenerateFromFrameNumber:
lbajardsilogic@0 1360 newPoint.value = frame;
lbajardsilogic@0 1361 break;
lbajardsilogic@0 1362
lbajardsilogic@0 1363 case GenerateFromRealTime:
lbajardsilogic@0 1364 newPoint.value = float(frame) / float(m_model->getSampleRate());
lbajardsilogic@0 1365 break;
lbajardsilogic@0 1366
lbajardsilogic@0 1367 case GenerateFromRealTimeDifference:
lbajardsilogic@0 1368 case GenerateFromTempo:
lbajardsilogic@0 1369 {
lbajardsilogic@0 1370 size_t nextFrame = frame;
lbajardsilogic@0 1371 Clipboard::PointList::const_iterator j = i;
lbajardsilogic@0 1372 for (; j != points.end(); ++j) {
lbajardsilogic@0 1373 if (!j->haveFrame()) continue;
lbajardsilogic@0 1374 if (j != i) break;
lbajardsilogic@0 1375 }
lbajardsilogic@0 1376 if (j != points.end()) {
lbajardsilogic@0 1377 nextFrame = j->getFrame();
lbajardsilogic@0 1378 }
lbajardsilogic@0 1379 if (generation == GenerateFromRealTimeDifference) {
lbajardsilogic@0 1380 newPoint.value = float(nextFrame - frame) /
lbajardsilogic@0 1381 float(m_model->getSampleRate());
lbajardsilogic@0 1382 } else {
lbajardsilogic@0 1383 float bpm = prevBpm;
lbajardsilogic@0 1384 if (nextFrame > frame) {
lbajardsilogic@0 1385 bpm = (60.f * m_model->getSampleRate()) /
lbajardsilogic@0 1386 (nextFrame - frame);
lbajardsilogic@0 1387 }
lbajardsilogic@0 1388 newPoint.value = bpm;
lbajardsilogic@0 1389 prevBpm = bpm;
lbajardsilogic@0 1390 }
lbajardsilogic@0 1391 break;
lbajardsilogic@0 1392 }
lbajardsilogic@0 1393
lbajardsilogic@0 1394 case GenerateFromExistingNeighbour:
lbajardsilogic@0 1395 {
lbajardsilogic@0 1396 SparseTimeValueModel::PointList points =
lbajardsilogic@0 1397 m_model->getPoints(frame);
lbajardsilogic@0 1398 if (points.empty()) points = m_model->getPreviousPoints(frame);
lbajardsilogic@0 1399 if (points.empty()) points = m_model->getNextPoints(frame);
lbajardsilogic@0 1400 if (points.empty()) {
lbajardsilogic@0 1401 newPoint.value = 0.f;
lbajardsilogic@0 1402 } else {
lbajardsilogic@0 1403 newPoint.value = points.begin()->value;
lbajardsilogic@0 1404 }
lbajardsilogic@0 1405 }
lbajardsilogic@0 1406
lbajardsilogic@0 1407 case GenerateFromLabels:
lbajardsilogic@0 1408 if (i->haveLabel()) {
lbajardsilogic@0 1409 // more forgiving than QString::toFloat()
lbajardsilogic@0 1410 newPoint.value = atof(i->getLabel().toLocal8Bit());
lbajardsilogic@0 1411 } else {
lbajardsilogic@0 1412 newPoint.value = 0.f;
lbajardsilogic@0 1413 }
lbajardsilogic@0 1414 }
lbajardsilogic@0 1415 }
lbajardsilogic@0 1416
lbajardsilogic@0 1417 command->addPoint(newPoint);
lbajardsilogic@0 1418
lbajardsilogic@0 1419 ++counter;
lbajardsilogic@0 1420 }
lbajardsilogic@0 1421
lbajardsilogic@0 1422 command->finish();
lbajardsilogic@0 1423 return true;
lbajardsilogic@0 1424 }
lbajardsilogic@0 1425
lbajardsilogic@0 1426 QString
lbajardsilogic@0 1427 TimeValueLayer::toXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@0 1428 {
lbajardsilogic@0 1429 return Layer::toXmlString(indent, extraAttributes +
lbajardsilogic@0 1430 QString(" colour=\"%1\" plotStyle=\"%2\"")
lbajardsilogic@0 1431 .arg(encodeColour(m_colour)).arg(m_plotStyle));
lbajardsilogic@0 1432 }
lbajardsilogic@0 1433
lbajardsilogic@18 1434 QString
lbajardsilogic@18 1435 TimeValueLayer::toEasaierXmlString(QString indent, QString extraAttributes) const
lbajardsilogic@18 1436 {
lbajardsilogic@18 1437 return Layer::toEasaierXmlString(indent, extraAttributes +
lbajardsilogic@18 1438 QString(" colour=\"%1\" plotStyle=\"%2\"")
lbajardsilogic@18 1439 .arg(encodeColour(m_colour)).arg(m_plotStyle));
lbajardsilogic@18 1440 }
lbajardsilogic@18 1441
lbajardsilogic@0 1442 void
lbajardsilogic@0 1443 TimeValueLayer::setProperties(const QXmlAttributes &attributes)
lbajardsilogic@0 1444 {
lbajardsilogic@0 1445 QString colourSpec = attributes.value("colour");
lbajardsilogic@0 1446 if (colourSpec != "") {
lbajardsilogic@0 1447 QColor colour(colourSpec);
lbajardsilogic@0 1448 if (colour.isValid()) {
lbajardsilogic@0 1449 setBaseColour(QColor(colourSpec));
lbajardsilogic@0 1450 }
lbajardsilogic@0 1451 }
lbajardsilogic@0 1452
lbajardsilogic@0 1453 bool ok;
lbajardsilogic@0 1454 PlotStyle style = (PlotStyle)
lbajardsilogic@0 1455 attributes.value("plotStyle").toInt(&ok);
lbajardsilogic@0 1456 if (ok) setPlotStyle(style);
lbajardsilogic@0 1457 }
lbajardsilogic@0 1458