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