Mercurial > hg > svgui
comparison layer/ImageLayer.cpp @ 303:46faec7aae12
* Phase 1 of an image layer.
author | Chris Cannam |
---|---|
date | Thu, 04 Oct 2007 16:34:11 +0000 |
parents | |
children | 4b7e8da8f069 |
comparison
equal
deleted
inserted
replaced
302:e9549ea3f825 | 303:46faec7aae12 |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006 Chris Cannam. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "ImageLayer.h" | |
17 | |
18 #include "data/model/Model.h" | |
19 #include "base/RealTime.h" | |
20 #include "base/Profiler.h" | |
21 #include "view/View.h" | |
22 | |
23 #include "data/model/ImageModel.h" | |
24 | |
25 #include "widgets/ImageDialog.h" | |
26 | |
27 #include <QPainter> | |
28 #include <QMouseEvent> | |
29 #include <QInputDialog> | |
30 | |
31 #include <iostream> | |
32 #include <cmath> | |
33 | |
34 ImageLayer::ImageMap | |
35 ImageLayer::m_images; | |
36 | |
37 ImageLayer::ImageLayer() : | |
38 Layer(), | |
39 m_model(0), | |
40 m_editing(false), | |
41 m_originalPoint(0, "", ""), | |
42 m_editingPoint(0, "", ""), | |
43 m_editingCommand(0) | |
44 { | |
45 | |
46 } | |
47 | |
48 void | |
49 ImageLayer::setModel(ImageModel *model) | |
50 { | |
51 if (m_model == model) return; | |
52 m_model = model; | |
53 | |
54 connect(m_model, SIGNAL(modelChanged()), this, SIGNAL(modelChanged())); | |
55 connect(m_model, SIGNAL(modelChanged(size_t, size_t)), | |
56 this, SIGNAL(modelChanged(size_t, size_t))); | |
57 | |
58 connect(m_model, SIGNAL(completionChanged()), | |
59 this, SIGNAL(modelCompletionChanged())); | |
60 | |
61 // std::cerr << "ImageLayer::setModel(" << model << ")" << std::endl; | |
62 | |
63 emit modelReplaced(); | |
64 } | |
65 | |
66 Layer::PropertyList | |
67 ImageLayer::getProperties() const | |
68 { | |
69 return Layer::getProperties(); | |
70 } | |
71 | |
72 QString | |
73 ImageLayer::getPropertyLabel(const PropertyName &name) const | |
74 { | |
75 return ""; | |
76 } | |
77 | |
78 Layer::PropertyType | |
79 ImageLayer::getPropertyType(const PropertyName &name) const | |
80 { | |
81 return Layer::getPropertyType(name); | |
82 } | |
83 | |
84 int | |
85 ImageLayer::getPropertyRangeAndValue(const PropertyName &name, | |
86 int *min, int *max, int *deflt) const | |
87 { | |
88 return Layer::getPropertyRangeAndValue(name, min, max, deflt); | |
89 } | |
90 | |
91 QString | |
92 ImageLayer::getPropertyValueLabel(const PropertyName &name, | |
93 int value) const | |
94 { | |
95 return Layer::getPropertyValueLabel(name, value); | |
96 } | |
97 | |
98 void | |
99 ImageLayer::setProperty(const PropertyName &name, int value) | |
100 { | |
101 Layer::setProperty(name, value); | |
102 } | |
103 | |
104 bool | |
105 ImageLayer::getValueExtents(float &, float &, bool &, QString &) const | |
106 { | |
107 return false; | |
108 } | |
109 | |
110 bool | |
111 ImageLayer::isLayerScrollable(const View *v) const | |
112 { | |
113 QPoint discard; | |
114 return !v->shouldIlluminateLocalFeatures(this, discard); | |
115 } | |
116 | |
117 | |
118 ImageModel::PointList | |
119 ImageLayer::getLocalPoints(View *v, int x, int y) const | |
120 { | |
121 if (!m_model) return ImageModel::PointList(); | |
122 | |
123 std::cerr << "ImageLayer::getLocalPoints(" << x << "," << y << "):"; | |
124 | |
125 long frame0 = v->getFrameForX(-150); | |
126 long frame1 = v->getFrameForX(v->width() + 150); | |
127 | |
128 ImageModel::PointList points(m_model->getPoints(frame0, frame1)); | |
129 | |
130 ImageModel::PointList rv; | |
131 | |
132 //!!! need to store drawn size as well as original size for each | |
133 //image, but for now: | |
134 | |
135 for (ImageModel::PointList::iterator i = points.begin(); | |
136 i != points.end(); ++i) { | |
137 | |
138 const ImageModel::Point &p(*i); | |
139 | |
140 int px = v->getXForFrame(p.frame); | |
141 | |
142 if (x >= px && x < px + 100) { | |
143 rv.insert(p); | |
144 } | |
145 } | |
146 | |
147 std::cerr << rv.size() << " point(s)" << std::endl; | |
148 | |
149 return rv; | |
150 } | |
151 | |
152 QString | |
153 ImageLayer::getFeatureDescription(View *v, QPoint &pos) const | |
154 { | |
155 int x = pos.x(); | |
156 | |
157 if (!m_model || !m_model->getSampleRate()) return ""; | |
158 | |
159 ImageModel::PointList points = getLocalPoints(v, x, pos.y()); | |
160 | |
161 if (points.empty()) { | |
162 if (!m_model->isReady()) { | |
163 return tr("In progress"); | |
164 } else { | |
165 return ""; | |
166 } | |
167 } | |
168 | |
169 long useFrame = points.begin()->frame; | |
170 | |
171 RealTime rt = RealTime::frame2RealTime(useFrame, m_model->getSampleRate()); | |
172 | |
173 QString text; | |
174 /* | |
175 if (points.begin()->label == "") { | |
176 text = QString(tr("Time:\t%1\nHeight:\t%2\nLabel:\t%3")) | |
177 .arg(rt.toText(true).c_str()) | |
178 .arg(points.begin()->height) | |
179 .arg(points.begin()->label); | |
180 } | |
181 | |
182 pos = QPoint(v->getXForFrame(useFrame), | |
183 getYForHeight(v, points.begin()->height)); | |
184 */ | |
185 return text; | |
186 } | |
187 | |
188 | |
189 //!!! too much overlap with TimeValueLayer/TimeInstantLayer/TextLayer | |
190 | |
191 bool | |
192 ImageLayer::snapToFeatureFrame(View *v, int &frame, | |
193 size_t &resolution, | |
194 SnapType snap) const | |
195 { | |
196 if (!m_model) { | |
197 return Layer::snapToFeatureFrame(v, frame, resolution, snap); | |
198 } | |
199 | |
200 resolution = m_model->getResolution(); | |
201 ImageModel::PointList points; | |
202 | |
203 if (snap == SnapNeighbouring) { | |
204 | |
205 points = getLocalPoints(v, v->getXForFrame(frame), -1); | |
206 if (points.empty()) return false; | |
207 frame = points.begin()->frame; | |
208 return true; | |
209 } | |
210 | |
211 points = m_model->getPoints(frame, frame); | |
212 int snapped = frame; | |
213 bool found = false; | |
214 | |
215 for (ImageModel::PointList::const_iterator i = points.begin(); | |
216 i != points.end(); ++i) { | |
217 | |
218 if (snap == SnapRight) { | |
219 | |
220 if (i->frame > frame) { | |
221 snapped = i->frame; | |
222 found = true; | |
223 break; | |
224 } | |
225 | |
226 } else if (snap == SnapLeft) { | |
227 | |
228 if (i->frame <= frame) { | |
229 snapped = i->frame; | |
230 found = true; // don't break, as the next may be better | |
231 } else { | |
232 break; | |
233 } | |
234 | |
235 } else { // nearest | |
236 | |
237 ImageModel::PointList::const_iterator j = i; | |
238 ++j; | |
239 | |
240 if (j == points.end()) { | |
241 | |
242 snapped = i->frame; | |
243 found = true; | |
244 break; | |
245 | |
246 } else if (j->frame >= frame) { | |
247 | |
248 if (j->frame - frame < frame - i->frame) { | |
249 snapped = j->frame; | |
250 } else { | |
251 snapped = i->frame; | |
252 } | |
253 found = true; | |
254 break; | |
255 } | |
256 } | |
257 } | |
258 | |
259 frame = snapped; | |
260 return found; | |
261 } | |
262 | |
263 void | |
264 ImageLayer::paint(View *v, QPainter &paint, QRect rect) const | |
265 { | |
266 if (!m_model || !m_model->isOK()) return; | |
267 | |
268 int sampleRate = m_model->getSampleRate(); | |
269 if (!sampleRate) return; | |
270 | |
271 // Profiler profiler("ImageLayer::paint", true); | |
272 | |
273 int x0 = rect.left(), x1 = rect.right(); | |
274 long frame0 = v->getFrameForX(x0); | |
275 long frame1 = v->getFrameForX(x1); | |
276 | |
277 ImageModel::PointList points(m_model->getPoints(frame0, frame1)); | |
278 if (points.empty()) return; | |
279 | |
280 QColor penColour; | |
281 penColour = v->getForeground(); | |
282 | |
283 // std::cerr << "ImageLayer::paint: resolution is " | |
284 // << m_model->getResolution() << " frames" << std::endl; | |
285 | |
286 QPoint localPos; | |
287 long illuminateFrame = -1; | |
288 | |
289 if (v->shouldIlluminateLocalFeatures(this, localPos)) { | |
290 ImageModel::PointList localPoints = getLocalPoints(v, localPos.x(), | |
291 localPos.y()); | |
292 if (!localPoints.empty()) illuminateFrame = localPoints.begin()->frame; | |
293 } | |
294 | |
295 paint.save(); | |
296 paint.setClipRect(rect.x(), 0, rect.width(), v->height()); | |
297 | |
298 for (ImageModel::PointList::const_iterator i = points.begin(); | |
299 i != points.end(); ++i) { | |
300 | |
301 const ImageModel::Point &p(*i); | |
302 | |
303 int x = v->getXForFrame(p.frame); | |
304 | |
305 int nx = x + 2000; | |
306 ImageModel::PointList::const_iterator j = i; | |
307 ++j; | |
308 if (j != points.end()) { | |
309 int jx = v->getXForFrame(j->frame); | |
310 if (jx < nx) nx = jx; | |
311 } | |
312 /* | |
313 if (illuminateFrame == p.frame) { | |
314 paint.setBrush(penColour); | |
315 paint.setPen(v->getBackground()); | |
316 } else { | |
317 paint.setPen(penColour); | |
318 paint.setBrush(brushColour); | |
319 } | |
320 */ | |
321 QString label = p.label; | |
322 QString imageName = p.image; | |
323 | |
324 int nw = nx - x; | |
325 if (nw < 10) nw = 20; | |
326 | |
327 int top = 10; | |
328 if (v->height() < 50) top = 5; | |
329 | |
330 int bottom = top; | |
331 | |
332 QRect labelRect; | |
333 if (label != "") { | |
334 float aspect = getImageAspect(imageName); | |
335 int iw = lrintf((v->height() - v->height()/4 - top - bottom) | |
336 * aspect); | |
337 labelRect = paint.fontMetrics().boundingRect | |
338 (QRect(0, 0, iw, v->height()/4), | |
339 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, label); | |
340 bottom += labelRect.height() + 5; | |
341 } | |
342 | |
343 QImage image = getImage(v, | |
344 imageName, | |
345 QSize(nw, v->height() - top - bottom)); | |
346 | |
347 if (image.isNull()) { | |
348 image = QImage(":icons/emptypage.png"); | |
349 } | |
350 | |
351 paint.setRenderHint(QPainter::Antialiasing, false); | |
352 | |
353 int boxWidth = image.width(); | |
354 | |
355 if (label != "") { | |
356 boxWidth = std::max(boxWidth, labelRect.width()); | |
357 } | |
358 | |
359 paint.drawRect(x-1, top-1, boxWidth+1, v->height() - 2 * top +1); | |
360 | |
361 paint.setRenderHint(QPainter::Antialiasing, true); | |
362 | |
363 paint.drawImage(x + (boxWidth - image.width())/2, top, image); | |
364 | |
365 paint.drawText(QRect(x, v->height() - bottom + 5, | |
366 boxWidth, labelRect.height()), | |
367 Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, | |
368 label); | |
369 } | |
370 | |
371 paint.restore(); | |
372 paint.setRenderHint(QPainter::Antialiasing, false); | |
373 } | |
374 | |
375 void | |
376 ImageLayer::setLayerDormant(const View *v, bool dormant) | |
377 { | |
378 if (dormant) { | |
379 // Delete the images named in the view's scaled map from the | |
380 // general image map as well. They can always be re-loaded | |
381 // if it turns out another view still needs them. | |
382 for (ImageMap::iterator i = m_scaled[v].begin(); | |
383 i != m_scaled[v].end(); ++i) { | |
384 m_images.erase(i->first); | |
385 } | |
386 m_scaled.erase(v); | |
387 } | |
388 } | |
389 | |
390 //!!! how to reap no-longer-used images? | |
391 | |
392 float | |
393 ImageLayer::getImageAspect(QString name) const | |
394 { | |
395 if (m_images.find(name) == m_images.end()) { | |
396 m_images[name] = QImage(name); | |
397 } | |
398 if (m_images[name].isNull()) return 1.f; | |
399 return float(m_images[name].width()) / float(m_images[name].height()); | |
400 } | |
401 | |
402 QImage | |
403 ImageLayer::getImage(View *v, QString name, QSize maxSize) const | |
404 { | |
405 bool need = false; | |
406 | |
407 // std::cerr << "ImageLayer::getImage(" << v << ", " << name.toStdString() << ", (" | |
408 // << maxSize.width() << "x" << maxSize.height() << "))" << std::endl; | |
409 | |
410 if (!m_scaled[v][name].isNull() && | |
411 (m_scaled[v][name].width() == maxSize.width() || | |
412 m_scaled[v][name].height() == maxSize.height())) { | |
413 // std::cerr << "cache hit" << std::endl; | |
414 return m_scaled[v][name]; | |
415 } | |
416 | |
417 if (m_images.find(name) == m_images.end()) { | |
418 m_images[name] = QImage(name); | |
419 } | |
420 | |
421 if (m_images[name].isNull()) { | |
422 // std::cerr << "null image" << std::endl; | |
423 m_scaled[v][name] = QImage(); | |
424 } else { | |
425 m_scaled[v][name] = | |
426 m_images[name].scaled(maxSize, | |
427 Qt::KeepAspectRatio, | |
428 Qt::SmoothTransformation); | |
429 } | |
430 | |
431 return m_scaled[v][name]; | |
432 } | |
433 | |
434 void | |
435 ImageLayer::drawStart(View *v, QMouseEvent *e) | |
436 { | |
437 // std::cerr << "ImageLayer::drawStart(" << e->x() << "," << e->y() << ")" << std::endl; | |
438 | |
439 if (!m_model) { | |
440 std::cerr << "ImageLayer::drawStart: no model" << std::endl; | |
441 return; | |
442 } | |
443 | |
444 long frame = v->getFrameForX(e->x()); | |
445 if (frame < 0) frame = 0; | |
446 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
447 | |
448 m_editingPoint = ImageModel::Point(frame, "", ""); | |
449 m_originalPoint = m_editingPoint; | |
450 | |
451 if (m_editingCommand) m_editingCommand->finish(); | |
452 m_editingCommand = new ImageModel::EditCommand(m_model, "Add Image"); | |
453 m_editingCommand->addPoint(m_editingPoint); | |
454 | |
455 m_editing = true; | |
456 } | |
457 | |
458 void | |
459 ImageLayer::drawDrag(View *v, QMouseEvent *e) | |
460 { | |
461 // std::cerr << "ImageLayer::drawDrag(" << e->x() << "," << e->y() << ")" << std::endl; | |
462 | |
463 if (!m_model || !m_editing) return; | |
464 | |
465 long frame = v->getFrameForX(e->x()); | |
466 if (frame < 0) frame = 0; | |
467 frame = frame / m_model->getResolution() * m_model->getResolution(); | |
468 | |
469 m_editingCommand->deletePoint(m_editingPoint); | |
470 m_editingPoint.frame = frame; | |
471 m_editingCommand->addPoint(m_editingPoint); | |
472 } | |
473 | |
474 void | |
475 ImageLayer::drawEnd(View *v, QMouseEvent *) | |
476 { | |
477 // std::cerr << "ImageLayer::drawEnd(" << e->x() << "," << e->y() << ")" << std::endl; | |
478 if (!m_model || !m_editing) return; | |
479 | |
480 bool ok = false; | |
481 | |
482 ImageDialog dialog(tr("Select image"), "", tr("<no label>")); | |
483 if (dialog.exec() == QDialog::Accepted) { | |
484 ImageModel::ChangeImageCommand *command = | |
485 new ImageModel::ChangeImageCommand | |
486 (m_model, m_editingPoint, dialog.getImage(), dialog.getLabel()); | |
487 m_editingCommand->addCommand(command); | |
488 } | |
489 | |
490 m_editingCommand->finish(); | |
491 m_editingCommand = 0; | |
492 m_editing = false; | |
493 } | |
494 | |
495 void | |
496 ImageLayer::editStart(View *v, QMouseEvent *e) | |
497 { | |
498 // std::cerr << "ImageLayer::editStart(" << e->x() << "," << e->y() << ")" << std::endl; | |
499 | |
500 if (!m_model) return; | |
501 | |
502 ImageModel::PointList points = getLocalPoints(v, e->x(), e->y()); | |
503 if (points.empty()) return; | |
504 | |
505 m_editOrigin = e->pos(); | |
506 m_editingPoint = *points.begin(); | |
507 m_originalPoint = m_editingPoint; | |
508 | |
509 if (m_editingCommand) { | |
510 m_editingCommand->finish(); | |
511 m_editingCommand = 0; | |
512 } | |
513 | |
514 m_editing = true; | |
515 } | |
516 | |
517 void | |
518 ImageLayer::editDrag(View *v, QMouseEvent *e) | |
519 { | |
520 if (!m_model || !m_editing) return; | |
521 | |
522 long frameDiff = v->getFrameForX(e->x()) - v->getFrameForX(m_editOrigin.x()); | |
523 long frame = m_originalPoint.frame + frameDiff; | |
524 | |
525 if (frame < 0) frame = 0; | |
526 frame = (frame / m_model->getResolution()) * m_model->getResolution(); | |
527 | |
528 if (!m_editingCommand) { | |
529 m_editingCommand = new ImageModel::EditCommand(m_model, tr("Move Image")); | |
530 } | |
531 | |
532 m_editingCommand->deletePoint(m_editingPoint); | |
533 m_editingPoint.frame = frame; | |
534 m_editingCommand->addPoint(m_editingPoint); | |
535 } | |
536 | |
537 void | |
538 ImageLayer::editEnd(View *, QMouseEvent *) | |
539 { | |
540 // std::cerr << "ImageLayer::editEnd(" << e->x() << "," << e->y() << ")" << std::endl; | |
541 if (!m_model || !m_editing) return; | |
542 | |
543 if (m_editingCommand) { | |
544 m_editingCommand->finish(); | |
545 } | |
546 | |
547 m_editingCommand = 0; | |
548 m_editing = false; | |
549 } | |
550 | |
551 bool | |
552 ImageLayer::editOpen(View *v, QMouseEvent *e) | |
553 { | |
554 if (!m_model) return false; | |
555 | |
556 ImageModel::PointList points = getLocalPoints(v, e->x(), e->y()); | |
557 if (points.empty()) return false; | |
558 | |
559 QString image = points.begin()->image; | |
560 QString label = points.begin()->label; | |
561 | |
562 ImageDialog dialog(tr("Select image"), | |
563 image, | |
564 label); | |
565 | |
566 if (dialog.exec() == QDialog::Accepted) { | |
567 ImageModel::ChangeImageCommand *command = | |
568 new ImageModel::ChangeImageCommand | |
569 (m_model, *points.begin(), dialog.getImage(), dialog.getLabel()); | |
570 CommandHistory::getInstance()->addCommand(command); | |
571 } | |
572 | |
573 return true; | |
574 } | |
575 | |
576 void | |
577 ImageLayer::moveSelection(Selection s, size_t newStartFrame) | |
578 { | |
579 if (!m_model) return; | |
580 | |
581 ImageModel::EditCommand *command = | |
582 new ImageModel::EditCommand(m_model, tr("Drag Selection")); | |
583 | |
584 ImageModel::PointList points = | |
585 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
586 | |
587 for (ImageModel::PointList::iterator i = points.begin(); | |
588 i != points.end(); ++i) { | |
589 | |
590 if (s.contains(i->frame)) { | |
591 ImageModel::Point newPoint(*i); | |
592 newPoint.frame = i->frame + newStartFrame - s.getStartFrame(); | |
593 command->deletePoint(*i); | |
594 command->addPoint(newPoint); | |
595 } | |
596 } | |
597 | |
598 command->finish(); | |
599 } | |
600 | |
601 void | |
602 ImageLayer::resizeSelection(Selection s, Selection newSize) | |
603 { | |
604 if (!m_model) return; | |
605 | |
606 ImageModel::EditCommand *command = | |
607 new ImageModel::EditCommand(m_model, tr("Resize Selection")); | |
608 | |
609 ImageModel::PointList points = | |
610 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
611 | |
612 double ratio = | |
613 double(newSize.getEndFrame() - newSize.getStartFrame()) / | |
614 double(s.getEndFrame() - s.getStartFrame()); | |
615 | |
616 for (ImageModel::PointList::iterator i = points.begin(); | |
617 i != points.end(); ++i) { | |
618 | |
619 if (s.contains(i->frame)) { | |
620 | |
621 double target = i->frame; | |
622 target = newSize.getStartFrame() + | |
623 double(target - s.getStartFrame()) * ratio; | |
624 | |
625 ImageModel::Point newPoint(*i); | |
626 newPoint.frame = lrint(target); | |
627 command->deletePoint(*i); | |
628 command->addPoint(newPoint); | |
629 } | |
630 } | |
631 | |
632 command->finish(); | |
633 } | |
634 | |
635 void | |
636 ImageLayer::deleteSelection(Selection s) | |
637 { | |
638 if (!m_model) return; | |
639 | |
640 ImageModel::EditCommand *command = | |
641 new ImageModel::EditCommand(m_model, tr("Delete Selection")); | |
642 | |
643 ImageModel::PointList points = | |
644 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
645 | |
646 for (ImageModel::PointList::iterator i = points.begin(); | |
647 i != points.end(); ++i) { | |
648 if (s.contains(i->frame)) command->deletePoint(*i); | |
649 } | |
650 | |
651 command->finish(); | |
652 } | |
653 | |
654 void | |
655 ImageLayer::copy(Selection s, Clipboard &to) | |
656 { | |
657 if (!m_model) return; | |
658 | |
659 ImageModel::PointList points = | |
660 m_model->getPoints(s.getStartFrame(), s.getEndFrame()); | |
661 | |
662 for (ImageModel::PointList::iterator i = points.begin(); | |
663 i != points.end(); ++i) { | |
664 if (s.contains(i->frame)) { | |
665 //!!! inadequate | |
666 Clipboard::Point point(i->frame, i->label); | |
667 to.addPoint(point); | |
668 } | |
669 } | |
670 } | |
671 | |
672 bool | |
673 ImageLayer::paste(const Clipboard &from, int frameOffset, bool /* interactive */) | |
674 { | |
675 if (!m_model) return false; | |
676 | |
677 const Clipboard::PointList &points = from.getPoints(); | |
678 | |
679 ImageModel::EditCommand *command = | |
680 new ImageModel::EditCommand(m_model, tr("Paste")); | |
681 | |
682 for (Clipboard::PointList::const_iterator i = points.begin(); | |
683 i != points.end(); ++i) { | |
684 | |
685 if (!i->haveFrame()) continue; | |
686 size_t frame = 0; | |
687 if (frameOffset > 0 || -frameOffset < i->getFrame()) { | |
688 frame = i->getFrame() + frameOffset; | |
689 } | |
690 ImageModel::Point newPoint(frame); | |
691 | |
692 //!!! inadequate | |
693 | |
694 if (i->haveLabel()) { | |
695 newPoint.label = i->getLabel(); | |
696 } else if (i->haveValue()) { | |
697 newPoint.label = QString("%1").arg(i->getValue()); | |
698 } else { | |
699 newPoint.label = tr("New Point"); | |
700 } | |
701 | |
702 command->addPoint(newPoint); | |
703 } | |
704 | |
705 command->finish(); | |
706 return true; | |
707 } | |
708 | |
709 QString | |
710 ImageLayer::toXmlString(QString indent, QString extraAttributes) const | |
711 { | |
712 return Layer::toXmlString(indent, extraAttributes); | |
713 } | |
714 | |
715 void | |
716 ImageLayer::setProperties(const QXmlAttributes &attributes) | |
717 { | |
718 } | |
719 |