Mercurial > hg > svcore
comparison base/View.cpp @ 0:da6937383da8
initial import
author | Chris Cannam |
---|---|
date | Tue, 10 Jan 2006 16:33:16 +0000 |
parents | |
children | a23739e2338a |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:da6937383da8 |
---|---|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 A waveform viewer and audio annotation editor. | |
5 Chris Cannam, Queen Mary University of London, 2005 | |
6 | |
7 This is experimental software. Not for distribution. | |
8 */ | |
9 | |
10 #include "base/View.h" | |
11 #include "base/ViewManager.h" | |
12 #include "base/Layer.h" | |
13 #include "base/Model.h" | |
14 #include "base/ZoomConstraint.h" | |
15 #include "base/Profiler.h" | |
16 | |
17 #include "layer/TimeRulerLayer.h" //!!! damn, shouldn't be including that here | |
18 | |
19 #include <QPainter> | |
20 #include <QPaintEvent> | |
21 #include <QRect> | |
22 #include <QApplication> | |
23 | |
24 #include <iostream> | |
25 | |
26 //#define DEBUG_VIEW_WIDGET_PAINT 1 | |
27 | |
28 using std::cerr; | |
29 using std::endl; | |
30 | |
31 View::View(QWidget *w, bool showProgress) : | |
32 QFrame(w), | |
33 m_centreFrame(0), | |
34 m_zoomLevel(1024), | |
35 m_newModel(true), | |
36 m_followPan(true), | |
37 m_followZoom(true), | |
38 m_followPlay(PlaybackScrollPage), | |
39 m_lightBackground(true), | |
40 m_showProgress(showProgress), | |
41 m_cache(0), | |
42 m_cacheCentreFrame(0), | |
43 m_cacheZoomLevel(1024), | |
44 m_deleting(false), | |
45 m_manager(0) | |
46 { | |
47 // QWidget::setAttribute(Qt::WA_PaintOnScreen); | |
48 } | |
49 | |
50 View::~View() | |
51 { | |
52 m_deleting = true; | |
53 | |
54 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
55 delete *i; | |
56 } | |
57 } | |
58 | |
59 PropertyContainer::PropertyList | |
60 View::getProperties() const | |
61 { | |
62 PropertyList list; | |
63 list.push_back(tr("Global Scroll")); | |
64 list.push_back(tr("Global Zoom")); | |
65 list.push_back(tr("Follow Playback")); | |
66 return list; | |
67 } | |
68 | |
69 PropertyContainer::PropertyType | |
70 View::getPropertyType(const PropertyName &name) const | |
71 { | |
72 if (name == tr("Global Scroll")) return ToggleProperty; | |
73 if (name == tr("Global Zoom")) return ToggleProperty; | |
74 if (name == tr("Follow Playback")) return ValueProperty; | |
75 return InvalidProperty; | |
76 } | |
77 | |
78 int | |
79 View::getPropertyRangeAndValue(const PropertyName &name, | |
80 int *min, int *max) const | |
81 { | |
82 if (name == tr("Global Scroll")) return m_followPan; | |
83 if (name == tr("Global Zoom")) return m_followZoom; | |
84 if (name == tr("Follow Playback")) { *min = 0; *max = 2; return int(m_followPlay); } | |
85 return PropertyContainer::getPropertyRangeAndValue(name, min, max); | |
86 } | |
87 | |
88 QString | |
89 View::getPropertyValueLabel(const PropertyName &name, | |
90 int value) const | |
91 { | |
92 if (name == tr("Follow Playback")) { | |
93 switch (value) { | |
94 default: | |
95 case 0: return tr("Scroll"); | |
96 case 1: return tr("Page"); | |
97 case 2: return tr("Off"); | |
98 } | |
99 } | |
100 return tr("<unknown>"); | |
101 } | |
102 | |
103 void | |
104 View::setProperty(const PropertyName &name, int value) | |
105 { | |
106 if (name == tr("Global Scroll")) { | |
107 setFollowGlobalPan(value != 0); | |
108 } else if (name == tr("Global Zoom")) { | |
109 setFollowGlobalZoom(value != 0); | |
110 } else if (name == tr("Follow Playback")) { | |
111 switch (value) { | |
112 default: | |
113 case 0: setPlaybackFollow(PlaybackScrollContinuous); break; | |
114 case 1: setPlaybackFollow(PlaybackScrollPage); break; | |
115 case 2: setPlaybackFollow(PlaybackIgnore); break; | |
116 } | |
117 } | |
118 } | |
119 | |
120 size_t | |
121 View::getPropertyContainerCount() const | |
122 { | |
123 return m_layers.size() + 1; // the 1 is for me | |
124 } | |
125 | |
126 const PropertyContainer * | |
127 View::getPropertyContainer(size_t i) const | |
128 { | |
129 return (const PropertyContainer *)(((View *)this)-> | |
130 getPropertyContainer(i)); | |
131 } | |
132 | |
133 PropertyContainer * | |
134 View::getPropertyContainer(size_t i) | |
135 { | |
136 if (i == 0) return this; | |
137 return m_layers[i-1]; | |
138 } | |
139 | |
140 void | |
141 View::propertyContainerSelected(PropertyContainer *pc) | |
142 { | |
143 if (pc == this) return; | |
144 | |
145 delete m_cache; | |
146 m_cache = 0; | |
147 | |
148 Layer *selectedLayer = 0; | |
149 | |
150 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
151 if (*i == pc) { | |
152 selectedLayer = *i; | |
153 m_layers.erase(i); | |
154 break; | |
155 } | |
156 } | |
157 | |
158 if (selectedLayer) { | |
159 m_layers.push_back(selectedLayer); | |
160 update(); | |
161 } | |
162 } | |
163 | |
164 long | |
165 View::getStartFrame() const | |
166 { | |
167 size_t w2 = (width() / 2) * m_zoomLevel; | |
168 size_t frame = m_centreFrame; | |
169 if (frame >= w2) { | |
170 frame -= w2; | |
171 return (frame / m_zoomLevel * m_zoomLevel); | |
172 } else { | |
173 frame = w2 - frame; | |
174 frame = frame / m_zoomLevel * m_zoomLevel; | |
175 return -(long)frame - m_zoomLevel; | |
176 } | |
177 } | |
178 | |
179 size_t | |
180 View::getEndFrame() const | |
181 { | |
182 return getStartFrame() + (width() * m_zoomLevel) - 1; | |
183 } | |
184 | |
185 void | |
186 View::setStartFrame(long f) | |
187 { | |
188 setCentreFrame(f + m_zoomLevel * (width() / 2)); | |
189 } | |
190 | |
191 void | |
192 View::setCentreFrame(size_t f, bool e) | |
193 { | |
194 if (m_centreFrame != f) { | |
195 | |
196 int formerPixel = m_centreFrame / m_zoomLevel; | |
197 | |
198 m_centreFrame = f; | |
199 | |
200 int newPixel = m_centreFrame / m_zoomLevel; | |
201 | |
202 if (newPixel != formerPixel) { | |
203 | |
204 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
205 std::cout << "View(" << this << ")::setCentreFrame: newPixel " << newPixel << ", formerPixel " << formerPixel << std::endl; | |
206 #endif | |
207 update(); | |
208 } | |
209 | |
210 if (e) emit centreFrameChanged(this, f, m_followPan); | |
211 } | |
212 } | |
213 | |
214 void | |
215 View::setZoomLevel(size_t z) | |
216 { | |
217 if (m_zoomLevel != int(z)) { | |
218 m_zoomLevel = z; | |
219 emit zoomLevelChanged(this, z, m_followZoom); | |
220 update(); | |
221 } | |
222 } | |
223 | |
224 void | |
225 View::addLayer(Layer *layer) | |
226 { | |
227 delete m_cache; | |
228 m_cache = 0; | |
229 | |
230 m_layers.push_back(layer); | |
231 | |
232 m_progressBars[layer] = new LayerProgressBar(this); | |
233 m_progressBars[layer]->setMinimum(0); | |
234 m_progressBars[layer]->setMaximum(100); | |
235 m_progressBars[layer]->setMinimumWidth(80); | |
236 m_progressBars[layer]->hide(); | |
237 | |
238 connect(layer, SIGNAL(layerParametersChanged()), | |
239 this, SLOT(layerParametersChanged())); | |
240 connect(layer, SIGNAL(layerNameChanged()), | |
241 this, SLOT(layerNameChanged())); | |
242 connect(layer, SIGNAL(modelChanged()), | |
243 this, SLOT(modelChanged())); | |
244 connect(layer, SIGNAL(modelCompletionChanged()), | |
245 this, SLOT(modelCompletionChanged())); | |
246 connect(layer, SIGNAL(modelChanged(size_t, size_t)), | |
247 this, SLOT(modelChanged(size_t, size_t))); | |
248 connect(layer, SIGNAL(modelReplaced()), | |
249 this, SLOT(modelReplaced())); | |
250 | |
251 m_newModel = true; | |
252 update(); | |
253 | |
254 emit propertyContainerAdded(layer); | |
255 } | |
256 | |
257 void | |
258 View::removeLayer(Layer *layer) | |
259 { | |
260 if (m_deleting) { | |
261 return; | |
262 } | |
263 | |
264 delete m_cache; | |
265 m_cache = 0; | |
266 | |
267 for (LayerList::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
268 if (*i == layer) { | |
269 m_layers.erase(i); | |
270 if (m_progressBars.find(layer) != m_progressBars.end()) { | |
271 delete m_progressBars[layer]; | |
272 m_progressBars.erase(layer); | |
273 } | |
274 break; | |
275 } | |
276 } | |
277 | |
278 update(); | |
279 | |
280 emit propertyContainerRemoved(layer); | |
281 } | |
282 | |
283 void | |
284 View::setViewManager(ViewManager *manager) | |
285 { | |
286 if (m_manager) { | |
287 m_manager->disconnect(this, SLOT(viewManagerCentreFrameChanged(void *, unsigned long, bool))); | |
288 m_manager->disconnect(this, SLOT(viewManagerZoomLevelChanged(void *, unsigned long, bool))); | |
289 disconnect(m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool))); | |
290 disconnect(m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool))); | |
291 } | |
292 | |
293 m_manager = manager; | |
294 if (m_followPan) setCentreFrame(m_manager->getGlobalCentreFrame(), false); | |
295 if (m_followZoom) setZoomLevel(m_manager->getGlobalZoom()); | |
296 | |
297 connect(m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool)), | |
298 this, SLOT(viewManagerCentreFrameChanged(void *, unsigned long, bool))); | |
299 connect(m_manager, SIGNAL(playbackFrameChanged(unsigned long)), | |
300 this, SLOT(viewManagerPlaybackFrameChanged(unsigned long))); | |
301 connect(m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)), | |
302 this, SLOT(viewManagerZoomLevelChanged(void *, unsigned long, bool))); | |
303 | |
304 connect(this, SIGNAL(centreFrameChanged(void *, unsigned long, bool)), | |
305 m_manager, SIGNAL(centreFrameChanged(void *, unsigned long, bool))); | |
306 connect(this, SIGNAL(zoomLevelChanged(void *, unsigned long, bool)), | |
307 m_manager, SIGNAL(zoomLevelChanged(void *, unsigned long, bool))); | |
308 } | |
309 | |
310 void | |
311 View::setFollowGlobalPan(bool f) | |
312 { | |
313 m_followPan = f; | |
314 emit propertyContainerPropertyChanged(this); | |
315 } | |
316 | |
317 void | |
318 View::setFollowGlobalZoom(bool f) | |
319 { | |
320 m_followZoom = f; | |
321 emit propertyContainerPropertyChanged(this); | |
322 } | |
323 | |
324 void | |
325 View::setPlaybackFollow(PlaybackFollowMode m) | |
326 { | |
327 m_followPlay = m; | |
328 emit propertyContainerPropertyChanged(this); | |
329 } | |
330 | |
331 void | |
332 View::modelChanged() | |
333 { | |
334 QObject *obj = sender(); | |
335 | |
336 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
337 std::cerr << "View::modelChanged()" << std::endl; | |
338 #endif | |
339 delete m_cache; | |
340 m_cache = 0; | |
341 | |
342 checkProgress(obj); | |
343 | |
344 update(); | |
345 } | |
346 | |
347 void | |
348 View::modelChanged(size_t startFrame, size_t endFrame) | |
349 { | |
350 QObject *obj = sender(); | |
351 | |
352 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
353 std::cerr << "View::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl; | |
354 #endif | |
355 | |
356 long myStartFrame = getStartFrame(); | |
357 size_t myEndFrame = getEndFrame(); | |
358 | |
359 if (myStartFrame > 0 && endFrame < size_t(myStartFrame)) { | |
360 checkProgress(obj); | |
361 return; | |
362 } | |
363 if (startFrame > myEndFrame) { | |
364 checkProgress(obj); | |
365 return; | |
366 } | |
367 | |
368 delete m_cache; | |
369 m_cache = 0; | |
370 | |
371 if (long(startFrame) < myStartFrame) startFrame = myStartFrame; | |
372 if (endFrame > myEndFrame) endFrame = myEndFrame; | |
373 | |
374 int x0 = (startFrame - myStartFrame) / m_zoomLevel; | |
375 int x1 = (endFrame - myStartFrame) / m_zoomLevel; | |
376 if (x1 < x0) return; | |
377 | |
378 checkProgress(obj); | |
379 | |
380 update(x0, 0, x1 - x0 + 1, height()); | |
381 } | |
382 | |
383 void | |
384 View::modelCompletionChanged() | |
385 { | |
386 QObject *obj = sender(); | |
387 checkProgress(obj); | |
388 } | |
389 | |
390 void | |
391 View::modelReplaced() | |
392 { | |
393 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
394 std::cerr << "View::modelReplaced()" << std::endl; | |
395 #endif | |
396 m_newModel = true; | |
397 update(); | |
398 } | |
399 | |
400 void | |
401 View::layerParametersChanged() | |
402 { | |
403 Layer *layer = dynamic_cast<Layer *>(sender()); | |
404 | |
405 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
406 std::cerr << "View::layerParametersChanged()" << std::endl; | |
407 #endif | |
408 | |
409 delete m_cache; | |
410 m_cache = 0; | |
411 update(); | |
412 | |
413 if (layer) { | |
414 emit propertyContainerPropertyChanged(layer); | |
415 } | |
416 } | |
417 | |
418 void | |
419 View::layerNameChanged() | |
420 { | |
421 Layer *layer = dynamic_cast<Layer *>(sender()); | |
422 if (layer) emit propertyContainerNameChanged(layer); | |
423 } | |
424 | |
425 void | |
426 View::viewManagerCentreFrameChanged(void *p, unsigned long f, bool locked) | |
427 { | |
428 if (m_followPan && p != this && locked) { | |
429 if (m_manager && (sender() == m_manager)) { | |
430 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
431 std::cerr << this << ": manager frame changed " << f << " from " << p << std::endl; | |
432 #endif | |
433 setCentreFrame(f); | |
434 if (p == this) repaint(); | |
435 } | |
436 } | |
437 } | |
438 | |
439 void | |
440 View::viewManagerPlaybackFrameChanged(unsigned long f) | |
441 { | |
442 if (m_manager) { | |
443 if (sender() != m_manager) return; | |
444 } | |
445 | |
446 if (m_playPointerFrame == f) return; | |
447 bool visible = (m_playPointerFrame / m_zoomLevel != f / m_zoomLevel); | |
448 size_t oldPlayPointerFrame = m_playPointerFrame; | |
449 m_playPointerFrame = f; | |
450 if (!visible) return; | |
451 | |
452 switch (m_followPlay) { | |
453 | |
454 case PlaybackScrollContinuous: | |
455 if (QApplication::mouseButtons() == Qt::NoButton) { | |
456 setCentreFrame(f, false); | |
457 } | |
458 break; | |
459 | |
460 case PlaybackScrollPage: | |
461 { | |
462 long w = width() * getZoomLevel(); | |
463 w -= w/5; | |
464 long sf = (f / w) * w - w/8; | |
465 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
466 std::cerr << "PlaybackScrollPage: f = " << f << ", sf = " << sf << ", start frame " | |
467 << getStartFrame() << std::endl; | |
468 #endif | |
469 setCentreFrame(sf + width() * getZoomLevel() / 2, false); | |
470 int xold = (long(oldPlayPointerFrame) - getStartFrame()) / m_zoomLevel; | |
471 int xnew = (long(m_playPointerFrame) - getStartFrame()) / m_zoomLevel; | |
472 update(xold - 1, 0, 3, height()); | |
473 update(xnew - 1, 0, 3, height()); | |
474 break; | |
475 } | |
476 | |
477 case PlaybackIgnore: | |
478 if (long(f) >= getStartFrame() && f < getEndFrame()) { | |
479 update(); | |
480 } | |
481 break; | |
482 } | |
483 } | |
484 | |
485 void | |
486 View::viewManagerZoomLevelChanged(void *p, unsigned long z, bool locked) | |
487 { | |
488 if (m_followZoom && p != this && locked) { | |
489 if (m_manager && (sender() == m_manager)) { | |
490 setZoomLevel(z); | |
491 if (p == this) repaint(); | |
492 } | |
493 } | |
494 } | |
495 | |
496 size_t | |
497 View::getModelsStartFrame() const | |
498 { | |
499 bool first = true; | |
500 size_t startFrame = 0; | |
501 | |
502 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
503 | |
504 if ((*i)->getModel() && (*i)->getModel()->isOK()) { | |
505 | |
506 size_t thisStartFrame = (*i)->getModel()->getStartFrame(); | |
507 | |
508 if (first || thisStartFrame < startFrame) { | |
509 startFrame = thisStartFrame; | |
510 } | |
511 first = false; | |
512 } | |
513 } | |
514 return startFrame; | |
515 } | |
516 | |
517 size_t | |
518 View::getModelsEndFrame() const | |
519 { | |
520 bool first = true; | |
521 size_t endFrame = 0; | |
522 | |
523 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
524 | |
525 if ((*i)->getModel() && (*i)->getModel()->isOK()) { | |
526 | |
527 size_t thisEndFrame = (*i)->getModel()->getEndFrame(); | |
528 | |
529 if (first || thisEndFrame > endFrame) { | |
530 endFrame = thisEndFrame; | |
531 } | |
532 first = false; | |
533 } | |
534 } | |
535 | |
536 if (first) return getModelsStartFrame(); | |
537 return endFrame; | |
538 } | |
539 | |
540 int | |
541 View::getModelsSampleRate() const | |
542 { | |
543 //!!! Just go for the first, for now. If we were supporting | |
544 // multiple samplerates, we'd probably want to do frame/time | |
545 // conversion in the model | |
546 | |
547 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
548 if ((*i)->getModel() && (*i)->getModel()->isOK()) { | |
549 return (*i)->getModel()->getSampleRate(); | |
550 } | |
551 } | |
552 return 0; | |
553 } | |
554 | |
555 bool | |
556 View::areLayersScrollable() const | |
557 { | |
558 // True iff all views are scrollable | |
559 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
560 if (!(*i)->isLayerScrollable()) return false; | |
561 } | |
562 return true; | |
563 } | |
564 | |
565 View::LayerList | |
566 View::getScrollableBackLayers(bool &changed) const | |
567 { | |
568 changed = false; | |
569 | |
570 LayerList scrollables; | |
571 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
572 if ((*i)->isLayerScrollable()) scrollables.push_back(*i); | |
573 else { | |
574 if (scrollables != m_lastScrollableBackLayers) { | |
575 m_lastScrollableBackLayers = scrollables; | |
576 changed = true; | |
577 } | |
578 return scrollables; | |
579 } | |
580 } | |
581 | |
582 if (scrollables.size() == 1 && | |
583 dynamic_cast<TimeRulerLayer *>(*scrollables.begin())) { | |
584 | |
585 // If only the ruler is scrollable, it's not worth the bother | |
586 // -- it probably redraws as quickly as it refreshes from | |
587 // cache | |
588 scrollables.clear(); | |
589 } | |
590 | |
591 if (scrollables != m_lastScrollableBackLayers) { | |
592 m_lastScrollableBackLayers = scrollables; | |
593 changed = true; | |
594 } | |
595 return scrollables; | |
596 } | |
597 | |
598 View::LayerList | |
599 View::getNonScrollableFrontLayers(bool &changed) const | |
600 { | |
601 changed = false; | |
602 LayerList scrollables = getScrollableBackLayers(changed); | |
603 LayerList nonScrollables; | |
604 | |
605 // Everything in front of the first non-scrollable from the back | |
606 // should also be considered non-scrollable | |
607 | |
608 size_t count = 0; | |
609 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
610 if (count < scrollables.size()) { | |
611 ++count; | |
612 continue; | |
613 } | |
614 nonScrollables.push_back(*i); | |
615 } | |
616 | |
617 if (nonScrollables != m_lastNonScrollableBackLayers) { | |
618 m_lastNonScrollableBackLayers = nonScrollables; | |
619 changed = true; | |
620 } | |
621 | |
622 return nonScrollables; | |
623 } | |
624 | |
625 size_t | |
626 View::getZoomConstraintBlockSize(size_t blockSize, | |
627 ZoomConstraint::RoundingDirection dir) | |
628 const | |
629 { | |
630 size_t candidate = blockSize; | |
631 bool haveCandidate = false; | |
632 | |
633 for (LayerList::const_iterator i = m_layers.begin(); i != m_layers.end(); ++i) { | |
634 | |
635 if ((*i)->getZoomConstraint()) { | |
636 | |
637 size_t thisBlockSize = | |
638 (*i)->getZoomConstraint()->getNearestBlockSize | |
639 (blockSize, dir); | |
640 | |
641 // Go for the block size that's furthest from the one | |
642 // passed in. Most of the time, that's what we want. | |
643 if (!haveCandidate || | |
644 (thisBlockSize > blockSize && thisBlockSize > candidate) || | |
645 (thisBlockSize < blockSize && thisBlockSize < candidate)) { | |
646 candidate = thisBlockSize; | |
647 haveCandidate = true; | |
648 } | |
649 } | |
650 } | |
651 | |
652 return candidate; | |
653 } | |
654 | |
655 void | |
656 View::zoom(bool in) | |
657 { | |
658 int newZoomLevel = m_zoomLevel; | |
659 | |
660 if (in) { | |
661 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel - 1, | |
662 ZoomConstraint::RoundDown); | |
663 } else { | |
664 newZoomLevel = getZoomConstraintBlockSize(newZoomLevel + 1, | |
665 ZoomConstraint::RoundUp); | |
666 } | |
667 | |
668 if (newZoomLevel != m_zoomLevel) { | |
669 setZoomLevel(newZoomLevel); | |
670 } | |
671 } | |
672 | |
673 void | |
674 View::checkProgress(void *object) | |
675 { | |
676 // std::cerr << "View::checkProgress(" << object << ")" << std::endl; | |
677 | |
678 if (!m_showProgress) return; | |
679 | |
680 int ph = height(); | |
681 | |
682 for (ProgressMap::const_iterator i = m_progressBars.begin(); | |
683 i != m_progressBars.end(); ++i) { | |
684 | |
685 if (i->first == object) { | |
686 | |
687 int completion = i->first->getCompletion(); | |
688 | |
689 if (completion >= 100) { | |
690 | |
691 i->second->hide(); | |
692 | |
693 } else { | |
694 | |
695 i->second->setText(i->first->getPropertyContainerName()); | |
696 i->second->setValue(completion); | |
697 i->second->move(0, ph - i->second->height()); | |
698 | |
699 i->second->show(); | |
700 i->second->update(); | |
701 | |
702 ph -= i->second->height(); | |
703 } | |
704 } else { | |
705 if (i->second->isVisible()) { | |
706 ph -= i->second->height(); | |
707 } | |
708 } | |
709 } | |
710 } | |
711 /*!!! | |
712 void | |
713 View::identifyLocalFeatures(bool on, int x, int y) | |
714 { | |
715 for (LayerList::const_iterator i = m_layers.end(); i != m_layers.begin(); ) { | |
716 --i; | |
717 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
718 std::cerr << "View::identifyLocalFeatures: calling on " << *i << std::endl; | |
719 #endif | |
720 if ((*i)->identifyLocalFeatures(on, x, y)) break; | |
721 } | |
722 } | |
723 */ | |
724 | |
725 void | |
726 View::paintEvent(QPaintEvent *e) | |
727 { | |
728 // Profiler prof("View::paintEvent", true); | |
729 // std::cerr << "View::paintEvent" << std::endl; | |
730 | |
731 if (m_layers.empty()) { | |
732 QFrame::paintEvent(e); | |
733 return; | |
734 } | |
735 | |
736 if (m_newModel) { | |
737 m_newModel = false; | |
738 } | |
739 | |
740 // ensure our constraints are met | |
741 m_zoomLevel = getZoomConstraintBlockSize(m_zoomLevel, | |
742 ZoomConstraint::RoundUp); | |
743 | |
744 QPainter paint; | |
745 bool repaintCache = false; | |
746 bool paintedCacheRect = false; | |
747 | |
748 QRect cacheRect(rect()); | |
749 | |
750 if (e) { | |
751 cacheRect &= e->rect(); | |
752 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
753 std::cerr << "paint rect " << cacheRect.width() << "x" << cacheRect.height() | |
754 << ", my rect " << width() << "x" << height() << std::endl; | |
755 #endif | |
756 } | |
757 | |
758 QRect nonCacheRect(cacheRect); | |
759 | |
760 // If not all layers are scrollable, but some of the back layers | |
761 // are, we should store only those in the cache | |
762 | |
763 bool layersChanged = false; | |
764 LayerList scrollables = getScrollableBackLayers(layersChanged); | |
765 LayerList nonScrollables = getNonScrollableFrontLayers(layersChanged); | |
766 | |
767 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
768 std::cerr << "View(" << this << ")::paintEvent: have " << scrollables.size() | |
769 << " scrollable back layers and " << nonScrollables.size() | |
770 << " non-scrollable front layers" << std::endl; | |
771 #endif | |
772 | |
773 if (layersChanged || scrollables.empty()) { | |
774 delete m_cache; | |
775 m_cache = 0; | |
776 } | |
777 | |
778 if (!scrollables.empty()) { | |
779 if (!m_cache || | |
780 m_cacheZoomLevel != m_zoomLevel || | |
781 width() != m_cache->width() || | |
782 height() != m_cache->height()) { | |
783 | |
784 // cache is not valid | |
785 | |
786 if (cacheRect.width() < width()/10) { | |
787 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
788 std::cerr << "View(" << this << ")::paintEvent: small repaint, not bothering to recreate cache" << std::endl; | |
789 #endif | |
790 } else { | |
791 delete m_cache; | |
792 m_cache = new QPixmap(width(), height()); | |
793 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
794 std::cerr << "View(" << this << ")::paintEvent: recreated cache" << std::endl; | |
795 #endif | |
796 cacheRect = rect(); | |
797 repaintCache = true; | |
798 } | |
799 | |
800 } else if (m_cacheCentreFrame != m_centreFrame) { | |
801 | |
802 long dx = long(m_cacheCentreFrame / m_zoomLevel) - | |
803 long(m_centreFrame / m_zoomLevel); | |
804 | |
805 if (dx > -width() && dx < width()) { | |
806 #if defined(Q_WS_WIN32) || defined(Q_WS_MAC) | |
807 // Copying a pixmap to itself doesn't work properly on Windows | |
808 // or Mac (it only works when moving in one direction) | |
809 static QPixmap *tmpPixmap = 0; | |
810 if (!tmpPixmap || | |
811 tmpPixmap->width() != width() || | |
812 tmpPixmap->height() != height()) { | |
813 delete tmpPixmap; | |
814 tmpPixmap = new QPixmap(width(), height()); | |
815 } | |
816 paint.begin(tmpPixmap); | |
817 paint.drawPixmap(0, 0, *m_cache); | |
818 paint.end(); | |
819 paint.begin(m_cache); | |
820 paint.drawPixmap(dx, 0, *tmpPixmap); | |
821 paint.end(); | |
822 #else | |
823 // But it seems to be fine on X11 | |
824 paint.begin(m_cache); | |
825 paint.drawPixmap(dx, 0, *m_cache); | |
826 paint.end(); | |
827 #endif | |
828 | |
829 if (dx < 0) { | |
830 cacheRect = QRect(width() + dx, 0, -dx, height()); | |
831 } else { | |
832 cacheRect = QRect(0, 0, dx, height()); | |
833 } | |
834 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
835 std::cerr << "View(" << this << ")::paintEvent: scrolled cache by " << dx << std::endl; | |
836 #endif | |
837 } else { | |
838 cacheRect = rect(); | |
839 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
840 std::cerr << "View(" << this << ")::paintEvent: scrolling too far" << std::endl; | |
841 #endif | |
842 } | |
843 repaintCache = true; | |
844 | |
845 } else { | |
846 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
847 std::cerr << "View(" << this << ")::paintEvent: cache is good" << std::endl; | |
848 #endif | |
849 paint.begin(this); | |
850 paint.drawPixmap(cacheRect, *m_cache, cacheRect); | |
851 paint.end(); | |
852 QFrame::paintEvent(e); | |
853 paintedCacheRect = true; | |
854 } | |
855 | |
856 m_cacheCentreFrame = m_centreFrame; | |
857 m_cacheZoomLevel = m_zoomLevel; | |
858 } | |
859 | |
860 #ifdef DEBUG_VIEW_WIDGET_PAINT | |
861 // std::cerr << "View(" << this << ")::paintEvent: cacheRect " << cacheRect << ", nonCacheRect " << (nonCacheRect | cacheRect) << ", repaintCache " << repaintCache << ", paintedCacheRect " << paintedCacheRect << std::endl; | |
862 #endif | |
863 | |
864 // Scrollable (cacheable) items first | |
865 | |
866 if (!paintedCacheRect) { | |
867 | |
868 if (repaintCache) paint.begin(m_cache); | |
869 else paint.begin(this); | |
870 | |
871 paint.setClipRect(cacheRect); | |
872 | |
873 if (hasLightBackground()) { | |
874 paint.setPen(Qt::white); | |
875 paint.setBrush(Qt::white); | |
876 } else { | |
877 paint.setPen(Qt::black); | |
878 paint.setBrush(Qt::black); | |
879 } | |
880 paint.drawRect(cacheRect); | |
881 | |
882 paint.setPen(Qt::black); | |
883 paint.setBrush(Qt::NoBrush); | |
884 | |
885 for (LayerList::iterator i = scrollables.begin(); i != scrollables.end(); ++i) { | |
886 (*i)->paint(paint, cacheRect); | |
887 } | |
888 | |
889 paint.end(); | |
890 | |
891 if (repaintCache) { | |
892 cacheRect |= (e ? e->rect() : rect()); | |
893 paint.begin(this); | |
894 paint.drawPixmap(cacheRect, *m_cache, cacheRect); | |
895 paint.end(); | |
896 } | |
897 } | |
898 | |
899 // Now non-cacheable items. We always need to redraw the | |
900 // non-cacheable items across at least the area we drew of the | |
901 // cacheable items. | |
902 | |
903 nonCacheRect |= cacheRect; | |
904 | |
905 paint.begin(this); | |
906 paint.setClipRect(nonCacheRect); | |
907 | |
908 if (scrollables.empty()) { | |
909 if (hasLightBackground()) { | |
910 paint.setPen(Qt::white); | |
911 paint.setBrush(Qt::white); | |
912 } else { | |
913 paint.setPen(Qt::black); | |
914 paint.setBrush(Qt::black); | |
915 } | |
916 paint.drawRect(nonCacheRect); | |
917 } | |
918 | |
919 paint.setPen(Qt::black); | |
920 paint.setBrush(Qt::NoBrush); | |
921 | |
922 for (LayerList::iterator i = nonScrollables.begin(); i != nonScrollables.end(); ++i) { | |
923 (*i)->paint(paint, nonCacheRect); | |
924 } | |
925 | |
926 paint.end(); | |
927 | |
928 if (m_followPlay != PlaybackScrollContinuous) { | |
929 | |
930 paint.begin(this); | |
931 | |
932 if (long(m_playPointerFrame) > getStartFrame() && | |
933 m_playPointerFrame < getEndFrame()) { | |
934 | |
935 int playx = (long(m_playPointerFrame) - getStartFrame()) / | |
936 m_zoomLevel; | |
937 | |
938 paint.setPen(Qt::black); | |
939 paint.drawLine(playx - 1, 0, playx - 1, height() - 1); | |
940 paint.drawLine(playx + 1, 0, playx + 1, height() - 1); | |
941 paint.drawPoint(playx, 0); | |
942 paint.drawPoint(playx, height() - 1); | |
943 paint.setPen(Qt::white); | |
944 paint.drawLine(playx, 1, playx, height() - 2); | |
945 } | |
946 | |
947 paint.end(); | |
948 } | |
949 | |
950 QFrame::paintEvent(e); | |
951 } | |
952 | |
953 #ifdef INCLUDE_MOCFILES | |
954 #include "View.moc.cpp" | |
955 #endif | |
956 |