Chris@127
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@127
|
2
|
Chris@127
|
3 /*
|
Chris@127
|
4 Sonic Visualiser
|
Chris@127
|
5 An audio file viewer and annotation editor.
|
Chris@127
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@182
|
7 This file copyright 2006 Chris Cannam and QMUL.
|
Chris@127
|
8
|
Chris@127
|
9 This program is free software; you can redistribute it and/or
|
Chris@127
|
10 modify it under the terms of the GNU General Public License as
|
Chris@127
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@127
|
12 License, or (at your option) any later version. See the file
|
Chris@127
|
13 COPYING included with this distribution for more information.
|
Chris@127
|
14 */
|
Chris@127
|
15
|
Chris@127
|
16 #include "Layer.h"
|
Chris@128
|
17 #include "view/View.h"
|
Chris@128
|
18 #include "data/model/Model.h"
|
Chris@376
|
19 #include "widgets/CommandHistory.h"
|
Chris@127
|
20
|
Chris@127
|
21 #include <iostream>
|
Chris@127
|
22
|
Chris@131
|
23 #include <QMutexLocker>
|
Chris@267
|
24 #include <QMouseEvent>
|
Chris@316
|
25 #include <QTextStream>
|
Chris@131
|
26
|
Chris@326
|
27 #include <QDomDocument>
|
Chris@326
|
28 #include <QDomElement>
|
Chris@326
|
29 #include <QDomNamedNodeMap>
|
Chris@326
|
30 #include <QDomAttr>
|
Chris@326
|
31
|
Chris@131
|
32 #include "LayerFactory.h"
|
Chris@128
|
33 #include "base/PlayParameterRepository.h"
|
Chris@127
|
34
|
Chris@272
|
35 #include <cmath>
|
Chris@272
|
36
|
Chris@267
|
37 Layer::Layer() :
|
Chris@283
|
38 m_haveDraggingRect(false),
|
Chris@283
|
39 m_haveCurrentMeasureRect(false)
|
Chris@127
|
40 {
|
Chris@127
|
41 }
|
Chris@127
|
42
|
Chris@127
|
43 Layer::~Layer()
|
Chris@127
|
44 {
|
Chris@587
|
45 // SVDEBUG << "Layer::~Layer(" << this << ")" << endl;
|
Chris@127
|
46 }
|
Chris@127
|
47
|
Chris@320
|
48 void
|
Chris@1469
|
49 Layer::connectSignals(ModelId modelId)
|
Chris@320
|
50 {
|
Chris@1469
|
51 auto model = ModelById::get(modelId);
|
Chris@1469
|
52 if (!model) return;
|
Chris@1469
|
53
|
Chris@1481
|
54 connect(model.get(), SIGNAL(modelChanged(ModelId)),
|
Chris@1481
|
55 this, SIGNAL(modelChanged(ModelId)));
|
Chris@320
|
56
|
Chris@1481
|
57 connect(model.get(), SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
|
Chris@1481
|
58 this, SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)));
|
Chris@320
|
59
|
Chris@1481
|
60 connect(model.get(), SIGNAL(completionChanged(ModelId)),
|
Chris@1481
|
61 this, SIGNAL(modelCompletionChanged(ModelId)));
|
Chris@320
|
62
|
Chris@1481
|
63 connect(model.get(), SIGNAL(alignmentCompletionChanged(ModelId)),
|
Chris@1481
|
64 this, SIGNAL(modelAlignmentCompletionChanged(ModelId)));
|
Chris@320
|
65 }
|
Chris@320
|
66
|
Chris@1489
|
67 ModelId
|
Chris@1489
|
68 Layer::getSourceModel() const
|
Chris@1489
|
69 {
|
Chris@1489
|
70 ModelId sourceId;
|
Chris@1489
|
71 auto model = ModelById::get(getModel());
|
Chris@1489
|
72 while (model && !model->getSourceModel().isNone()) {
|
Chris@1489
|
73 sourceId = model->getSourceModel();
|
Chris@1489
|
74 model = ModelById::get(sourceId);
|
Chris@1489
|
75 }
|
Chris@1489
|
76 return sourceId;
|
Chris@1489
|
77 }
|
Chris@1489
|
78
|
Chris@127
|
79 QString
|
Chris@127
|
80 Layer::getPropertyContainerIconName() const
|
Chris@127
|
81 {
|
Chris@127
|
82 return LayerFactory::getInstance()->getLayerIconName
|
Chris@1266
|
83 (LayerFactory::getInstance()->getLayerType(this));
|
Chris@127
|
84 }
|
Chris@127
|
85
|
Chris@363
|
86 void
|
Chris@363
|
87 Layer::setPresentationName(QString name)
|
Chris@363
|
88 {
|
Chris@363
|
89 m_presentationName = name;
|
Chris@363
|
90 }
|
Chris@363
|
91
|
Chris@1585
|
92 bool
|
Chris@1585
|
93 Layer::isPresentationNameSet() const
|
Chris@1585
|
94 {
|
Chris@1585
|
95 return (m_presentationName != "");
|
Chris@1585
|
96 }
|
Chris@1585
|
97
|
Chris@127
|
98 QString
|
Chris@127
|
99 Layer::getLayerPresentationName() const
|
Chris@127
|
100 {
|
Chris@363
|
101 if (m_presentationName != "") return m_presentationName;
|
Chris@203
|
102
|
Chris@203
|
103 LayerFactory *factory = LayerFactory::getInstance();
|
Chris@203
|
104 QString layerName = factory->getLayerPresentationName
|
Chris@203
|
105 (factory->getLayerType(this));
|
Chris@203
|
106
|
Chris@127
|
107 QString modelName;
|
Chris@1469
|
108 auto model = ModelById::get(getModel());
|
Chris@1469
|
109 if (model) modelName = model->objectName();
|
Chris@1266
|
110
|
Chris@127
|
111 QString text;
|
Chris@127
|
112 if (modelName != "") {
|
Chris@1266
|
113 text = QString("%1: %2").arg(modelName).arg(layerName);
|
Chris@127
|
114 } else {
|
Chris@1266
|
115 text = layerName;
|
Chris@127
|
116 }
|
Chris@1266
|
117
|
Chris@127
|
118 return text;
|
Chris@127
|
119 }
|
Chris@127
|
120
|
Chris@127
|
121 void
|
Chris@127
|
122 Layer::setObjectName(const QString &name)
|
Chris@127
|
123 {
|
Chris@127
|
124 QObject::setObjectName(name);
|
Chris@127
|
125 emit layerNameChanged();
|
Chris@127
|
126 }
|
Chris@127
|
127
|
Chris@1480
|
128 std::shared_ptr<PlayParameters>
|
Chris@127
|
129 Layer::getPlayParameters()
|
Chris@127
|
130 {
|
Chris@1470
|
131 return PlayParameterRepository::getInstance()->getPlayParameters
|
Chris@1470
|
132 (getModel().untyped);
|
Chris@127
|
133 }
|
Chris@127
|
134
|
Chris@127
|
135 void
|
Chris@918
|
136 Layer::setLayerDormant(const LayerGeometryProvider *v, bool dormant)
|
Chris@131
|
137 {
|
Chris@131
|
138 const void *vv = (const void *)v;
|
Chris@131
|
139 QMutexLocker locker(&m_dormancyMutex);
|
Chris@131
|
140 m_dormancy[vv] = dormant;
|
Chris@131
|
141 }
|
Chris@131
|
142
|
Chris@131
|
143 bool
|
Chris@918
|
144 Layer::isLayerDormant(const LayerGeometryProvider *v) const
|
Chris@131
|
145 {
|
Chris@131
|
146 const void *vv = (const void *)v;
|
Chris@131
|
147 QMutexLocker locker(&m_dormancyMutex);
|
Chris@131
|
148 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
|
Chris@131
|
149 return m_dormancy.find(vv)->second;
|
Chris@131
|
150 }
|
Chris@131
|
151
|
Chris@131
|
152 void
|
Chris@918
|
153 Layer::showLayer(LayerGeometryProvider *view, bool show)
|
Chris@127
|
154 {
|
Chris@127
|
155 setLayerDormant(view, !show);
|
Chris@127
|
156 emit layerParametersChanged();
|
Chris@127
|
157 }
|
Chris@127
|
158
|
Chris@260
|
159 bool
|
Chris@918
|
160 Layer::getXScaleValue(const LayerGeometryProvider *v, int x, double &value, QString &unit) const
|
Chris@260
|
161 {
|
Chris@260
|
162 if (!hasTimeXAxis()) return false;
|
Chris@260
|
163
|
Chris@1469
|
164 auto model = ModelById::get(getModel());
|
Chris@1469
|
165 if (!model) return false;
|
Chris@260
|
166
|
Chris@1469
|
167 value = double(v->getFrameForX(x)) / model->getSampleRate();
|
Chris@260
|
168 unit = "s";
|
Chris@260
|
169 return true;
|
Chris@260
|
170 }
|
Chris@260
|
171
|
Chris@268
|
172 bool
|
Chris@918
|
173 Layer::getYScaleDifference(const LayerGeometryProvider *v, int y0, int y1,
|
Chris@904
|
174 double &diff, QString &unit) const
|
Chris@274
|
175 {
|
Chris@904
|
176 double v0, v1;
|
Chris@274
|
177 if (!getYScaleValue(v, y0, v0, unit) ||
|
Chris@274
|
178 !getYScaleValue(v, y1, v1, unit)) {
|
Chris@274
|
179 diff = 0.f;
|
Chris@274
|
180 return false;
|
Chris@274
|
181 }
|
Chris@904
|
182 diff = fabs(v1 - v0);
|
Chris@274
|
183 return true;
|
Chris@274
|
184 }
|
Chris@274
|
185
|
Chris@904
|
186 sv_frame_t
|
Chris@918
|
187 Layer::alignToReference(LayerGeometryProvider *v, sv_frame_t frame) const
|
Chris@359
|
188 {
|
Chris@1469
|
189 auto model = ModelById::get(getModel());
|
Chris@1469
|
190 if (model && !model->getAlignmentReference().isNone()) {
|
Chris@1469
|
191 return model->alignToReference(frame);
|
Chris@359
|
192 } else {
|
Chris@918
|
193 return v->getView()->alignToReference(frame);
|
Chris@359
|
194 }
|
Chris@359
|
195 }
|
Chris@359
|
196
|
Chris@904
|
197 sv_frame_t
|
Chris@918
|
198 Layer::alignFromReference(LayerGeometryProvider *v, sv_frame_t frame) const
|
Chris@359
|
199 {
|
Chris@1469
|
200 auto model = ModelById::get(getModel());
|
Chris@1469
|
201 if (model && !model->getAlignmentReference().isNone()) {
|
Chris@1469
|
202 return model->alignFromReference(frame);
|
Chris@359
|
203 } else {
|
Chris@918
|
204 return v->getView()->alignFromReference(frame);
|
Chris@359
|
205 }
|
Chris@359
|
206 }
|
Chris@359
|
207
|
Chris@274
|
208 bool
|
Chris@918
|
209 Layer::clipboardHasDifferentAlignment(LayerGeometryProvider *v, const Clipboard &clip) const
|
Chris@360
|
210 {
|
Chris@360
|
211 // Notes on pasting to an aligned layer:
|
Chris@360
|
212 //
|
Chris@360
|
213 // Each point may have a reference frame that may differ from the
|
Chris@360
|
214 // point's given frame (in its source model). If it has no
|
Chris@360
|
215 // reference frame, we have to assume the source model was not
|
Chris@360
|
216 // aligned or was the reference model: when cutting or copying
|
Chris@360
|
217 // points from a layer, we must always set their reference frame
|
Chris@360
|
218 // correctly if we are aligned.
|
Chris@360
|
219 //
|
Chris@360
|
220 // When pasting:
|
Chris@360
|
221 // - if point's reference and aligned frames differ:
|
Chris@360
|
222 // - if this layer is aligned:
|
Chris@360
|
223 // - if point's aligned frame matches this layer's aligned version
|
Chris@360
|
224 // of point's reference frame:
|
Chris@360
|
225 // - we can paste at reference frame or our frame
|
Chris@360
|
226 // - else
|
Chris@360
|
227 // - we can paste at reference frame, result of aligning reference
|
Chris@360
|
228 // frame in our model, or literal source frame
|
Chris@360
|
229 // - else
|
Chris@360
|
230 // - we can paste at reference (our) frame, or literal source frame
|
Chris@360
|
231 // - else
|
Chris@360
|
232 // - if this layer is aligned:
|
Chris@360
|
233 // - we can paste at reference (point's only available) frame,
|
Chris@360
|
234 // or result of aligning reference frame in our model
|
Chris@360
|
235 // - else
|
Chris@360
|
236 // - we can only paste at reference frame
|
Chris@360
|
237 //
|
Chris@360
|
238 // Which of these alternatives are useful?
|
Chris@360
|
239 //
|
Chris@360
|
240 // Example: we paste between two tracks that are aligned to the
|
Chris@360
|
241 // same reference, and the points are at 10s and 20s in the source
|
Chris@360
|
242 // track, corresponding to 5s and 10s in the reference but 20s and
|
Chris@360
|
243 // 30s in the target track.
|
Chris@360
|
244 //
|
Chris@360
|
245 // The obvious default is to paste at 20s and 30s; if we aren't
|
Chris@360
|
246 // doing that, would it be better to paste at 5s and 10s or at 10s
|
Chris@360
|
247 // and 20s? We probably don't ever want to do the former, do we?
|
Chris@360
|
248 // We either want to be literal all the way through, or aligned
|
Chris@360
|
249 // all the way through.
|
Chris@360
|
250
|
Chris@1423
|
251 for (EventVector::const_iterator i = clip.getPoints().begin();
|
Chris@360
|
252 i != clip.getPoints().end(); ++i) {
|
Chris@360
|
253
|
Chris@360
|
254 // In principle, we want to know whether the aligned version
|
Chris@360
|
255 // of the reference frame in our layer is the same as the
|
Chris@360
|
256 // source frame contained in the clipboard point. However,
|
Chris@360
|
257 // because of rounding during alignment, that won't
|
Chris@360
|
258 // necessarily be the case even if the clipboard point came
|
Chris@360
|
259 // from our layer! What we need to check is whether, if we
|
Chris@360
|
260 // aligned the clipboard point's frame back to the reference
|
Chris@360
|
261 // using this layer's alignment, we would obtain the same
|
Chris@360
|
262 // reference frame as that for the clipboard point.
|
Chris@360
|
263
|
Chris@360
|
264 // What if the clipboard point has no reference frame? Then
|
Chris@360
|
265 // we have to treat it as having its own frame as the
|
Chris@360
|
266 // reference (i.e. having been copied from the reference
|
Chris@360
|
267 // model).
|
Chris@360
|
268
|
Chris@905
|
269 sv_frame_t sourceFrame = i->getFrame();
|
Chris@905
|
270 sv_frame_t referenceFrame = sourceFrame;
|
Chris@1423
|
271 if (i->hasReferenceFrame()) {
|
Chris@360
|
272 referenceFrame = i->getReferenceFrame();
|
Chris@360
|
273 }
|
Chris@905
|
274 sv_frame_t myMappedFrame = alignToReference(v, sourceFrame);
|
Chris@360
|
275
|
Chris@1423
|
276 // cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->hasReferenceFrame() << "), myMappedFrame = " << myMappedFrame << endl;
|
Chris@360
|
277
|
Chris@360
|
278 if (myMappedFrame != referenceFrame) return true;
|
Chris@360
|
279 }
|
Chris@360
|
280
|
Chris@360
|
281 return false;
|
Chris@360
|
282 }
|
Chris@360
|
283
|
Chris@360
|
284 bool
|
Chris@268
|
285 Layer::MeasureRect::operator<(const MeasureRect &mr) const
|
Chris@268
|
286 {
|
Chris@268
|
287 if (haveFrames) {
|
Chris@268
|
288 if (startFrame == mr.startFrame) {
|
Chris@268
|
289 if (endFrame != mr.endFrame) {
|
Chris@268
|
290 return endFrame < mr.endFrame;
|
Chris@268
|
291 }
|
Chris@268
|
292 } else {
|
Chris@268
|
293 return startFrame < mr.startFrame;
|
Chris@268
|
294 }
|
Chris@268
|
295 } else {
|
Chris@268
|
296 if (pixrect.x() == mr.pixrect.x()) {
|
Chris@268
|
297 if (pixrect.width() != mr.pixrect.width()) {
|
Chris@268
|
298 return pixrect.width() < mr.pixrect.width();
|
Chris@268
|
299 }
|
Chris@268
|
300 } else {
|
Chris@268
|
301 return pixrect.x() < mr.pixrect.x();
|
Chris@268
|
302 }
|
Chris@268
|
303 }
|
Chris@268
|
304
|
Chris@268
|
305 // the two rects are equal in x and width
|
Chris@268
|
306
|
Chris@268
|
307 if (pixrect.y() == mr.pixrect.y()) {
|
Chris@268
|
308 return pixrect.height() < mr.pixrect.height();
|
Chris@268
|
309 } else {
|
Chris@268
|
310 return pixrect.y() < mr.pixrect.y();
|
Chris@268
|
311 }
|
Chris@268
|
312 }
|
Chris@268
|
313
|
Chris@316
|
314 void
|
Chris@316
|
315 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
|
Chris@269
|
316 {
|
Chris@316
|
317 stream << indent;
|
Chris@316
|
318 stream << QString("<measurement ");
|
Chris@269
|
319
|
Chris@269
|
320 if (haveFrames) {
|
Chris@316
|
321 stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
|
Chris@269
|
322 .arg(startFrame).arg(endFrame);
|
Chris@269
|
323 } else {
|
Chris@316
|
324 stream << QString("startX=\"%1\" endX=\"%2\" ")
|
Chris@316
|
325 .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
|
Chris@269
|
326 }
|
Chris@269
|
327
|
Chris@316
|
328 stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
|
Chris@273
|
329 .arg(startY).arg(endY);
|
Chris@269
|
330 }
|
Chris@269
|
331
|
Chris@269
|
332 void
|
Chris@269
|
333 Layer::addMeasurementRect(const QXmlAttributes &attributes)
|
Chris@269
|
334 {
|
Chris@269
|
335 MeasureRect rect;
|
Chris@269
|
336 QString fs = attributes.value("startFrame");
|
Chris@273
|
337 int x0 = 0, x1 = 0;
|
Chris@269
|
338 if (fs != "") {
|
Chris@806
|
339 rect.startFrame = fs.toInt();
|
Chris@806
|
340 rect.endFrame = attributes.value("endFrame").toInt();
|
Chris@269
|
341 rect.haveFrames = true;
|
Chris@269
|
342 } else {
|
Chris@269
|
343 x0 = attributes.value("startX").toInt();
|
Chris@269
|
344 x1 = attributes.value("endX").toInt();
|
Chris@269
|
345 rect.haveFrames = false;
|
Chris@269
|
346 }
|
Chris@273
|
347 rect.startY = attributes.value("startY").toDouble();
|
Chris@273
|
348 rect.endY = attributes.value("endY").toDouble();
|
Chris@273
|
349 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
|
Chris@269
|
350 addMeasureRectToSet(rect);
|
Chris@269
|
351 }
|
Chris@269
|
352
|
Chris@269
|
353 QString
|
Chris@268
|
354 Layer::AddMeasurementRectCommand::getName() const
|
Chris@268
|
355 {
|
Chris@268
|
356 return tr("Make Measurement");
|
Chris@268
|
357 }
|
Chris@268
|
358
|
Chris@268
|
359 void
|
Chris@268
|
360 Layer::AddMeasurementRectCommand::execute()
|
Chris@268
|
361 {
|
Chris@269
|
362 m_layer->addMeasureRectToSet(m_rect);
|
Chris@268
|
363 }
|
Chris@268
|
364
|
Chris@268
|
365 void
|
Chris@268
|
366 Layer::AddMeasurementRectCommand::unexecute()
|
Chris@268
|
367 {
|
Chris@269
|
368 m_layer->deleteMeasureRectFromSet(m_rect);
|
Chris@268
|
369 }
|
Chris@268
|
370
|
Chris@283
|
371 QString
|
Chris@283
|
372 Layer::DeleteMeasurementRectCommand::getName() const
|
Chris@283
|
373 {
|
Chris@283
|
374 return tr("Delete Measurement");
|
Chris@283
|
375 }
|
Chris@283
|
376
|
Chris@283
|
377 void
|
Chris@283
|
378 Layer::DeleteMeasurementRectCommand::execute()
|
Chris@283
|
379 {
|
Chris@283
|
380 m_layer->deleteMeasureRectFromSet(m_rect);
|
Chris@283
|
381 }
|
Chris@283
|
382
|
Chris@283
|
383 void
|
Chris@283
|
384 Layer::DeleteMeasurementRectCommand::unexecute()
|
Chris@283
|
385 {
|
Chris@283
|
386 m_layer->addMeasureRectToSet(m_rect);
|
Chris@283
|
387 }
|
Chris@283
|
388
|
Chris@267
|
389 void
|
Chris@918
|
390 Layer::measureStart(LayerGeometryProvider *v, QMouseEvent *e)
|
Chris@267
|
391 {
|
Chris@1434
|
392 m_draggingRect.haveFrames = hasTimeXAxis();
|
Chris@1434
|
393
|
Chris@1434
|
394 // NB if haveFrames, then pixrect x and width will be rewritten on
|
Chris@1434
|
395 // every paint according to the current locations of the
|
Chris@1434
|
396 // definitive frame values. So we should set the start frame value
|
Chris@1434
|
397 // once on measureStart, and then not modify it on drag (to avoid
|
Chris@1434
|
398 // drift from repeated conversion back and forth).
|
Chris@1434
|
399
|
Chris@1434
|
400 m_draggingRect.pixrect = QRect(e->x(), e->y(), 0, 0);
|
Chris@1434
|
401
|
Chris@1434
|
402 if (m_draggingRect.haveFrames) {
|
Chris@1434
|
403 m_draggingRect.startFrame = v->getFrameForX(e->x());
|
Chris@1434
|
404 m_draggingRect.endFrame = v->getFrameForX(e->x());
|
Chris@1434
|
405 }
|
Chris@1434
|
406
|
Chris@1434
|
407 setMeasureRectYCoord(v, m_draggingRect, true, e->y());
|
Chris@1434
|
408 setMeasureRectYCoord(v, m_draggingRect, false, e->y());
|
Chris@1434
|
409
|
Chris@267
|
410 m_haveDraggingRect = true;
|
Chris@267
|
411 }
|
Chris@267
|
412
|
Chris@267
|
413 void
|
Chris@918
|
414 Layer::measureDrag(LayerGeometryProvider *v, QMouseEvent *e)
|
Chris@267
|
415 {
|
Chris@267
|
416 if (!m_haveDraggingRect) return;
|
Chris@268
|
417
|
Chris@1434
|
418 m_draggingRect.pixrect.setHeight(e->y() - m_draggingRect.pixrect.y());
|
Chris@1434
|
419
|
Chris@1434
|
420 if (m_draggingRect.haveFrames) {
|
Chris@1434
|
421 m_draggingRect.endFrame = v->getFrameForX(e->x());
|
Chris@1434
|
422 } else {
|
Chris@1434
|
423 m_draggingRect.pixrect.setWidth(e->x() - m_draggingRect.pixrect.x());
|
Chris@1434
|
424 }
|
Chris@1434
|
425
|
Chris@1434
|
426 setMeasureRectYCoord(v, m_draggingRect, false, e->y());
|
Chris@267
|
427 }
|
Chris@267
|
428
|
Chris@267
|
429 void
|
Chris@918
|
430 Layer::measureEnd(LayerGeometryProvider *v, QMouseEvent *e)
|
Chris@267
|
431 {
|
Chris@267
|
432 if (!m_haveDraggingRect) return;
|
Chris@267
|
433 measureDrag(v, e);
|
Chris@283
|
434
|
Chris@283
|
435 if (!m_draggingRect.pixrect.isNull()) {
|
Chris@283
|
436 CommandHistory::getInstance()->addCommand
|
Chris@283
|
437 (new AddMeasurementRectCommand(this, m_draggingRect));
|
Chris@283
|
438 }
|
Chris@268
|
439
|
Chris@267
|
440 m_haveDraggingRect = false;
|
Chris@267
|
441 }
|
Chris@267
|
442
|
Chris@267
|
443 void
|
Chris@918
|
444 Layer::measureDoubleClick(LayerGeometryProvider *, QMouseEvent *)
|
Chris@280
|
445 {
|
Chris@283
|
446 // nothing, in the base class
|
Chris@283
|
447 }
|
Chris@283
|
448
|
Chris@283
|
449 void
|
Chris@283
|
450 Layer::deleteCurrentMeasureRect()
|
Chris@283
|
451 {
|
Chris@283
|
452 if (!m_haveCurrentMeasureRect) return;
|
Chris@283
|
453
|
Chris@283
|
454 MeasureRectSet::const_iterator focusRectItr =
|
Chris@283
|
455 findFocusedMeasureRect(m_currentMeasureRectPoint);
|
Chris@283
|
456
|
Chris@283
|
457 if (focusRectItr == m_measureRects.end()) return;
|
Chris@283
|
458
|
Chris@283
|
459 CommandHistory::getInstance()->addCommand
|
Chris@283
|
460 (new DeleteMeasurementRectCommand(this, *focusRectItr));
|
Chris@280
|
461 }
|
Chris@280
|
462
|
Chris@280
|
463 void
|
Chris@918
|
464 Layer::paintMeasurementRects(LayerGeometryProvider *v, QPainter &paint,
|
Chris@272
|
465 bool showFocus, QPoint focusPoint) const
|
Chris@267
|
466 {
|
Chris@273
|
467 updateMeasurePixrects(v);
|
Chris@272
|
468
|
Chris@272
|
469 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
|
Chris@272
|
470
|
Chris@267
|
471 if (m_haveDraggingRect) {
|
Chris@272
|
472
|
Chris@270
|
473 paintMeasurementRect(v, paint, m_draggingRect, true);
|
Chris@272
|
474
|
Chris@272
|
475 } else if (showFocus) {
|
Chris@272
|
476
|
Chris@272
|
477 focusRectItr = findFocusedMeasureRect(focusPoint);
|
Chris@267
|
478 }
|
Chris@267
|
479
|
Chris@283
|
480 m_haveCurrentMeasureRect = false;
|
Chris@283
|
481
|
Chris@268
|
482 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@268
|
483 i != m_measureRects.end(); ++i) {
|
Chris@283
|
484
|
Chris@283
|
485 bool focused = (i == focusRectItr);
|
Chris@283
|
486 paintMeasurementRect(v, paint, *i, focused);
|
Chris@283
|
487
|
Chris@283
|
488 if (focused) {
|
Chris@283
|
489 m_haveCurrentMeasureRect = true;
|
Chris@283
|
490 m_currentMeasureRectPoint = focusPoint;
|
Chris@283
|
491 }
|
Chris@267
|
492 }
|
Chris@267
|
493 }
|
Chris@267
|
494
|
Chris@272
|
495 bool
|
Chris@918
|
496 Layer::nearestMeasurementRectChanged(LayerGeometryProvider *v, QPoint prev, QPoint now) const
|
Chris@272
|
497 {
|
Chris@273
|
498 updateMeasurePixrects(v);
|
Chris@272
|
499
|
Chris@272
|
500 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
|
Chris@272
|
501 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
|
Chris@272
|
502
|
Chris@272
|
503 return (i0 != i1);
|
Chris@272
|
504 }
|
Chris@272
|
505
|
Chris@272
|
506 void
|
Chris@918
|
507 Layer::updateMeasurePixrects(LayerGeometryProvider *v) const
|
Chris@272
|
508 {
|
Chris@905
|
509 sv_frame_t sf = v->getStartFrame();
|
Chris@905
|
510 sv_frame_t ef = v->getEndFrame();
|
Chris@272
|
511
|
Chris@272
|
512 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@272
|
513 i != m_measureRects.end(); ++i) {
|
Chris@272
|
514
|
Chris@273
|
515 // This logic depends on the fact that if one measure rect in
|
Chris@273
|
516 // a layer has frame values, they all will. That is in fact
|
Chris@273
|
517 // the case, because haveFrames is based on whether the layer
|
Chris@273
|
518 // hasTimeXAxis() or not. Measure rect ordering in the rect
|
Chris@273
|
519 // set wouldn't work correctly either, if haveFrames could
|
Chris@273
|
520 // vary.
|
Chris@272
|
521
|
Chris@273
|
522 if (i->haveFrames) {
|
Chris@273
|
523 if (i->startFrame >= ef) break;
|
Chris@273
|
524 if (i->endFrame <= sf) continue;
|
Chris@273
|
525 }
|
Chris@272
|
526
|
Chris@273
|
527 int x0 = i->pixrect.x();
|
Chris@273
|
528 int x1 = x0 + i->pixrect.width();
|
Chris@273
|
529
|
Chris@273
|
530 if (i->haveFrames) {
|
Chris@273
|
531 if (i->startFrame >= v->getStartFrame()) {
|
Chris@273
|
532 x0 = v->getXForFrame(i->startFrame);
|
Chris@273
|
533 }
|
Chris@806
|
534 if (i->endFrame <= int(v->getEndFrame())) {
|
Chris@273
|
535 x1 = v->getXForFrame(i->endFrame);
|
Chris@273
|
536 }
|
Chris@272
|
537 }
|
Chris@272
|
538
|
Chris@273
|
539 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
|
Chris@273
|
540
|
Chris@273
|
541 updateMeasureRectYCoords(v, *i);
|
Chris@273
|
542 }
|
Chris@273
|
543 }
|
Chris@273
|
544
|
Chris@273
|
545 void
|
Chris@918
|
546 Layer::updateMeasureRectYCoords(LayerGeometryProvider *v, const MeasureRect &r) const
|
Chris@273
|
547 {
|
Chris@918
|
548 int y0 = int(lrint(r.startY * v->getPaintHeight()));
|
Chris@918
|
549 int y1 = int(lrint(r.endY * v->getPaintHeight()));
|
Chris@273
|
550 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
|
Chris@273
|
551 }
|
Chris@273
|
552
|
Chris@273
|
553 void
|
Chris@918
|
554 Layer::setMeasureRectYCoord(LayerGeometryProvider *v, MeasureRect &r, bool start, int y) const
|
Chris@273
|
555 {
|
Chris@273
|
556 if (start) {
|
Chris@918
|
557 r.startY = double(y) / double(v->getPaintHeight());
|
Chris@273
|
558 r.endY = r.startY;
|
Chris@273
|
559 } else {
|
Chris@918
|
560 r.endY = double(y) / double(v->getPaintHeight());
|
Chris@272
|
561 }
|
Chris@272
|
562 }
|
Chris@272
|
563
|
Chris@283
|
564 void
|
Chris@918
|
565 Layer::setMeasureRectFromPixrect(LayerGeometryProvider *v, MeasureRect &r, QRect pixrect) const
|
Chris@283
|
566 {
|
Chris@283
|
567 r.pixrect = pixrect;
|
Chris@283
|
568 r.haveFrames = hasTimeXAxis();
|
Chris@283
|
569 if (r.haveFrames) {
|
Chris@283
|
570 r.startFrame = v->getFrameForX(pixrect.x());
|
Chris@283
|
571 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
|
Chris@283
|
572 }
|
Chris@283
|
573 setMeasureRectYCoord(v, r, true, pixrect.y());
|
Chris@283
|
574 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
|
Chris@283
|
575 }
|
Chris@283
|
576
|
Chris@272
|
577 Layer::MeasureRectSet::const_iterator
|
Chris@272
|
578 Layer::findFocusedMeasureRect(QPoint focusPoint) const
|
Chris@272
|
579 {
|
Chris@904
|
580 double frDist = 0;
|
Chris@272
|
581 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
|
Chris@272
|
582
|
Chris@272
|
583 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@272
|
584 i != m_measureRects.end(); ++i) {
|
Chris@272
|
585
|
Chris@272
|
586 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
|
Chris@272
|
587
|
Chris@272
|
588 int cx = i->pixrect.x() + i->pixrect.width()/2;
|
Chris@272
|
589 int cy = i->pixrect.y() + i->pixrect.height()/2;
|
Chris@272
|
590 int xd = focusPoint.x() - cx;
|
Chris@272
|
591 int yd = focusPoint.y() - cy;
|
Chris@272
|
592
|
Chris@904
|
593 double d = sqrt(double(xd * xd + yd * yd));
|
Chris@272
|
594
|
Chris@272
|
595 if (focusRectItr == m_measureRects.end() || d < frDist) {
|
Chris@272
|
596 focusRectItr = i;
|
Chris@272
|
597 frDist = d;
|
Chris@272
|
598 }
|
Chris@272
|
599 }
|
Chris@272
|
600
|
Chris@272
|
601 return focusRectItr;
|
Chris@272
|
602 }
|
Chris@272
|
603
|
Chris@268
|
604 void
|
Chris@918
|
605 Layer::paintMeasurementRect(LayerGeometryProvider *v, QPainter &paint,
|
Chris@270
|
606 const MeasureRect &r, bool focus) const
|
Chris@268
|
607 {
|
Chris@268
|
608 if (r.haveFrames) {
|
Chris@268
|
609
|
Chris@268
|
610 int x0 = -1;
|
Chris@918
|
611 int x1 = v->getPaintWidth() + 1;
|
Chris@268
|
612
|
Chris@268
|
613 if (r.startFrame >= v->getStartFrame()) {
|
Chris@268
|
614 x0 = v->getXForFrame(r.startFrame);
|
Chris@268
|
615 }
|
Chris@806
|
616 if (r.endFrame <= v->getEndFrame()) {
|
Chris@268
|
617 x1 = v->getXForFrame(r.endFrame);
|
Chris@268
|
618 }
|
Chris@268
|
619
|
Chris@272
|
620 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
|
Chris@268
|
621 r.pixrect = pr;
|
Chris@268
|
622 }
|
Chris@274
|
623
|
Chris@274
|
624 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
|
Chris@268
|
625 }
|
Chris@268
|
626
|
Chris@1315
|
627 bool
|
Chris@1315
|
628 Layer::valueExtentsMatchMine(LayerGeometryProvider *v) const
|
Chris@1315
|
629 {
|
Chris@1315
|
630 double min, min_;
|
Chris@1315
|
631 double max, max_;
|
Chris@1315
|
632 bool logarithmic, logarithmic_;
|
Chris@1315
|
633 QString unit;
|
Chris@1315
|
634
|
Chris@1315
|
635 if (!getValueExtents(min_, max_, logarithmic_, unit)) {
|
Chris@1315
|
636 return false;
|
Chris@1315
|
637 }
|
Chris@1315
|
638
|
Chris@1537
|
639 if (!v->getVisibleExtentsForUnit(unit, min, max, logarithmic)) {
|
Chris@1315
|
640 return false;
|
Chris@1315
|
641 }
|
Chris@1315
|
642
|
Chris@1315
|
643 if (min != min_ ||
|
Chris@1315
|
644 max != max_ ||
|
Chris@1315
|
645 logarithmic != logarithmic_) {
|
Chris@1315
|
646 return false;
|
Chris@1315
|
647 }
|
Chris@1315
|
648
|
Chris@1315
|
649 return true;
|
Chris@1315
|
650 }
|
Chris@1315
|
651
|
Chris@316
|
652 void
|
Chris@316
|
653 Layer::toXml(QTextStream &stream,
|
Chris@316
|
654 QString indent, QString extraAttributes) const
|
Chris@268
|
655 {
|
Chris@316
|
656 stream << indent;
|
Chris@268
|
657
|
Chris@363
|
658 if (m_presentationName != "") {
|
Chris@363
|
659 extraAttributes = QString("%1 presentationName=\"%2\"")
|
Chris@363
|
660 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
|
Chris@363
|
661 }
|
Chris@363
|
662
|
Chris@1469
|
663 int modelExportId = -1;
|
Chris@1469
|
664 auto model = ModelById::get(getModel());
|
Chris@1469
|
665 if (model) modelExportId = model->getExportId();
|
Chris@1469
|
666
|
Chris@316
|
667 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
|
Chris@1266
|
668 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
|
Chris@268
|
669 (LayerFactory::getInstance()->getLayerType(this))))
|
Chris@1439
|
670 .arg(getExportId())
|
Chris@1266
|
671 .arg(encodeEntities(objectName()))
|
Chris@1469
|
672 .arg(modelExportId)
|
Chris@1266
|
673 .arg(extraAttributes);
|
Chris@268
|
674
|
Chris@269
|
675 if (m_measureRects.empty()) {
|
Chris@316
|
676 stream << QString("/>\n");
|
Chris@316
|
677 return;
|
Chris@269
|
678 }
|
Chris@269
|
679
|
Chris@316
|
680 stream << QString(">\n");
|
Chris@269
|
681
|
Chris@269
|
682 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@269
|
683 i != m_measureRects.end(); ++i) {
|
Chris@316
|
684 i->toXml(stream, indent + " ");
|
Chris@269
|
685 }
|
Chris@269
|
686
|
Chris@316
|
687 stream << QString("</layer>\n");
|
Chris@268
|
688 }
|
Chris@269
|
689
|
Chris@316
|
690 void
|
Chris@316
|
691 Layer::toBriefXml(QTextStream &stream,
|
Chris@316
|
692 QString indent, QString extraAttributes) const
|
Chris@269
|
693 {
|
Chris@316
|
694 stream << indent;
|
Chris@269
|
695
|
Chris@363
|
696 if (m_presentationName != "") {
|
Chris@363
|
697 extraAttributes = QString("%1 presentationName=\"%2\"")
|
Chris@363
|
698 .arg(extraAttributes).arg(encodeEntities(m_presentationName));
|
Chris@363
|
699 }
|
Chris@363
|
700
|
Chris@1469
|
701 int modelExportId = -1;
|
Chris@1469
|
702 auto model = ModelById::get(getModel());
|
Chris@1469
|
703 if (model) modelExportId = model->getExportId();
|
Chris@1469
|
704
|
Chris@316
|
705 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
|
Chris@1266
|
706 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
|
Chris@269
|
707 (LayerFactory::getInstance()->getLayerType(this))))
|
Chris@1439
|
708 .arg(getExportId())
|
Chris@1266
|
709 .arg(encodeEntities(objectName()))
|
Chris@1469
|
710 .arg(modelExportId)
|
Chris@269
|
711 .arg(extraAttributes);
|
Chris@269
|
712 }
|
Chris@269
|
713
|