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@268
|
19 #include "base/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@127
|
45 // std::cerr << "Layer::~Layer(" << this << ")" << std::endl;
|
Chris@127
|
46 }
|
Chris@127
|
47
|
Chris@320
|
48 void
|
Chris@320
|
49 Layer::connectSignals(const Model *model)
|
Chris@320
|
50 {
|
Chris@320
|
51 connect(model, SIGNAL(modelChanged()),
|
Chris@320
|
52 this, SIGNAL(modelChanged()));
|
Chris@320
|
53
|
Chris@320
|
54 connect(model, SIGNAL(modelChanged(size_t, size_t)),
|
Chris@320
|
55 this, SIGNAL(modelChanged(size_t, size_t)));
|
Chris@320
|
56
|
Chris@320
|
57 connect(model, SIGNAL(completionChanged()),
|
Chris@320
|
58 this, SIGNAL(modelCompletionChanged()));
|
Chris@320
|
59
|
Chris@320
|
60 connect(model, SIGNAL(alignmentCompletionChanged()),
|
Chris@320
|
61 this, SIGNAL(modelAlignmentCompletionChanged()));
|
Chris@320
|
62 }
|
Chris@320
|
63
|
Chris@127
|
64 QString
|
Chris@127
|
65 Layer::getPropertyContainerIconName() const
|
Chris@127
|
66 {
|
Chris@127
|
67 return LayerFactory::getInstance()->getLayerIconName
|
Chris@127
|
68 (LayerFactory::getInstance()->getLayerType(this));
|
Chris@127
|
69 }
|
Chris@127
|
70
|
Chris@127
|
71 QString
|
Chris@127
|
72 Layer::getLayerPresentationName() const
|
Chris@127
|
73 {
|
Chris@203
|
74 // QString layerName = objectName();
|
Chris@203
|
75
|
Chris@203
|
76 LayerFactory *factory = LayerFactory::getInstance();
|
Chris@203
|
77 QString layerName = factory->getLayerPresentationName
|
Chris@203
|
78 (factory->getLayerType(this));
|
Chris@203
|
79
|
Chris@127
|
80 QString modelName;
|
Chris@127
|
81 if (getModel()) modelName = getModel()->objectName();
|
Chris@127
|
82
|
Chris@127
|
83 QString text;
|
Chris@127
|
84 if (modelName != "") {
|
Chris@127
|
85 text = QString("%1: %2").arg(modelName).arg(layerName);
|
Chris@127
|
86 } else {
|
Chris@127
|
87 text = layerName;
|
Chris@127
|
88 }
|
Chris@127
|
89
|
Chris@127
|
90 return text;
|
Chris@127
|
91 }
|
Chris@127
|
92
|
Chris@127
|
93 void
|
Chris@127
|
94 Layer::setObjectName(const QString &name)
|
Chris@127
|
95 {
|
Chris@127
|
96 QObject::setObjectName(name);
|
Chris@127
|
97 emit layerNameChanged();
|
Chris@127
|
98 }
|
Chris@127
|
99
|
Chris@127
|
100 PlayParameters *
|
Chris@127
|
101 Layer::getPlayParameters()
|
Chris@127
|
102 {
|
Chris@127
|
103 // std::cerr << "Layer (" << this << ", " << objectName().toStdString() << ")::getPlayParameters: model is "<< getModel() << std::endl;
|
Chris@127
|
104 const Model *model = getModel();
|
Chris@127
|
105 if (model) {
|
Chris@127
|
106 return PlayParameterRepository::getInstance()->getPlayParameters(model);
|
Chris@127
|
107 }
|
Chris@127
|
108 return 0;
|
Chris@127
|
109 }
|
Chris@127
|
110
|
Chris@127
|
111 void
|
Chris@131
|
112 Layer::setLayerDormant(const View *v, bool dormant)
|
Chris@131
|
113 {
|
Chris@131
|
114 const void *vv = (const void *)v;
|
Chris@131
|
115 QMutexLocker locker(&m_dormancyMutex);
|
Chris@131
|
116 m_dormancy[vv] = dormant;
|
Chris@131
|
117 }
|
Chris@131
|
118
|
Chris@131
|
119 bool
|
Chris@131
|
120 Layer::isLayerDormant(const View *v) const
|
Chris@131
|
121 {
|
Chris@131
|
122 const void *vv = (const void *)v;
|
Chris@131
|
123 QMutexLocker locker(&m_dormancyMutex);
|
Chris@131
|
124 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
|
Chris@131
|
125 return m_dormancy.find(vv)->second;
|
Chris@131
|
126 }
|
Chris@131
|
127
|
Chris@131
|
128 void
|
Chris@127
|
129 Layer::showLayer(View *view, bool show)
|
Chris@127
|
130 {
|
Chris@127
|
131 setLayerDormant(view, !show);
|
Chris@127
|
132 emit layerParametersChanged();
|
Chris@127
|
133 }
|
Chris@127
|
134
|
Chris@260
|
135 bool
|
Chris@267
|
136 Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
|
Chris@260
|
137 {
|
Chris@260
|
138 if (!hasTimeXAxis()) return false;
|
Chris@260
|
139
|
Chris@260
|
140 const Model *m = getModel();
|
Chris@260
|
141 if (!m) return false;
|
Chris@260
|
142
|
Chris@260
|
143 value = float(v->getFrameForX(x)) / m->getSampleRate();
|
Chris@260
|
144 unit = "s";
|
Chris@260
|
145 return true;
|
Chris@260
|
146 }
|
Chris@260
|
147
|
Chris@268
|
148 bool
|
Chris@274
|
149 Layer::getYScaleDifference(const View *v, int y0, int y1,
|
Chris@274
|
150 float &diff, QString &unit) const
|
Chris@274
|
151 {
|
Chris@274
|
152 float v0, v1;
|
Chris@274
|
153 if (!getYScaleValue(v, y0, v0, unit) ||
|
Chris@274
|
154 !getYScaleValue(v, y1, v1, unit)) {
|
Chris@274
|
155 diff = 0.f;
|
Chris@274
|
156 return false;
|
Chris@274
|
157 }
|
Chris@274
|
158 diff = fabsf(v1 - v0);
|
Chris@274
|
159 return true;
|
Chris@274
|
160 }
|
Chris@274
|
161
|
Chris@359
|
162 size_t
|
Chris@359
|
163 Layer::alignToReference(View *v, size_t frame) const
|
Chris@359
|
164 {
|
Chris@359
|
165 const Model *m = getModel();
|
Chris@359
|
166 std::cerr << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << std::endl;
|
Chris@359
|
167 if (m && m->getAlignmentReference()) {
|
Chris@359
|
168 return m->alignToReference(frame);
|
Chris@359
|
169 } else {
|
Chris@359
|
170 return v->alignToReference(frame);
|
Chris@359
|
171 }
|
Chris@359
|
172 }
|
Chris@359
|
173
|
Chris@359
|
174 size_t
|
Chris@359
|
175 Layer::alignFromReference(View *v, size_t frame) const
|
Chris@359
|
176 {
|
Chris@359
|
177 const Model *m = getModel();
|
Chris@359
|
178 std::cerr << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << std::endl;
|
Chris@359
|
179 if (m && m->getAlignmentReference()) {
|
Chris@359
|
180 return m->alignFromReference(frame);
|
Chris@359
|
181 } else {
|
Chris@359
|
182 return v->alignFromReference(frame);
|
Chris@359
|
183 }
|
Chris@359
|
184 }
|
Chris@359
|
185
|
Chris@274
|
186 bool
|
Chris@360
|
187 Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const
|
Chris@360
|
188 {
|
Chris@360
|
189 // Notes on pasting to an aligned layer:
|
Chris@360
|
190 //
|
Chris@360
|
191 // Each point may have a reference frame that may differ from the
|
Chris@360
|
192 // point's given frame (in its source model). If it has no
|
Chris@360
|
193 // reference frame, we have to assume the source model was not
|
Chris@360
|
194 // aligned or was the reference model: when cutting or copying
|
Chris@360
|
195 // points from a layer, we must always set their reference frame
|
Chris@360
|
196 // correctly if we are aligned.
|
Chris@360
|
197 //
|
Chris@360
|
198 // When pasting:
|
Chris@360
|
199 // - if point's reference and aligned frames differ:
|
Chris@360
|
200 // - if this layer is aligned:
|
Chris@360
|
201 // - if point's aligned frame matches this layer's aligned version
|
Chris@360
|
202 // of point's reference frame:
|
Chris@360
|
203 // - we can paste at reference frame or our frame
|
Chris@360
|
204 // - else
|
Chris@360
|
205 // - we can paste at reference frame, result of aligning reference
|
Chris@360
|
206 // frame in our model, or literal source frame
|
Chris@360
|
207 // - else
|
Chris@360
|
208 // - we can paste at reference (our) frame, or literal source frame
|
Chris@360
|
209 // - else
|
Chris@360
|
210 // - if this layer is aligned:
|
Chris@360
|
211 // - we can paste at reference (point's only available) frame,
|
Chris@360
|
212 // or result of aligning reference frame in our model
|
Chris@360
|
213 // - else
|
Chris@360
|
214 // - we can only paste at reference frame
|
Chris@360
|
215 //
|
Chris@360
|
216 // Which of these alternatives are useful?
|
Chris@360
|
217 //
|
Chris@360
|
218 // Example: we paste between two tracks that are aligned to the
|
Chris@360
|
219 // same reference, and the points are at 10s and 20s in the source
|
Chris@360
|
220 // track, corresponding to 5s and 10s in the reference but 20s and
|
Chris@360
|
221 // 30s in the target track.
|
Chris@360
|
222 //
|
Chris@360
|
223 // The obvious default is to paste at 20s and 30s; if we aren't
|
Chris@360
|
224 // doing that, would it be better to paste at 5s and 10s or at 10s
|
Chris@360
|
225 // and 20s? We probably don't ever want to do the former, do we?
|
Chris@360
|
226 // We either want to be literal all the way through, or aligned
|
Chris@360
|
227 // all the way through.
|
Chris@360
|
228
|
Chris@360
|
229 for (Clipboard::PointList::const_iterator i = clip.getPoints().begin();
|
Chris@360
|
230 i != clip.getPoints().end(); ++i) {
|
Chris@360
|
231
|
Chris@360
|
232 // In principle, we want to know whether the aligned version
|
Chris@360
|
233 // of the reference frame in our layer is the same as the
|
Chris@360
|
234 // source frame contained in the clipboard point. However,
|
Chris@360
|
235 // because of rounding during alignment, that won't
|
Chris@360
|
236 // necessarily be the case even if the clipboard point came
|
Chris@360
|
237 // from our layer! What we need to check is whether, if we
|
Chris@360
|
238 // aligned the clipboard point's frame back to the reference
|
Chris@360
|
239 // using this layer's alignment, we would obtain the same
|
Chris@360
|
240 // reference frame as that for the clipboard point.
|
Chris@360
|
241
|
Chris@360
|
242 // What if the clipboard point has no reference frame? Then
|
Chris@360
|
243 // we have to treat it as having its own frame as the
|
Chris@360
|
244 // reference (i.e. having been copied from the reference
|
Chris@360
|
245 // model).
|
Chris@360
|
246
|
Chris@360
|
247 long sourceFrame = i->getFrame();
|
Chris@360
|
248 long referenceFrame = sourceFrame;
|
Chris@360
|
249 if (i->haveReferenceFrame()) {
|
Chris@360
|
250 referenceFrame = i->getReferenceFrame();
|
Chris@360
|
251 }
|
Chris@360
|
252 long myMappedFrame = alignToReference(v, sourceFrame);
|
Chris@360
|
253
|
Chris@360
|
254 // std::cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << std::endl;
|
Chris@360
|
255
|
Chris@360
|
256 if (myMappedFrame != referenceFrame) return true;
|
Chris@360
|
257 }
|
Chris@360
|
258
|
Chris@360
|
259 return false;
|
Chris@360
|
260 }
|
Chris@360
|
261
|
Chris@360
|
262 bool
|
Chris@268
|
263 Layer::MeasureRect::operator<(const MeasureRect &mr) const
|
Chris@268
|
264 {
|
Chris@268
|
265 if (haveFrames) {
|
Chris@268
|
266 if (startFrame == mr.startFrame) {
|
Chris@268
|
267 if (endFrame != mr.endFrame) {
|
Chris@268
|
268 return endFrame < mr.endFrame;
|
Chris@268
|
269 }
|
Chris@268
|
270 } else {
|
Chris@268
|
271 return startFrame < mr.startFrame;
|
Chris@268
|
272 }
|
Chris@268
|
273 } else {
|
Chris@268
|
274 if (pixrect.x() == mr.pixrect.x()) {
|
Chris@268
|
275 if (pixrect.width() != mr.pixrect.width()) {
|
Chris@268
|
276 return pixrect.width() < mr.pixrect.width();
|
Chris@268
|
277 }
|
Chris@268
|
278 } else {
|
Chris@268
|
279 return pixrect.x() < mr.pixrect.x();
|
Chris@268
|
280 }
|
Chris@268
|
281 }
|
Chris@268
|
282
|
Chris@268
|
283 // the two rects are equal in x and width
|
Chris@268
|
284
|
Chris@268
|
285 if (pixrect.y() == mr.pixrect.y()) {
|
Chris@268
|
286 return pixrect.height() < mr.pixrect.height();
|
Chris@268
|
287 } else {
|
Chris@268
|
288 return pixrect.y() < mr.pixrect.y();
|
Chris@268
|
289 }
|
Chris@268
|
290 }
|
Chris@268
|
291
|
Chris@316
|
292 void
|
Chris@316
|
293 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
|
Chris@269
|
294 {
|
Chris@316
|
295 stream << indent;
|
Chris@316
|
296 stream << QString("<measurement ");
|
Chris@269
|
297
|
Chris@269
|
298 if (haveFrames) {
|
Chris@316
|
299 stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
|
Chris@269
|
300 .arg(startFrame).arg(endFrame);
|
Chris@269
|
301 } else {
|
Chris@316
|
302 stream << QString("startX=\"%1\" endX=\"%2\" ")
|
Chris@316
|
303 .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
|
Chris@269
|
304 }
|
Chris@269
|
305
|
Chris@316
|
306 stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
|
Chris@273
|
307 .arg(startY).arg(endY);
|
Chris@269
|
308 }
|
Chris@269
|
309
|
Chris@269
|
310 void
|
Chris@269
|
311 Layer::addMeasurementRect(const QXmlAttributes &attributes)
|
Chris@269
|
312 {
|
Chris@269
|
313 MeasureRect rect;
|
Chris@269
|
314 QString fs = attributes.value("startFrame");
|
Chris@273
|
315 int x0 = 0, x1 = 0;
|
Chris@269
|
316 if (fs != "") {
|
Chris@269
|
317 rect.startFrame = fs.toLong();
|
Chris@269
|
318 rect.endFrame = attributes.value("endFrame").toLong();
|
Chris@269
|
319 rect.haveFrames = true;
|
Chris@269
|
320 } else {
|
Chris@269
|
321 x0 = attributes.value("startX").toInt();
|
Chris@269
|
322 x1 = attributes.value("endX").toInt();
|
Chris@269
|
323 rect.haveFrames = false;
|
Chris@269
|
324 }
|
Chris@273
|
325 rect.startY = attributes.value("startY").toDouble();
|
Chris@273
|
326 rect.endY = attributes.value("endY").toDouble();
|
Chris@273
|
327 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
|
Chris@269
|
328 addMeasureRectToSet(rect);
|
Chris@269
|
329 }
|
Chris@269
|
330
|
Chris@269
|
331 QString
|
Chris@268
|
332 Layer::AddMeasurementRectCommand::getName() const
|
Chris@268
|
333 {
|
Chris@268
|
334 return tr("Make Measurement");
|
Chris@268
|
335 }
|
Chris@268
|
336
|
Chris@268
|
337 void
|
Chris@268
|
338 Layer::AddMeasurementRectCommand::execute()
|
Chris@268
|
339 {
|
Chris@269
|
340 m_layer->addMeasureRectToSet(m_rect);
|
Chris@268
|
341 }
|
Chris@268
|
342
|
Chris@268
|
343 void
|
Chris@268
|
344 Layer::AddMeasurementRectCommand::unexecute()
|
Chris@268
|
345 {
|
Chris@269
|
346 m_layer->deleteMeasureRectFromSet(m_rect);
|
Chris@268
|
347 }
|
Chris@268
|
348
|
Chris@283
|
349 QString
|
Chris@283
|
350 Layer::DeleteMeasurementRectCommand::getName() const
|
Chris@283
|
351 {
|
Chris@283
|
352 return tr("Delete Measurement");
|
Chris@283
|
353 }
|
Chris@283
|
354
|
Chris@283
|
355 void
|
Chris@283
|
356 Layer::DeleteMeasurementRectCommand::execute()
|
Chris@283
|
357 {
|
Chris@283
|
358 m_layer->deleteMeasureRectFromSet(m_rect);
|
Chris@283
|
359 }
|
Chris@283
|
360
|
Chris@283
|
361 void
|
Chris@283
|
362 Layer::DeleteMeasurementRectCommand::unexecute()
|
Chris@283
|
363 {
|
Chris@283
|
364 m_layer->addMeasureRectToSet(m_rect);
|
Chris@283
|
365 }
|
Chris@283
|
366
|
Chris@267
|
367 void
|
Chris@267
|
368 Layer::measureStart(View *v, QMouseEvent *e)
|
Chris@267
|
369 {
|
Chris@283
|
370 setMeasureRectFromPixrect(v, m_draggingRect,
|
Chris@283
|
371 QRect(e->x(), e->y(), 0, 0));
|
Chris@267
|
372 m_haveDraggingRect = true;
|
Chris@267
|
373 }
|
Chris@267
|
374
|
Chris@267
|
375 void
|
Chris@267
|
376 Layer::measureDrag(View *v, QMouseEvent *e)
|
Chris@267
|
377 {
|
Chris@267
|
378 if (!m_haveDraggingRect) return;
|
Chris@268
|
379
|
Chris@283
|
380 setMeasureRectFromPixrect(v, m_draggingRect,
|
Chris@283
|
381 QRect(m_draggingRect.pixrect.x(),
|
Chris@283
|
382 m_draggingRect.pixrect.y(),
|
Chris@283
|
383 e->x() - m_draggingRect.pixrect.x(),
|
Chris@283
|
384 e->y() - m_draggingRect.pixrect.y()));
|
Chris@267
|
385 }
|
Chris@267
|
386
|
Chris@267
|
387 void
|
Chris@267
|
388 Layer::measureEnd(View *v, QMouseEvent *e)
|
Chris@267
|
389 {
|
Chris@267
|
390 if (!m_haveDraggingRect) return;
|
Chris@267
|
391 measureDrag(v, e);
|
Chris@283
|
392
|
Chris@283
|
393 if (!m_draggingRect.pixrect.isNull()) {
|
Chris@283
|
394 CommandHistory::getInstance()->addCommand
|
Chris@283
|
395 (new AddMeasurementRectCommand(this, m_draggingRect));
|
Chris@283
|
396 }
|
Chris@268
|
397
|
Chris@267
|
398 m_haveDraggingRect = false;
|
Chris@267
|
399 }
|
Chris@267
|
400
|
Chris@267
|
401 void
|
Chris@280
|
402 Layer::measureDoubleClick(View *v, QMouseEvent *e)
|
Chris@280
|
403 {
|
Chris@283
|
404 // nothing, in the base class
|
Chris@283
|
405 }
|
Chris@283
|
406
|
Chris@283
|
407 void
|
Chris@283
|
408 Layer::deleteCurrentMeasureRect()
|
Chris@283
|
409 {
|
Chris@283
|
410 if (!m_haveCurrentMeasureRect) return;
|
Chris@283
|
411
|
Chris@283
|
412 MeasureRectSet::const_iterator focusRectItr =
|
Chris@283
|
413 findFocusedMeasureRect(m_currentMeasureRectPoint);
|
Chris@283
|
414
|
Chris@283
|
415 if (focusRectItr == m_measureRects.end()) return;
|
Chris@283
|
416
|
Chris@283
|
417 CommandHistory::getInstance()->addCommand
|
Chris@283
|
418 (new DeleteMeasurementRectCommand(this, *focusRectItr));
|
Chris@280
|
419 }
|
Chris@280
|
420
|
Chris@280
|
421 void
|
Chris@272
|
422 Layer::paintMeasurementRects(View *v, QPainter &paint,
|
Chris@272
|
423 bool showFocus, QPoint focusPoint) const
|
Chris@267
|
424 {
|
Chris@273
|
425 updateMeasurePixrects(v);
|
Chris@272
|
426
|
Chris@272
|
427 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
|
Chris@272
|
428
|
Chris@267
|
429 if (m_haveDraggingRect) {
|
Chris@272
|
430
|
Chris@270
|
431 paintMeasurementRect(v, paint, m_draggingRect, true);
|
Chris@272
|
432
|
Chris@272
|
433 } else if (showFocus) {
|
Chris@272
|
434
|
Chris@272
|
435 focusRectItr = findFocusedMeasureRect(focusPoint);
|
Chris@267
|
436 }
|
Chris@267
|
437
|
Chris@283
|
438 m_haveCurrentMeasureRect = false;
|
Chris@283
|
439
|
Chris@268
|
440 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@268
|
441 i != m_measureRects.end(); ++i) {
|
Chris@283
|
442
|
Chris@283
|
443 bool focused = (i == focusRectItr);
|
Chris@283
|
444 paintMeasurementRect(v, paint, *i, focused);
|
Chris@283
|
445
|
Chris@283
|
446 if (focused) {
|
Chris@283
|
447 m_haveCurrentMeasureRect = true;
|
Chris@283
|
448 m_currentMeasureRectPoint = focusPoint;
|
Chris@283
|
449 }
|
Chris@267
|
450 }
|
Chris@267
|
451 }
|
Chris@267
|
452
|
Chris@272
|
453 bool
|
Chris@272
|
454 Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const
|
Chris@272
|
455 {
|
Chris@273
|
456 updateMeasurePixrects(v);
|
Chris@272
|
457
|
Chris@272
|
458 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
|
Chris@272
|
459 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
|
Chris@272
|
460
|
Chris@272
|
461 return (i0 != i1);
|
Chris@272
|
462 }
|
Chris@272
|
463
|
Chris@272
|
464 void
|
Chris@273
|
465 Layer::updateMeasurePixrects(View *v) const
|
Chris@272
|
466 {
|
Chris@272
|
467 long sf = v->getStartFrame();
|
Chris@272
|
468 long ef = v->getEndFrame();
|
Chris@272
|
469
|
Chris@272
|
470 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@272
|
471 i != m_measureRects.end(); ++i) {
|
Chris@272
|
472
|
Chris@273
|
473 // This logic depends on the fact that if one measure rect in
|
Chris@273
|
474 // a layer has frame values, they all will. That is in fact
|
Chris@273
|
475 // the case, because haveFrames is based on whether the layer
|
Chris@273
|
476 // hasTimeXAxis() or not. Measure rect ordering in the rect
|
Chris@273
|
477 // set wouldn't work correctly either, if haveFrames could
|
Chris@273
|
478 // vary.
|
Chris@272
|
479
|
Chris@273
|
480 if (i->haveFrames) {
|
Chris@273
|
481 if (i->startFrame >= ef) break;
|
Chris@273
|
482 if (i->endFrame <= sf) continue;
|
Chris@273
|
483 }
|
Chris@272
|
484
|
Chris@273
|
485 int x0 = i->pixrect.x();
|
Chris@273
|
486 int x1 = x0 + i->pixrect.width();
|
Chris@273
|
487
|
Chris@273
|
488 if (i->haveFrames) {
|
Chris@273
|
489 if (i->startFrame >= v->getStartFrame()) {
|
Chris@273
|
490 x0 = v->getXForFrame(i->startFrame);
|
Chris@273
|
491 }
|
Chris@273
|
492 if (i->endFrame <= long(v->getEndFrame())) {
|
Chris@273
|
493 x1 = v->getXForFrame(i->endFrame);
|
Chris@273
|
494 }
|
Chris@272
|
495 }
|
Chris@272
|
496
|
Chris@273
|
497 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
|
Chris@273
|
498
|
Chris@273
|
499 updateMeasureRectYCoords(v, *i);
|
Chris@273
|
500 }
|
Chris@273
|
501 }
|
Chris@273
|
502
|
Chris@273
|
503 void
|
Chris@273
|
504 Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const
|
Chris@273
|
505 {
|
Chris@273
|
506 int y0 = lrint(r.startY * v->height());
|
Chris@273
|
507 int y1 = lrint(r.endY * v->height());
|
Chris@273
|
508 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
|
Chris@273
|
509 }
|
Chris@273
|
510
|
Chris@273
|
511 void
|
Chris@273
|
512 Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const
|
Chris@273
|
513 {
|
Chris@273
|
514 if (start) {
|
Chris@273
|
515 r.startY = double(y) / double(v->height());
|
Chris@273
|
516 r.endY = r.startY;
|
Chris@273
|
517 } else {
|
Chris@273
|
518 r.endY = double(y) / double(v->height());
|
Chris@272
|
519 }
|
Chris@272
|
520 }
|
Chris@272
|
521
|
Chris@283
|
522 void
|
Chris@283
|
523 Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const
|
Chris@283
|
524 {
|
Chris@283
|
525 r.pixrect = pixrect;
|
Chris@283
|
526 r.haveFrames = hasTimeXAxis();
|
Chris@283
|
527 if (r.haveFrames) {
|
Chris@283
|
528 r.startFrame = v->getFrameForX(pixrect.x());
|
Chris@283
|
529 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
|
Chris@283
|
530 }
|
Chris@283
|
531 setMeasureRectYCoord(v, r, true, pixrect.y());
|
Chris@283
|
532 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
|
Chris@283
|
533 }
|
Chris@283
|
534
|
Chris@272
|
535 Layer::MeasureRectSet::const_iterator
|
Chris@272
|
536 Layer::findFocusedMeasureRect(QPoint focusPoint) const
|
Chris@272
|
537 {
|
Chris@272
|
538 float frDist = 0;
|
Chris@272
|
539 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
|
Chris@272
|
540
|
Chris@272
|
541 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@272
|
542 i != m_measureRects.end(); ++i) {
|
Chris@272
|
543
|
Chris@272
|
544 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
|
Chris@272
|
545
|
Chris@272
|
546 int cx = i->pixrect.x() + i->pixrect.width()/2;
|
Chris@272
|
547 int cy = i->pixrect.y() + i->pixrect.height()/2;
|
Chris@272
|
548 int xd = focusPoint.x() - cx;
|
Chris@272
|
549 int yd = focusPoint.y() - cy;
|
Chris@272
|
550
|
Chris@272
|
551 float d = sqrt(xd * xd + yd * yd);
|
Chris@272
|
552
|
Chris@272
|
553 if (focusRectItr == m_measureRects.end() || d < frDist) {
|
Chris@272
|
554 focusRectItr = i;
|
Chris@272
|
555 frDist = d;
|
Chris@272
|
556 }
|
Chris@272
|
557 }
|
Chris@272
|
558
|
Chris@272
|
559 return focusRectItr;
|
Chris@272
|
560 }
|
Chris@272
|
561
|
Chris@268
|
562 void
|
Chris@270
|
563 Layer::paintMeasurementRect(View *v, QPainter &paint,
|
Chris@270
|
564 const MeasureRect &r, bool focus) const
|
Chris@268
|
565 {
|
Chris@268
|
566 if (r.haveFrames) {
|
Chris@268
|
567
|
Chris@268
|
568 int x0 = -1;
|
Chris@268
|
569 int x1 = v->width() + 1;
|
Chris@268
|
570
|
Chris@268
|
571 if (r.startFrame >= v->getStartFrame()) {
|
Chris@268
|
572 x0 = v->getXForFrame(r.startFrame);
|
Chris@268
|
573 }
|
Chris@272
|
574 if (r.endFrame <= long(v->getEndFrame())) {
|
Chris@268
|
575 x1 = v->getXForFrame(r.endFrame);
|
Chris@268
|
576 }
|
Chris@268
|
577
|
Chris@272
|
578 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
|
Chris@268
|
579 r.pixrect = pr;
|
Chris@268
|
580 }
|
Chris@274
|
581
|
Chris@274
|
582 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
|
Chris@268
|
583 }
|
Chris@268
|
584
|
Chris@316
|
585 void
|
Chris@316
|
586 Layer::toXml(QTextStream &stream,
|
Chris@316
|
587 QString indent, QString extraAttributes) const
|
Chris@268
|
588 {
|
Chris@316
|
589 stream << indent;
|
Chris@268
|
590
|
Chris@316
|
591 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
|
Chris@268
|
592 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
|
Chris@268
|
593 (LayerFactory::getInstance()->getLayerType(this))))
|
Chris@268
|
594 .arg(getObjectExportId(this))
|
Chris@268
|
595 .arg(encodeEntities(objectName()))
|
Chris@268
|
596 .arg(getObjectExportId(getModel()))
|
Chris@268
|
597 .arg(extraAttributes);
|
Chris@268
|
598
|
Chris@269
|
599 if (m_measureRects.empty()) {
|
Chris@316
|
600 stream << QString("/>\n");
|
Chris@316
|
601 return;
|
Chris@269
|
602 }
|
Chris@269
|
603
|
Chris@316
|
604 stream << QString(">\n");
|
Chris@269
|
605
|
Chris@269
|
606 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
|
Chris@269
|
607 i != m_measureRects.end(); ++i) {
|
Chris@316
|
608 i->toXml(stream, indent + " ");
|
Chris@269
|
609 }
|
Chris@269
|
610
|
Chris@316
|
611 stream << QString("</layer>\n");
|
Chris@268
|
612 }
|
Chris@269
|
613
|
Chris@316
|
614 void
|
Chris@316
|
615 Layer::toBriefXml(QTextStream &stream,
|
Chris@316
|
616 QString indent, QString extraAttributes) const
|
Chris@269
|
617 {
|
Chris@316
|
618 stream << indent;
|
Chris@269
|
619
|
Chris@316
|
620 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
|
Chris@269
|
621 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
|
Chris@269
|
622 (LayerFactory::getInstance()->getLayerType(this))))
|
Chris@269
|
623 .arg(getObjectExportId(this))
|
Chris@269
|
624 .arg(encodeEntities(objectName()))
|
Chris@269
|
625 .arg(getObjectExportId(getModel()))
|
Chris@269
|
626 .arg(extraAttributes);
|
Chris@269
|
627 }
|
Chris@269
|
628
|