1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3Support module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "q3canvas.h"
43 #include "qapplication.h"
44 #include "qbitmap.h"
45 #include "qdesktopwidget.h"
46 #include "qimage.h"
47 #include "q3ptrdict.h"
48 #include "qpainter.h"
49 #include "q3polygonscanner.h"
50 #include "qtimer.h"
51 #include "q3tl.h"
52 
53 #include <stdlib.h>
54 
55 QT_BEGIN_NAMESPACE
56 
57 using namespace Qt;
58 
59 class Q3CanvasData {
60 public:
Q3CanvasData()61     Q3CanvasData() :
62 	itemDict(1013), animDict(503)
63     {
64     }
65 
66     Q3PtrList<Q3CanvasView> viewList;
67     Q3PtrDict<void> itemDict;
68     Q3PtrDict<void> animDict;
69 };
70 
71 class Q3CanvasViewData {
72 public:
Q3CanvasViewData()73     Q3CanvasViewData() {}
74 #ifndef QT_NO_TRANSFORMATIONS
75     QMatrix xform;
76     QMatrix ixform;
77 #endif
78     QRegion eraseRegion;
79 };
80 
81 // clusterizer
82 
83 class Q3CanvasClusterizer {
84 public:
85     Q3CanvasClusterizer(int maxclusters);
86     ~Q3CanvasClusterizer();
87 
88     void add(int x, int y); // 1x1 rectangle (point)
89     void add(int x, int y, int w, int h);
90     void add(const QRect& rect);
91 
92     void clear();
clusters() const93     int clusters() const { return count; }
94     const QRect& operator[](int i) const;
95 
96 private:
97     QRect* cluster;
98     int count;
99     const int maxcl;
100 };
101 
102 static
include(QRect & r,const QRect & rect)103 void include(QRect& r, const QRect& rect)
104 {
105     if (rect.left()<r.left()) {
106 	    r.setLeft(rect.left());
107     }
108     if (rect.right()>r.right()) {
109 	    r.setRight(rect.right());
110     }
111     if (rect.top()<r.top()) {
112 	    r.setTop(rect.top());
113     }
114     if (rect.bottom()>r.bottom()) {
115 	    r.setBottom(rect.bottom());
116     }
117 }
118 
119 /*
120 A Q3CanvasClusterizer groups rectangles (QRects) into non-overlapping rectangles
121 by a merging heuristic.
122 */
Q3CanvasClusterizer(int maxclusters)123 Q3CanvasClusterizer::Q3CanvasClusterizer(int maxclusters) :
124     cluster(new QRect[maxclusters]),
125     count(0),
126     maxcl(maxclusters)
127 { }
128 
~Q3CanvasClusterizer()129 Q3CanvasClusterizer::~Q3CanvasClusterizer()
130 {
131     delete [] cluster;
132 }
133 
clear()134 void Q3CanvasClusterizer::clear()
135 {
136     count=0;
137 }
138 
add(int x,int y)139 void Q3CanvasClusterizer::add(int x, int y)
140 {
141     add(QRect(x,y,1,1));
142 }
143 
add(int x,int y,int w,int h)144 void Q3CanvasClusterizer::add(int x, int y, int w, int h)
145 {
146     add(QRect(x,y,w,h));
147 }
148 
add(const QRect & rect)149 void Q3CanvasClusterizer::add(const QRect& rect)
150 {
151     QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2);
152 
153     //Q_ASSERT(rect.width()>0 && rect.height()>0);
154 
155     int cursor;
156 
157     for (cursor=0; cursor<count; cursor++) {
158 	if (cluster[cursor].contains(rect)) {
159 	    // Wholly contained already.
160 	    return;
161 	}
162     }
163 
164     int lowestcost=9999999;
165     int cheapest=-1;
166     cursor = 0;
167     while(cursor<count) {
168 	if (cluster[cursor].intersects(biggerrect)) {
169 	    QRect larger=cluster[cursor];
170 	    include(larger,rect);
171 	    int cost = larger.width()*larger.height() -
172 		       cluster[cursor].width()*cluster[cursor].height();
173 
174 	    if (cost < lowestcost) {
175 		bool bad=false;
176 		for (int c=0; c<count && !bad; c++) {
177 		    bad=cluster[c].intersects(larger) && c!=cursor;
178 		}
179 		if (!bad) {
180 		    cheapest=cursor;
181 		    lowestcost=cost;
182 		}
183 	    }
184 	}
185 	cursor++;
186     }
187 
188     if (cheapest>=0) {
189 	include(cluster[cheapest],rect);
190 	return;
191     }
192 
193     if (count < maxcl) {
194 	cluster[count++]=rect;
195 	return;
196     }
197 
198     // Do cheapest of:
199     //     add to closest cluster
200     //     do cheapest cluster merge, add to new cluster
201 
202     lowestcost=9999999;
203     cheapest=-1;
204     cursor=0;
205     while(cursor<count) {
206 	QRect larger=cluster[cursor];
207 	include(larger,rect);
208 	int cost=larger.width()*larger.height()
209 		- cluster[cursor].width()*cluster[cursor].height();
210 	if (cost < lowestcost) {
211 	    bool bad=false;
212 	    for (int c=0; c<count && !bad; c++) {
213 		bad=cluster[c].intersects(larger) && c!=cursor;
214 	    }
215 	    if (!bad) {
216 		cheapest=cursor;
217 		lowestcost=cost;
218 	    }
219 	}
220 	cursor++;
221     }
222 
223     // ###
224     // could make an heuristic guess as to whether we need to bother
225     // looking for a cheap merge.
226 
227     int cheapestmerge1 = -1;
228     int cheapestmerge2 = -1;
229 
230     int merge1 = 0;
231     while(merge1 < count) {
232 	int merge2=0;
233 	while(merge2 < count) {
234 	    if(merge1!=merge2) {
235 		QRect larger=cluster[merge1];
236 		include(larger,cluster[merge2]);
237 		int cost=larger.width()*larger.height()
238 		    - cluster[merge1].width()*cluster[merge1].height()
239 		    - cluster[merge2].width()*cluster[merge2].height();
240 		if (cost < lowestcost) {
241 		    bool bad=false;
242 		    for (int c=0; c<count && !bad; c++) {
243 			bad=cluster[c].intersects(larger) && c!=cursor;
244 		    }
245 		    if (!bad) {
246 			cheapestmerge1=merge1;
247 			cheapestmerge2=merge2;
248 			lowestcost=cost;
249 		    }
250 		}
251 	    }
252 	    merge2++;
253 	}
254 	merge1++;
255     }
256 
257     if (cheapestmerge1>=0) {
258 	include(cluster[cheapestmerge1],cluster[cheapestmerge2]);
259 	cluster[cheapestmerge2]=cluster[count--];
260     } else {
261 	// if (!cheapest) debugRectangles(rect);
262 	include(cluster[cheapest],rect);
263     }
264 
265     // NB: clusters do not intersect (or intersection will
266     //     overwrite). This is a result of the above algorithm,
267     //     given the assumption that (x,y) are ordered topleft
268     //     to bottomright.
269 
270     // ###
271     //
272     // add explicit x/y ordering to that comment, move it to the top
273     // and rephrase it as pre-/post-conditions.
274 }
275 
operator [](int i) const276 const QRect& Q3CanvasClusterizer::operator[](int i) const
277 {
278     return cluster[i];
279 }
280 
281 // end of clusterizer
282 
283 // there's no more device coordinate clipping done, so introduce these
284 // clip setting compat functions
285 
qt_setclipregion(QPainter * p,const QRegion & r)286 static void qt_setclipregion(QPainter *p, const QRegion &r)
287 {
288     QMatrix matrix = p->worldMatrix();
289     p->setWorldMatrix(QMatrix());
290     p->setClipRegion(r);
291     p->setWorldMatrix(matrix);
292 }
293 
qt_setcliprect(QPainter * p,const QRect & r)294 static void qt_setcliprect(QPainter *p, const QRect &r)
295 {
296     qt_setclipregion(p, QRegion(r));
297 }
298 
299 
300 class Q_COMPAT_EXPORT Q3CanvasItemPtr {
301 public:
Q3CanvasItemPtr()302     Q3CanvasItemPtr() : ptr(0) { }
Q3CanvasItemPtr(Q3CanvasItem * p)303     Q3CanvasItemPtr(Q3CanvasItem* p) : ptr(p) { }
304 
operator <=(const Q3CanvasItemPtr & that) const305     bool operator<=(const Q3CanvasItemPtr& that) const
306     {
307 	// Order same-z objects by identity.
308 	if (that.ptr->z()==ptr->z())
309 	    return that.ptr <= ptr;
310 	return that.ptr->z() <= ptr->z();
311     }
operator <(const Q3CanvasItemPtr & that) const312     bool operator<(const Q3CanvasItemPtr& that) const
313     {
314 	// Order same-z objects by identity.
315 	if (that.ptr->z()==ptr->z())
316 	    return that.ptr < ptr;
317 	return that.ptr->z() < ptr->z();
318     }
operator >(const Q3CanvasItemPtr & that) const319     bool operator>(const Q3CanvasItemPtr& that) const
320     {
321 	// Order same-z objects by identity.
322 	if (that.ptr->z()==ptr->z())
323 	    return that.ptr > ptr;
324 	return that.ptr->z() > ptr->z();
325     }
operator ==(const Q3CanvasItemPtr & that) const326     bool operator==(const Q3CanvasItemPtr& that) const
327     {
328 	    return that.ptr == ptr;
329     }
operator Q3CanvasItem*() const330     operator Q3CanvasItem*() const { return ptr; }
331 
332 private:
333     Q3CanvasItem* ptr;
334 };
335 
336 
337 /*!
338     \class Q3CanvasItemList
339     \compat
340     \brief The Q3CanvasItemList class is a list of Q3CanvasItems.
341 
342     Q3CanvasItemList is a Q3ValueList of pointers to \l{Q3CanvasItem}s.
343     This class is used by some methods in Q3Canvas that need to return
344     a list of canvas items.
345 
346     The \l Q3ValueList documentation describes how to use this list.
347 
348     \sa QtCanvas, {Porting to Graphics View}
349 */
350 
351 /*!
352   \internal
353 */
sort()354 void Q3CanvasItemList::sort()
355 {
356     qHeapSort(*((Q3ValueList<Q3CanvasItemPtr>*)this));
357 }
358 
359 /*!
360   \internal
361 */
drawUnique(QPainter & painter)362 void Q3CanvasItemList::drawUnique(QPainter& painter)
363 {
364     Q3CanvasItem* prev=0;
365     for (Iterator it=fromLast(); it!=end(); --it) {
366 	Q3CanvasItem *g=*it;
367 	if (g!=prev) {
368 	    g->draw(painter);
369 	    prev=g;
370 	}
371     }
372 }
373 
374 /*!
375     Returns the concatenation of this list and list \a l.
376 */
operator +(const Q3CanvasItemList & l) const377 Q3CanvasItemList Q3CanvasItemList::operator+(const Q3CanvasItemList &l) const
378 {
379     Q3CanvasItemList l2(*this);
380     for(const_iterator it = l.begin(); it != l.end(); ++it)
381        l2.append(*it);
382     return l2;
383 }
384 
385 class Q3CanvasChunk {
386 public:
Q3CanvasChunk()387     Q3CanvasChunk() : changed(true) { }
388     // Other code assumes lists are not deleted. Assignment is also
389     // done on ChunkRecs. So don't add that sort of thing here.
390 
sort()391     void sort()
392     {
393 	list.sort();
394     }
395 
listPtr() const396     const Q3CanvasItemList* listPtr() const
397     {
398 	return &list;
399     }
400 
add(Q3CanvasItem * item)401     void add(Q3CanvasItem* item)
402     {
403 	list.prepend(item);
404 	changed = true;
405     }
406 
remove(Q3CanvasItem * item)407     void remove(Q3CanvasItem* item)
408     {
409 	list.remove(item);
410 	changed = true;
411     }
412 
change()413     void change()
414     {
415 	changed = true;
416     }
417 
hasChanged() const418     bool hasChanged() const
419     {
420 	return changed;
421     }
422 
takeChange()423     bool takeChange()
424     {
425 	bool y = changed;
426 	changed = false;
427 	return y;
428     }
429 
430 private:
431     Q3CanvasItemList list;
432     bool changed;
433 };
434 
435 
gcd(int a,int b)436 static int gcd(int a, int b)
437 {
438     int r;
439     while ((r = a%b)) {
440 	a=b;
441 	b=r;
442     }
443     return b;
444 }
445 
scm(int a,int b)446 static int scm(int a, int b)
447 {
448     int g = gcd(a,b);
449     return a/g*b;
450 }
451 
452 
453 
454 /*!
455     \class Q3Canvas
456     \compat
457     \brief The Q3Canvas class provides a 2D area that can contain Q3CanvasItem objects.
458 
459     The Q3Canvas class manages its 2D graphic area and all the canvas
460     items the area contains. The canvas has no visual appearance of
461     its own. Instead, it is displayed on screen using a Q3CanvasView.
462     Multiple Q3CanvasView widgets may be associated with a canvas to
463     provide multiple views of the same canvas.
464 
465     The canvas is optimized for large numbers of items, particularly
466     where only a small percentage of the items change at any
467     one time. If the entire display changes very frequently, you should
468     consider using your own custom Q3ScrollView subclass.
469 
470     Qt provides a rich
471     set of canvas item classes, e.g. Q3CanvasEllipse, Q3CanvasLine,
472     Q3CanvasPolygon, Q3CanvasPolygonalItem, Q3CanvasRectangle, Q3CanvasSpline,
473     Q3CanvasSprite and Q3CanvasText. You can subclass to create your own
474     canvas items; Q3CanvasPolygonalItem is the most common base class used
475     for this purpose.
476 
477     Items appear on the canvas after their \link Q3CanvasItem::show()
478     show()\endlink function has been called (or \link
479     Q3CanvasItem::setVisible() setVisible(true)\endlink), and \e after
480     update() has been called. The canvas only shows items that are
481     \link Q3CanvasItem::setVisible() visible\endlink, and then only if
482     \l update() is called. (By default the canvas is white and so are
483     canvas items, so if nothing appears try changing colors.)
484 
485     If you created the canvas without passing a width and height to
486     the constructor you must also call resize().
487 
488     Although a canvas may appear to be similar to a widget with child
489     widgets, there are several notable differences:
490 
491     \list
492     \i Canvas items are usually much faster to manipulate and redraw than
493     child widgets, with the speed advantage becoming especially great when
494     there are \e many canvas items and non-rectangular items. In most
495     situations canvas items are also a lot more memory efficient than child
496     widgets.
497 
498     \i It's easy to detect overlapping items (collision detection).
499 
500     \i The canvas can be larger than a widget. A million-by-million canvas
501     is perfectly possible. At such a size a widget might be very
502     inefficient, and some window systems might not support it at all,
503     whereas Q3Canvas scales well. Even with a billion pixels and a million
504     items, finding a particular canvas item, detecting collisions, etc.,
505     is still fast (though the memory consumption may be prohibitive
506     at such extremes).
507 
508     \i Two or more Q3CanvasView objects can view the same canvas.
509 
510     \i An arbitrary transformation matrix can be set on each Q3CanvasView
511     which makes it easy to zoom, rotate or shear the viewed canvas.
512 
513     \i Widgets provide a lot more functionality, such as input (QKeyEvent,
514     QMouseEvent etc.) and layout management (QGridLayout etc.).
515 
516     \endlist
517 
518     A canvas consists of a background, a number of canvas items organized by
519     x, y and z coordinates, and a foreground. A canvas item's z coordinate
520     can be treated as a layer number -- canvas items with a higher z
521     coordinate appear in front of canvas items with a lower z coordinate.
522 
523     The background is white by default, but can be set to a different color
524     using setBackgroundColor(), or to a repeated pixmap using
525     setBackgroundPixmap() or to a mosaic of smaller pixmaps using
526     setTiles(). Individual tiles can be set with setTile(). There
527     are corresponding get functions, e.g. backgroundColor() and
528     backgroundPixmap().
529 
530     Note that Q3Canvas does not inherit from QWidget, even though it has some
531     functions which provide the same functionality as those in QWidget. One
532     of these is setBackgroundPixmap(); some others are resize(), size(),
533     width() and height(). \l Q3CanvasView is the widget used to display a
534     canvas on the screen.
535 
536     Canvas items are added to a canvas by constructing them and passing the
537     canvas to the canvas item's constructor. An item can be moved to a
538     different canvas using Q3CanvasItem::setCanvas().
539 
540     Canvas items are movable (and in the case of Q3CanvasSprites, animated)
541     objects that inherit Q3CanvasItem. Each canvas item has a position on the
542     canvas (x, y coordinates) and a height (z coordinate), all of which are
543     held as floating-point numbers. Moving canvas items also have x and y
544     velocities. It's possible for a canvas item to be outside the canvas
545     (for example Q3CanvasItem::x() is greater than width()). When a canvas
546     item is off the canvas, onCanvas() returns false and the canvas
547     disregards the item. (Canvas items off the canvas do not slow down any
548     of the common operations on the canvas.)
549 
550     Canvas items can be moved with Q3CanvasItem::move(). The advance()
551     function moves all Q3CanvasItem::animated() canvas items and
552     setAdvancePeriod() makes Q3Canvas move them automatically on a periodic
553     basis. In the context of the Q3Canvas classes, to `animate' a canvas item
554     is to set it in motion, i.e. using Q3CanvasItem::setVelocity(). Animation
555     of a canvas item itself, i.e. items which change over time, is enabled
556     by calling Q3CanvasSprite::setFrameAnimation(), or more generally by
557     subclassing and reimplementing Q3CanvasItem::advance(). To detect collisions
558     use one of the Q3CanvasItem::collisions() functions.
559 
560     The changed parts of the canvas are redrawn (if they are visible in a
561     canvas view) whenever update() is called. You can either call update()
562     manually after having changed the contents of the canvas, or force
563     periodic updates using setUpdatePeriod(). If you have moving objects on
564     the canvas, you must call advance() every time the objects should
565     move one step further. Periodic calls to advance() can be forced using
566     setAdvancePeriod(). The advance() function will call
567     Q3CanvasItem::advance() on every item that is \link
568     Q3CanvasItem::animated() animated\endlink and trigger an update of the
569     affected areas afterwards. (A canvas item that is `animated' is simply
570     a canvas item that is in motion.)
571 
572     Q3Canvas organizes its canvas items into \e chunks; these are areas on
573     the canvas that are used to speed up most operations. Many operations
574     start by eliminating most chunks (i.e. those which haven't changed)
575     and then process only the canvas items that are in the few interesting
576     (i.e. changed) chunks. A valid chunk, validChunk(), is one which is on
577     the canvas.
578 
579     The chunk size is a key factor to Q3Canvas's speed: if there are too many
580     chunks, the speed benefit of grouping canvas items into chunks is
581     reduced. If the chunks are too large, it takes too long to process each
582     one. The Q3Canvas constructor tries to pick a suitable size, but you
583     can call retune() to change it at any time. The chunkSize() function
584     returns the current chunk size. The canvas items always make sure
585     they're in the right chunks; all you need to make sure of is that
586     the canvas uses the right chunk size. A good rule of thumb is that
587     the size should be a bit smaller than the average canvas item
588     size. If you have moving objects, the chunk size should be a bit
589     smaller than the average size of the moving items.
590 
591     The foreground is normally nothing, but if you reimplement
592     drawForeground(), you can draw things in front of all the canvas
593     items.
594 
595     Areas can be set as changed with setChanged() and set unchanged with
596     setUnchanged(). The entire canvas can be set as changed with
597     setAllChanged(). A list of all the items on the canvas is returned by
598     allItems().
599 
600     An area can be copied (painted) to a QPainter with drawArea().
601 
602     If the canvas is resized it emits the resized() signal.
603 
604     The examples/canvas application and the 2D graphics page of the
605     examples/demo application demonstrate many of Q3Canvas's facilities.
606 
607     \sa Q3CanvasView Q3CanvasItem, QtCanvas, {Porting to Graphics View}
608 */
init(int w,int h,int chunksze,int mxclusters)609 void Q3Canvas::init(int w, int h, int chunksze, int mxclusters)
610 {
611     d = new Q3CanvasData;
612     awidth=w;
613     aheight=h;
614     chunksize=chunksze;
615     maxclusters=mxclusters;
616     chwidth=(w+chunksize-1)/chunksize;
617     chheight=(h+chunksize-1)/chunksize;
618     chunks=new Q3CanvasChunk[chwidth*chheight];
619     update_timer = 0;
620     bgcolor = white;
621     grid = 0;
622     htiles = 0;
623     vtiles = 0;
624     dblbuf = false;
625     debug_redraw_areas = false;
626 }
627 
628 /*!
629     Create a Q3Canvas with no size. \a parent and \a name are passed to
630     the QObject superclass.
631 
632     \warning You \e must call resize() at some time after creation to
633     be able to use the canvas.
634 */
Q3Canvas(QObject * parent,const char * name)635 Q3Canvas::Q3Canvas(QObject* parent, const char* name)
636     : QObject(parent, name)
637 {
638     init(0,0);
639 }
640 
641 /*!
642     Constructs a Q3Canvas that is \a w pixels wide and \a h pixels high.
643 */
Q3Canvas(int w,int h)644 Q3Canvas::Q3Canvas(int w, int h)
645 {
646     init(w,h);
647 }
648 
649 /*!
650     Constructs a Q3Canvas which will be composed of \a h tiles
651     horizontally and \a v tiles vertically. Each tile will be an image
652     \a tilewidth by \a tileheight pixels taken from pixmap \a p.
653 
654     The pixmap \a p is a list of tiles, arranged left to right, (and
655     in the case of pixmaps that have multiple rows of tiles, top to
656     bottom), with tile 0 in the top-left corner, tile 1 next to the
657     right, and so on, e.g.
658 
659     \table
660     \row \i 0 \i 1 \i 2 \i 3
661     \row \i 4 \i 5 \i 6 \i 7
662     \endtable
663 
664     The Q3Canvas is initially sized to show exactly the given number of
665     tiles horizontally and vertically. If it is resized to be larger,
666     the entire matrix of tiles will be repeated as often as necessary
667     to cover the area. If it is smaller, tiles to the right and bottom
668     will not be visible.
669 
670     \sa setTiles()
671 */
Q3Canvas(QPixmap p,int h,int v,int tilewidth,int tileheight)672 Q3Canvas::Q3Canvas(QPixmap p,
673 	int h, int v, int tilewidth, int tileheight)
674 {
675     init(h*tilewidth, v*tileheight, scm(tilewidth,tileheight));
676     setTiles(p, h, v, tilewidth, tileheight);
677 }
678 
qt_unview(Q3Canvas * c)679 void qt_unview(Q3Canvas* c)
680 {
681     for (Q3CanvasView* view=c->d->viewList.first(); view != 0; view=c->d->viewList.next()) {
682 	view->viewing = 0;
683     }
684 }
685 
686 /*!
687     Destroys the canvas and all the canvas's canvas items.
688 */
~Q3Canvas()689 Q3Canvas::~Q3Canvas()
690 {
691     qt_unview(this);
692     Q3CanvasItemList all = allItems();
693     for (Q3CanvasItemList::Iterator it=all.begin(); it!=all.end(); ++it)
694 	delete *it;
695     delete [] chunks;
696     delete [] grid;
697     delete d;
698 }
699 
700 /*!
701 \internal
702 Returns the chunk at a chunk position \a i, \a j.
703 */
chunk(int i,int j) const704 Q3CanvasChunk& Q3Canvas::chunk(int i, int j) const
705 {
706     return chunks[i+chwidth*j];
707 }
708 
709 /*!
710 \internal
711 Returns the chunk at a pixel position \a x, \a y.
712 */
chunkContaining(int x,int y) const713 Q3CanvasChunk& Q3Canvas::chunkContaining(int x, int y) const
714 {
715     return chunk(x/chunksize,y/chunksize);
716 }
717 
718 /*!
719     Returns a list of all the items in the canvas.
720 */
allItems()721 Q3CanvasItemList Q3Canvas::allItems()
722 {
723     Q3CanvasItemList list;
724     for (Q3PtrDictIterator<void> it=d->itemDict; it.currentKey(); ++it) {
725 	list.prepend((Q3CanvasItem*)it.currentKey());
726     }
727     return list;
728 }
729 
730 
731 /*!
732     Changes the size of the canvas to have a width of \a w and a
733     height of \a h. This is a slow operation.
734 */
resize(int w,int h)735 void Q3Canvas::resize(int w, int h)
736 {
737     if (awidth==w && aheight==h)
738 	return;
739 
740     Q3CanvasItem* item;
741     Q3PtrList<Q3CanvasItem> hidden;
742     for (Q3PtrDictIterator<void> it=d->itemDict; it.currentKey(); ++it) {
743 	if (((Q3CanvasItem*)it.currentKey())->isVisible()) {
744 	    ((Q3CanvasItem*)it.currentKey())->hide();
745 	    hidden.append(((Q3CanvasItem*)it.currentKey()));
746 	}
747     }
748 
749     int nchwidth=(w+chunksize-1)/chunksize;
750     int nchheight=(h+chunksize-1)/chunksize;
751 
752     Q3CanvasChunk* newchunks = new Q3CanvasChunk[nchwidth*nchheight];
753 
754     // Commit the new values.
755     //
756     awidth=w;
757     aheight=h;
758     chwidth=nchwidth;
759     chheight=nchheight;
760     delete [] chunks;
761     chunks=newchunks;
762 
763     for (item=hidden.first(); item != 0; item=hidden.next()) {
764 	item->show();
765     }
766 
767     setAllChanged();
768 
769     emit resized();
770 }
771 
772 /*!
773     \fn void Q3Canvas::resized()
774 
775     This signal is emitted whenever the canvas is resized. Each
776     Q3CanvasView connects to this signal to keep the scrollview's size
777     correct.
778 */
779 
780 /*!
781     Change the efficiency tuning parameters to \a mxclusters clusters,
782     each of size \a chunksze. This is a slow operation if there are
783     many objects on the canvas.
784 
785     The canvas is divided into chunks which are rectangular areas \a
786     chunksze wide by \a chunksze high. Use a chunk size which is about
787     the average size of the canvas items. If you choose a chunk size
788     which is too small it will increase the amount of calculation
789     required when drawing since each change will affect many chunks.
790     If you choose a chunk size which is too large the amount of
791     drawing required will increase because for each change, a lot of
792     drawing will be required since there will be many (unchanged)
793     canvas items which are in the same chunk as the changed canvas
794     items.
795 
796     Internally, a canvas uses a low-resolution "chunk matrix" to keep
797     track of all the items in the canvas. A 64x64 chunk matrix is the
798     default for a 1024x1024 pixel canvas, where each chunk collects
799     canvas items in a 16x16 pixel square. This default is also
800     affected by setTiles(). You can tune this default using this
801     function. For example if you have a very large canvas and want to
802     trade off speed for memory then you might set the chunk size to 32
803     or 64.
804 
805     The \a mxclusters argument is the number of rectangular groups of
806     chunks that will be separately drawn. If the canvas has a large
807     number of small, dispersed items, this should be about that
808     number. Our testing suggests that a large number of clusters is
809     almost always best.
810 
811 */
retune(int chunksze,int mxclusters)812 void Q3Canvas::retune(int chunksze, int mxclusters)
813 {
814     maxclusters=mxclusters;
815 
816     if (chunksize!=chunksze) {
817 	Q3PtrList<Q3CanvasItem> hidden;
818 	for (Q3PtrDictIterator<void> it=d->itemDict; it.currentKey(); ++it) {
819 	    if (((Q3CanvasItem*)it.currentKey())->isVisible()) {
820 		((Q3CanvasItem*)it.currentKey())->hide();
821 		hidden.append(((Q3CanvasItem*)it.currentKey()));
822 	    }
823 	}
824 
825 	chunksize=chunksze;
826 
827 	int nchwidth=(awidth+chunksize-1)/chunksize;
828 	int nchheight=(aheight+chunksize-1)/chunksize;
829 
830 	Q3CanvasChunk* newchunks = new Q3CanvasChunk[nchwidth*nchheight];
831 
832 	// Commit the new values.
833 	//
834 	chwidth=nchwidth;
835 	chheight=nchheight;
836 	delete [] chunks;
837 	chunks=newchunks;
838 
839 	for (Q3CanvasItem* item=hidden.first(); item != 0; item=hidden.next()) {
840 	    item->show();
841 	}
842     }
843 }
844 
845 /*!
846     \fn int Q3Canvas::width() const
847 
848     Returns the width of the canvas, in pixels.
849 */
850 
851 /*!
852     \fn int Q3Canvas::height() const
853 
854     Returns the height of the canvas, in pixels.
855 */
856 
857 /*!
858     \fn QSize Q3Canvas::size() const
859 
860     Returns the size of the canvas, in pixels.
861 */
862 
863 /*!
864     \fn QRect Q3Canvas::rect() const
865 
866     Returns a rectangle the size of the canvas.
867 */
868 
869 
870 /*!
871     \fn bool Q3Canvas::onCanvas(int x, int y) const
872 
873     Returns true if the pixel position (\a x, \a y) is on the canvas;
874     otherwise returns false.
875 
876     \sa validChunk()
877 */
878 
879 /*!
880     \fn bool Q3Canvas::onCanvas(const QPoint& p) const
881     \overload
882 
883     Returns true if the pixel position \a p is on the canvas;
884     otherwise returns false.
885 
886     \sa validChunk()
887 */
888 
889 /*!
890     \fn bool Q3Canvas::validChunk(int x, int y) const
891 
892     Returns true if the chunk position (\a x, \a y) is on the canvas;
893     otherwise returns false.
894 
895     \sa onCanvas()
896 */
897 
898 /*!
899   \fn bool Q3Canvas::validChunk(const QPoint& p) const
900   \overload
901 
902   Returns true if the chunk position \a p is on the canvas; otherwise
903   returns false.
904 
905   \sa onCanvas()
906 */
907 
908 /*!
909     \fn int Q3Canvas::chunkSize() const
910 
911     Returns the chunk size of the canvas.
912 
913     \sa retune()
914 */
915 
916 /*!
917 \fn bool Q3Canvas::sameChunk(int x1, int y1, int x2, int y2) const
918 \internal
919 Tells if the points (\a x1, \a y1) and (\a x2, \a y2) are within the same chunk.
920 */
921 
922 /*!
923 \internal
924 This method adds an the item \a item to the list of Q3CanvasItem objects
925 in the Q3Canvas. The Q3CanvasItem class calls this.
926 */
addItem(Q3CanvasItem * item)927 void Q3Canvas::addItem(Q3CanvasItem* item)
928 {
929     d->itemDict.insert((void*)item,(void*)1);
930 }
931 
932 /*!
933 \internal
934 This method adds the item \a item to the list of Q3CanvasItem objects
935 to be moved. The Q3CanvasItem class calls this.
936 */
addAnimation(Q3CanvasItem * item)937 void Q3Canvas::addAnimation(Q3CanvasItem* item)
938 {
939     d->animDict.insert((void*)item,(void*)1);
940 }
941 
942 /*!
943 \internal
944 This method adds the item \a item  to the list of Q3CanvasItem objects
945 which are no longer to be moved. The Q3CanvasItem class calls this.
946 */
removeAnimation(Q3CanvasItem * item)947 void Q3Canvas::removeAnimation(Q3CanvasItem* item)
948 {
949     d->animDict.remove((void*)item);
950 }
951 
952 /*!
953 \internal
954 This method removes the item \a item from the list of Q3CanvasItem objects
955 in this Q3Canvas. The Q3CanvasItem class calls this.
956 */
removeItem(Q3CanvasItem * item)957 void Q3Canvas::removeItem(Q3CanvasItem* item)
958 {
959     d->itemDict.remove((void*)item);
960 }
961 
962 /*!
963 \internal
964 This method adds the view \a view to the list of Q3CanvasView objects
965 viewing this Q3Canvas. The Q3CanvasView class calls this.
966 */
addView(Q3CanvasView * view)967 void Q3Canvas::addView(Q3CanvasView* view)
968 {
969     d->viewList.append(view);
970     if (htiles>1 || vtiles>1 || pm.isNull())
971 	view->viewport()->setBackgroundColor(backgroundColor());
972 }
973 
974 /*!
975 \internal
976 This method removes the view \a view from the list of Q3CanvasView objects
977 viewing this Q3Canvas. The Q3CanvasView class calls this.
978 */
removeView(Q3CanvasView * view)979 void Q3Canvas::removeView(Q3CanvasView* view)
980 {
981     d->viewList.removeRef(view);
982 }
983 
984 /*!
985     Sets the canvas to call advance() every \a ms milliseconds. Any
986     previous setting by setAdvancePeriod() or setUpdatePeriod() is
987     overridden.
988 
989     If \a ms is less than 0 advancing will be stopped.
990 */
setAdvancePeriod(int ms)991 void Q3Canvas::setAdvancePeriod(int ms)
992 {
993     if (ms<0) {
994 	if (update_timer)
995 	    update_timer->stop();
996     } else {
997 	if (update_timer)
998 	    delete update_timer;
999 	update_timer = new QTimer(this);
1000 	connect(update_timer,SIGNAL(timeout()),this,SLOT(advance()));
1001 	update_timer->start(ms);
1002     }
1003 }
1004 
1005 /*!
1006     Sets the canvas to call update() every \a ms milliseconds. Any
1007     previous setting by setAdvancePeriod() or setUpdatePeriod() is
1008     overridden.
1009 
1010     If \a ms is less than 0 automatic updating will be stopped.
1011 */
setUpdatePeriod(int ms)1012 void Q3Canvas::setUpdatePeriod(int ms)
1013 {
1014     if (ms<0) {
1015 	if (update_timer)
1016 	    update_timer->stop();
1017     } else {
1018 	if (update_timer)
1019 	    delete update_timer;
1020 	update_timer = new QTimer(this);
1021 	connect(update_timer,SIGNAL(timeout()),this,SLOT(update()));
1022 	update_timer->start(ms);
1023     }
1024 }
1025 
1026 /*!
1027     Moves all Q3CanvasItem::animated() canvas items on the canvas and
1028     refreshes all changes to all views of the canvas. (An `animated'
1029     item is an item that is in motion; see setVelocity().)
1030 
1031     The advance takes place in two phases. In phase 0, the
1032     Q3CanvasItem::advance() function of each Q3CanvasItem::animated()
1033     canvas item is called with parameter 0. Then all these canvas
1034     items are called again, with parameter 1. In phase 0, the canvas
1035     items should not change position, merely examine other items on
1036     the canvas for which special processing is required, such as
1037     collisions between items. In phase 1, all canvas items should
1038     change positions, ignoring any other items on the canvas. This
1039     two-phase approach allows for considerations of "fairness",
1040     although no Q3CanvasItem subclasses supplied with Qt do anything
1041     interesting in phase 0.
1042 
1043     The canvas can be configured to call this function periodically
1044     with setAdvancePeriod().
1045 
1046     \sa update()
1047 */
advance()1048 void Q3Canvas::advance()
1049 {
1050     Q3PtrDictIterator<void> it=d->animDict;
1051     while (it.current()) {
1052 	Q3CanvasItem* i = (Q3CanvasItem*)(void*)it.currentKey();
1053 	++it;
1054 	if (i)
1055 	    i->advance(0);
1056     }
1057     // we expect the dict contains the exact same items as in the
1058     // first pass.
1059     it.toFirst();
1060     while (it.current()) {
1061 	Q3CanvasItem* i = (Q3CanvasItem*)(void*)it.currentKey();
1062 	++it;
1063 	if (i)
1064 	    i->advance(1);
1065     }
1066     update();
1067 }
1068 
1069 // Don't call this unless you know what you're doing.
1070 // p is in the content's co-ordinate example.
1071 /*!
1072   \internal
1073 */
drawViewArea(Q3CanvasView * view,QPainter * p,const QRect & vr,bool)1074 void Q3Canvas::drawViewArea(Q3CanvasView* view, QPainter* p, const QRect& vr, bool)
1075 {
1076     QPoint tl = view->contentsToViewport(QPoint(0,0));
1077 
1078 #ifndef QT_NO_TRANSFORMATIONS
1079     QMatrix wm = view->worldMatrix();
1080     QMatrix iwm = wm.invert();
1081     // ivr = covers all chunks in vr
1082     QRect ivr = iwm.map(vr);
1083     QMatrix twm;
1084     twm.translate(tl.x(),tl.y());
1085 #else
1086     QRect ivr = vr;
1087 #endif
1088 
1089     QRect all(0,0,width(),height());
1090 
1091     if (!all.contains(ivr)) {
1092 	// Need to clip with edge of canvas.
1093 
1094 #ifndef QT_NO_TRANSFORMATIONS
1095 	// For translation-only transformation, it is safe to include the right
1096 	// and bottom edges, but otherwise, these must be excluded since they
1097 	// are not precisely defined (different bresenham paths).
1098 	Q3PointArray a;
1099 	if (wm.m12()==0.0 && wm.m21()==0.0 && wm.m11() == 1.0 && wm.m22() == 1.0)
1100 	    a = Q3PointArray(QRect(all.x(),all.y(),all.width()+1,all.height()+1));
1101 	else
1102 	    a = Q3PointArray(all);
1103 
1104 	a = (wm*twm).map(a);
1105 #else
1106 	Q3PointArray a(QRect(all.x(),all.y(),all.width()+1,all.height()+1));
1107 #endif
1108 	if (view->viewport()->backgroundMode() == NoBackground) {
1109 	    QRect cvr = vr; cvr.moveBy(tl.x(),tl.y());
1110 	    qt_setclipregion(p, QRegion(cvr)-QRegion(a));
1111 	    p->fillRect(vr,view->viewport()->palette()
1112                         .brush(QPalette::Active,QPalette::Window));
1113 	}
1114 	qt_setclipregion(p, a);
1115     }
1116 
1117     QRect r = vr; r.moveBy(tl.x(),tl.y()); // move to untransformed co-ords
1118     if (!all.contains(ivr)) {
1119         QRegion inside = p->clipRegion() & r;
1120         //QRegion outside = p->clipRegion() - r;
1121         //p->setClipRegion(outside);
1122         //p->fillRect(outside.boundingRect(),red);
1123         qt_setclipregion(p, inside);
1124     } else {
1125         qt_setcliprect(p, r);
1126     }
1127 #ifndef QT_NO_TRANSFORMATIONS
1128     p->setWorldMatrix(wm*twm);
1129 #else
1130 #endif
1131     drawCanvasArea(ivr,p,false);
1132 }
1133 
1134 /*!
1135     Repaints changed areas in all views of the canvas.
1136 
1137     \sa advance()
1138 */
update()1139 void Q3Canvas::update()
1140 {
1141     // ##### fix QT_NO_TRANSFORMATIONS
1142 #ifndef QT_NO_TRANSFORMATIONS
1143     Q3PtrList<QRect> doneareas;
1144     doneareas.setAutoDelete(true);
1145 #endif
1146 
1147     Q3PtrListIterator<Q3CanvasView> it(d->viewList);
1148     Q3CanvasView* view;
1149     while((view=it.current()) != 0) {
1150 	++it;
1151 #ifndef QT_NO_TRANSFORMATIONS
1152 	QMatrix wm = view->worldMatrix();
1153 #endif
1154 	QRect area(view->contentsX(),view->contentsY(),
1155 		   view->visibleWidth(),view->visibleHeight());
1156 	if (area.width()>0 && area.height()>0) {
1157 #ifndef QT_NO_TRANSFORMATIONS
1158             // r = Visible area of the canvas where there are changes
1159             QRect r = changeBounds(view->inverseWorldMatrix().map(area));
1160             if (!r.isEmpty()) {
1161                 QRect tr = wm.map(r);
1162                 tr.moveBy(-view->contentsX(), -view->contentsY());
1163                 view->viewport()->update(tr);
1164                 doneareas.append(new QRect(r));
1165             }
1166 #endif
1167 	}
1168     }
1169 
1170 #ifndef QT_NO_TRANSFORMATIONS
1171     for (QRect* r=doneareas.first(); r != 0; r=doneareas.next())
1172 	setUnchanged(*r);
1173 #endif
1174 }
1175 
1176 
1177 /*!
1178     Marks the whole canvas as changed.
1179     All views of the canvas will be entirely redrawn when
1180     update() is called next.
1181 */
setAllChanged()1182 void Q3Canvas::setAllChanged()
1183 {
1184     setChanged(QRect(0,0,width(),height()));
1185 }
1186 
1187 /*!
1188     Marks \a area as changed. This \a area will be redrawn in all
1189     views that are showing it when update() is called next.
1190 */
setChanged(const QRect & area)1191 void Q3Canvas::setChanged(const QRect& area)
1192 {
1193     QRect thearea = area.intersected(QRect(0, 0, width(), height()));
1194 
1195     int mx = (thearea.x()+thearea.width()+chunksize)/chunksize;
1196     int my = (thearea.y()+thearea.height()+chunksize)/chunksize;
1197     if (mx>chwidth)
1198 	mx=chwidth;
1199     if (my>chheight)
1200 	my=chheight;
1201 
1202     int x=thearea.x()/chunksize;
1203     while(x<mx) {
1204 	int y = thearea.y()/chunksize;
1205 	while(y<my) {
1206 	    chunk(x,y).change();
1207 	    y++;
1208 	}
1209 	x++;
1210     }
1211 }
1212 
1213 /*!
1214     Marks \a area as \e unchanged. The area will \e not be redrawn in
1215     the views for the next update(), unless it is marked or changed
1216     again before the next call to update().
1217 */
setUnchanged(const QRect & area)1218 void Q3Canvas::setUnchanged(const QRect& area)
1219 {
1220     QRect thearea = area.intersected(QRect(0, 0, width(), height()));
1221 
1222     int mx = (thearea.x()+thearea.width()+chunksize)/chunksize;
1223     int my = (thearea.y()+thearea.height()+chunksize)/chunksize;
1224     if (mx>chwidth)
1225 	mx=chwidth;
1226     if (my>chheight)
1227 	my=chheight;
1228 
1229     int x=thearea.x()/chunksize;
1230     while(x<mx) {
1231 	int y = thearea.y()/chunksize;
1232 	while(y<my) {
1233 	    chunk(x,y).takeChange();
1234 	    y++;
1235 	}
1236 	x++;
1237     }
1238 }
1239 
1240 
1241 /*!
1242   \internal
1243 */
changeBounds(const QRect & inarea)1244 QRect Q3Canvas::changeBounds(const QRect& inarea)
1245 {
1246     QRect area = inarea.intersected(QRect(0, 0, width(), height()));
1247 
1248     int mx = (area.x()+area.width()+chunksize)/chunksize;
1249     int my = (area.y()+area.height()+chunksize)/chunksize;
1250     if (mx > chwidth)
1251 	mx=chwidth;
1252     if (my > chheight)
1253 	my=chheight;
1254 
1255     QRect result;
1256 
1257     int x=area.x()/chunksize;
1258     while(x<mx) {
1259 	int y=area.y()/chunksize;
1260 	while(y<my) {
1261 	    Q3CanvasChunk& ch=chunk(x,y);
1262 	    if (ch.hasChanged())
1263 		result |= QRect(x,y,1,1);
1264 	    y++;
1265 	}
1266 	x++;
1267     }
1268 
1269     if (!result.isEmpty()) {
1270 	result.rLeft() *= chunksize;
1271 	result.rTop() *= chunksize;
1272 	result.rRight() *= chunksize;
1273 	result.rBottom() *= chunksize;
1274 	result.rRight() += chunksize;
1275 	result.rBottom() += chunksize;
1276     }
1277 
1278     return result;
1279 }
1280 
ensureOffScrSize(int osw,int osh)1281 void Q3Canvas::ensureOffScrSize(int osw, int osh)
1282 {
1283     if (osw > offscr.width() || osh > offscr.height())
1284 	offscr.resize(QMAX(osw,offscr.width()),
1285 		      QMAX(osh,offscr.height()));
1286     else if (offscr.width() == 0 || offscr.height() == 0)
1287 	offscr.resize(QMAX(offscr.width(), 1),
1288 		       QMAX(offscr.height(), 1));
1289 }
1290 
1291 /*!
1292     Paints all canvas items that are in the area \a clip to \a
1293     painter, using double-buffering if \a dbuf is true.
1294 
1295     e.g. to print the canvas to a printer:
1296     \snippet doc/src/snippets/code/src_qt3support_canvas_q3canvas.cpp 0
1297 */
drawArea(const QRect & clip,QPainter * painter,bool dbuf)1298 void Q3Canvas::drawArea(const QRect& clip, QPainter* painter, bool dbuf)
1299 {
1300     if (painter)
1301 	drawCanvasArea(clip, painter, dbuf);
1302 }
1303 
1304 QT_BEGIN_INCLUDE_NAMESPACE
1305 #include <qdebug.h>
1306 QT_END_INCLUDE_NAMESPACE
1307 
1308 /*!
1309   \internal
1310 */
drawCanvasArea(const QRect & inarea,QPainter * p,bool)1311 void Q3Canvas::drawCanvasArea(const QRect& inarea, QPainter* p, bool /*double_buffer*/)
1312 {
1313     QRect area=inarea.intersected(QRect(0,0,width(),height()));
1314 
1315     if (!p) return; // Nothing to do.
1316 
1317     int lx=area.x()/chunksize;
1318     int ly=area.y()/chunksize;
1319     int mx=area.right()/chunksize;
1320     int my=area.bottom()/chunksize;
1321     if (mx>=chwidth)
1322 	mx=chwidth-1;
1323     if (my>=chheight)
1324 	my=chheight-1;
1325 
1326     Q3CanvasItemList allvisible;
1327 
1328     // Stores the region within area that need to be drawn. It is relative
1329     // to area.topLeft()  (so as to keep within bounds of 16-bit XRegions)
1330     QRegion rgn;
1331 
1332     for (int x=lx; x<=mx; x++) {
1333 	for (int y=ly; y<=my; y++) {
1334 	    // Only reset change if all views updating, and
1335 	    // wholy within area. (conservative:  ignore entire boundary)
1336 	    //
1337 	    // Disable this to help debugging.
1338 	    //
1339 	    if (!p) {
1340 		if (chunk(x,y).takeChange()) {
1341 		    // ### should at least make bands
1342 		    rgn |= QRegion(x*chunksize-area.x(),y*chunksize-area.y(),
1343                                    chunksize,chunksize);
1344 		    allvisible += *chunk(x,y).listPtr();
1345 		}
1346 	    } else {
1347 		allvisible += *chunk(x,y).listPtr();
1348 	    }
1349 	}
1350     }
1351     allvisible.sort();
1352 
1353     drawBackground(*p,area);
1354     allvisible.drawUnique(*p);
1355     drawForeground(*p,area);
1356 }
1357 
1358 /*!
1359 \internal
1360 This method to informs the Q3Canvas that a given chunk is
1361 `dirty' and needs to be redrawn in the next Update.
1362 
1363 (\a x,\a y) is a chunk location.
1364 
1365 The sprite classes call this. Any new derived class of Q3CanvasItem
1366 must do so too. SetChangedChunkContaining can be used instead.
1367 */
setChangedChunk(int x,int y)1368 void Q3Canvas::setChangedChunk(int x, int y)
1369 {
1370     if (validChunk(x,y)) {
1371 	Q3CanvasChunk& ch=chunk(x,y);
1372 	ch.change();
1373     }
1374 }
1375 
1376 /*!
1377 \internal
1378 This method to informs the Q3Canvas that the chunk containing a given
1379 pixel is `dirty' and needs to be redrawn in the next Update.
1380 
1381 (\a x,\a y) is a pixel location.
1382 
1383 The item classes call this. Any new derived class of Q3CanvasItem must
1384 do so too. SetChangedChunk can be used instead.
1385 */
setChangedChunkContaining(int x,int y)1386 void Q3Canvas::setChangedChunkContaining(int x, int y)
1387 {
1388     if (x>=0 && x<width() && y>=0 && y<height()) {
1389 	Q3CanvasChunk& chunk=chunkContaining(x,y);
1390 	chunk.change();
1391     }
1392 }
1393 
1394 /*!
1395 \internal
1396 This method adds the Q3CanvasItem \a g to the list of those which need to be
1397 drawn if the given chunk at location (\a x, \a y) is redrawn. Like
1398 SetChangedChunk and SetChangedChunkContaining, this method marks the
1399 chunk as `dirty'.
1400 */
addItemToChunk(Q3CanvasItem * g,int x,int y)1401 void Q3Canvas::addItemToChunk(Q3CanvasItem* g, int x, int y)
1402 {
1403     if (validChunk(x,y)) {
1404 	chunk(x,y).add(g);
1405     }
1406 }
1407 
1408 /*!
1409 \internal
1410 This method removes the Q3CanvasItem \a g from the list of those which need to
1411 be drawn if the given chunk at location (\a x, \a y) is redrawn. Like
1412 SetChangedChunk and SetChangedChunkContaining, this method marks the chunk
1413 as `dirty'.
1414 */
removeItemFromChunk(Q3CanvasItem * g,int x,int y)1415 void Q3Canvas::removeItemFromChunk(Q3CanvasItem* g, int x, int y)
1416 {
1417     if (validChunk(x,y)) {
1418 	chunk(x,y).remove(g);
1419     }
1420 }
1421 
1422 
1423 /*!
1424 \internal
1425 This method adds the Q3CanvasItem \a g to the list of those which need to be
1426 drawn if the chunk containing the given pixel (\a x, \a y) is redrawn. Like
1427 SetChangedChunk and SetChangedChunkContaining, this method marks the
1428 chunk as `dirty'.
1429 */
addItemToChunkContaining(Q3CanvasItem * g,int x,int y)1430 void Q3Canvas::addItemToChunkContaining(Q3CanvasItem* g, int x, int y)
1431 {
1432     if (x>=0 && x<width() && y>=0 && y<height()) {
1433 	chunkContaining(x,y).add(g);
1434     }
1435 }
1436 
1437 /*!
1438 \internal
1439 This method removes the Q3CanvasItem \a g from the list of those which need to
1440 be drawn if the chunk containing the given pixel (\a x, \a y) is redrawn.
1441 Like SetChangedChunk and SetChangedChunkContaining, this method
1442 marks the chunk as `dirty'.
1443 */
removeItemFromChunkContaining(Q3CanvasItem * g,int x,int y)1444 void Q3Canvas::removeItemFromChunkContaining(Q3CanvasItem* g, int x, int y)
1445 {
1446     if (x>=0 && x<width() && y>=0 && y<height()) {
1447 	chunkContaining(x,y).remove(g);
1448     }
1449 }
1450 
1451 /*!
1452     Returns the color set by setBackgroundColor(). By default, this is
1453     white.
1454 
1455     This function is not a reimplementation of
1456     QWidget::backgroundColor() (Q3Canvas is not a subclass of QWidget),
1457     but all Q3CanvasViews that are viewing the canvas will set their
1458     backgrounds to this color.
1459 
1460     \sa setBackgroundColor(), backgroundPixmap()
1461 */
backgroundColor() const1462 QColor Q3Canvas::backgroundColor() const
1463 {
1464     return bgcolor;
1465 }
1466 
1467 /*!
1468     Sets the solid background to be the color \a c.
1469 
1470     \sa backgroundColor(), setBackgroundPixmap(), setTiles()
1471 */
setBackgroundColor(const QColor & c)1472 void Q3Canvas::setBackgroundColor(const QColor& c)
1473 {
1474     if (bgcolor != c) {
1475 	bgcolor = c;
1476 	Q3CanvasView* view=d->viewList.first();
1477 	while (view != 0) {
1478 	    /* XXX this doesn't look right. Shouldn't this
1479 	       be more like setBackgroundPixmap? : Ian */
1480 	    view->viewport()->setEraseColor(bgcolor);
1481 	    view=d->viewList.next();
1482 	}
1483 	setAllChanged();
1484     }
1485 }
1486 
1487 /*!
1488     Returns the pixmap set by setBackgroundPixmap(). By default,
1489     this is a null pixmap.
1490 
1491     \sa setBackgroundPixmap(), backgroundColor()
1492 */
backgroundPixmap() const1493 QPixmap Q3Canvas::backgroundPixmap() const
1494 {
1495     return pm;
1496 }
1497 
1498 /*!
1499     Sets the solid background to be the pixmap \a p repeated as
1500     necessary to cover the entire canvas.
1501 
1502     \sa backgroundPixmap(), setBackgroundColor(), setTiles()
1503 */
setBackgroundPixmap(const QPixmap & p)1504 void Q3Canvas::setBackgroundPixmap(const QPixmap& p)
1505 {
1506     setTiles(p, 1, 1, p.width(), p.height());
1507     Q3CanvasView* view = d->viewList.first();
1508     while (view != 0) {
1509 	view->updateContents();
1510 	view = d->viewList.next();
1511     }
1512 }
1513 
1514 /*!
1515     This virtual function is called for all updates of the canvas. It
1516     renders any background graphics using the painter \a painter, in
1517     the area \a clip. If the canvas has a background pixmap or a tiled
1518     background, that graphic is used, otherwise the canvas is cleared
1519     using the background color.
1520 
1521     If the graphics for an area change, you must explicitly call
1522     setChanged(const QRect&) for the result to be visible when
1523     update() is next called.
1524 
1525     \sa setBackgroundColor(), setBackgroundPixmap(), setTiles()
1526 */
drawBackground(QPainter & painter,const QRect & clip)1527 void Q3Canvas::drawBackground(QPainter& painter, const QRect& clip)
1528 {
1529     if (pm.isNull()) {
1530 	painter.fillRect(clip,bgcolor);
1531     } else if (!grid) {
1532 	for (int x=clip.x()/pm.width();
1533 	    x<(clip.x()+clip.width()+pm.width()-1)/pm.width(); x++)
1534 	{
1535 	    for (int y=clip.y()/pm.height();
1536 		y<(clip.y()+clip.height()+pm.height()-1)/pm.height(); y++)
1537 	    {
1538 		painter.drawPixmap(x*pm.width(), y*pm.height(),pm);
1539 	    }
1540 	}
1541     } else {
1542 	const int x1 = clip.left()/tilew;
1543 	int x2 = clip.right()/tilew;
1544 	const int y1 = clip.top()/tileh;
1545 	int y2 = clip.bottom()/tileh;
1546 
1547 	const int roww = pm.width()/tilew;
1548 
1549 	for (int j=y1; j<=y2; j++) {
1550 	    int jj = j%tilesVertically();
1551 	    for (int i=x1; i<=x2; i++) {
1552 		int t = tile(i%tilesHorizontally(), jj);
1553 		int tx = t % roww;
1554 		int ty = t / roww;
1555 		painter.drawPixmap(i*tilew, j*tileh, pm,
1556 				tx*tilew, ty*tileh, tilew, tileh);
1557 	    }
1558 	}
1559     }
1560 }
1561 
1562 /*!
1563     This virtual function is called for all updates of the canvas. It
1564     renders any foreground graphics using the painter \a painter, in
1565     the area \a clip.
1566 
1567     If the graphics for an area change, you must explicitly call
1568     setChanged(const QRect&) for the result to be visible when
1569     update() is next called.
1570 
1571     The default is to draw nothing.
1572 */
drawForeground(QPainter & painter,const QRect & clip)1573 void Q3Canvas::drawForeground(QPainter& painter, const QRect& clip)
1574 {
1575     if (debug_redraw_areas) {
1576 	painter.setPen(red);
1577 	painter.setBrush(NoBrush);
1578 	painter.drawRect(clip);
1579     }
1580 }
1581 
1582 /*!
1583     If \a y is true (the default) double-buffering is switched on;
1584     otherwise double-buffering is switched off.
1585 
1586     Turning off double-buffering causes the redrawn areas to flicker a
1587     little and also gives a (usually small) performance improvement.
1588 */
setDoubleBuffering(bool y)1589 void Q3Canvas::setDoubleBuffering(bool y)
1590 {
1591     dblbuf = y;
1592 }
1593 
1594 
1595 /*!
1596     Sets the Q3Canvas to be composed of \a h tiles horizontally and \a
1597     v tiles vertically. Each tile will be an image \a tilewidth by \a
1598     tileheight pixels from pixmap \a p.
1599 
1600     The pixmap \a p is a list of tiles, arranged left to right, (and
1601     in the case of pixmaps that have multiple rows of tiles, top to
1602     bottom), with tile 0 in the top-left corner, tile 1 next to the
1603     right, and so on, e.g.
1604 
1605     \table
1606     \row \i 0 \i 1 \i 2 \i 3
1607     \row \i 4 \i 5 \i 6 \i 7
1608     \endtable
1609 
1610     If the canvas is larger than the matrix of tiles, the entire
1611     matrix is repeated as necessary to cover the whole canvas. If it
1612     is smaller, tiles to the right and bottom are not visible.
1613 
1614     The width and height of \a p must be a multiple of \a tilewidth
1615     and \a tileheight. If they are not the function will do nothing.
1616 
1617     If you want to unset any tiling set, then just pass in a null
1618     pixmap and 0 for \a h, \a v, \a tilewidth, and
1619     \a tileheight.
1620 */
setTiles(QPixmap p,int h,int v,int tilewidth,int tileheight)1621 void Q3Canvas::setTiles(QPixmap p,
1622 			int h, int v, int tilewidth, int tileheight)
1623 {
1624     if (!p.isNull() && (!tilewidth || !tileheight ||
1625 	 p.width() % tilewidth != 0 || p.height() % tileheight != 0))
1626     	return;
1627 
1628     htiles = h;
1629     vtiles = v;
1630     delete[] grid;
1631     pm = p;
1632     if (h && v && !p.isNull()) {
1633 	grid = new ushort[h*v];
1634 	memset(grid, 0, h*v*sizeof(ushort));
1635 	tilew = tilewidth;
1636 	tileh = tileheight;
1637     } else {
1638 	grid = 0;
1639     }
1640     if (h + v > 10) {
1641 	int s = scm(tilewidth,tileheight);
1642 	retune(s < 128 ? s : QMAX(tilewidth,tileheight));
1643     }
1644     setAllChanged();
1645 }
1646 
1647 /*!
1648     \fn int Q3Canvas::tile(int x, int y) const
1649 
1650     Returns the tile at position (\a x, \a y). Initially, all tiles
1651     are 0.
1652 
1653     The parameters must be within range, i.e.
1654 	0 \< \a x \< tilesHorizontally() and
1655 	0 \< \a y \< tilesVertically().
1656 
1657     \sa setTile()
1658 */
1659 
1660 /*!
1661     \fn int Q3Canvas::tilesHorizontally() const
1662 
1663     Returns the number of tiles horizontally.
1664 */
1665 
1666 /*!
1667     \fn int Q3Canvas::tilesVertically() const
1668 
1669     Returns the number of tiles vertically.
1670 */
1671 
1672 /*!
1673     \fn int Q3Canvas::tileWidth() const
1674 
1675     Returns the width of each tile.
1676 */
1677 
1678 /*!
1679     \fn int Q3Canvas::tileHeight() const
1680 
1681     Returns the height of each tile.
1682 */
1683 
1684 
1685 /*!
1686     Sets the tile at (\a x, \a y) to use tile number \a tilenum, which
1687     is an index into the tile pixmaps. The canvas will update
1688     appropriately when update() is next called.
1689 
1690     The images are taken from the pixmap set by setTiles() and are
1691     arranged left to right, (and in the case of pixmaps that have
1692     multiple rows of tiles, top to bottom), with tile 0 in the
1693     top-left corner, tile 1 next to the right, and so on, e.g.
1694 
1695     \table
1696     \row \i 0 \i 1 \i 2 \i 3
1697     \row \i 4 \i 5 \i 6 \i 7
1698     \endtable
1699 
1700     \sa tile() setTiles()
1701 */
setTile(int x,int y,int tilenum)1702 void Q3Canvas::setTile(int x, int y, int tilenum)
1703 {
1704     ushort& t = grid[x+y*htiles];
1705     if (t != tilenum) {
1706 	t = tilenum;
1707 	if (tilew == tileh && tilew == chunksize)
1708 	    setChangedChunk(x, y);	    // common case
1709 	else
1710 	    setChanged(QRect(x*tilew,y*tileh,tilew,tileh));
1711     }
1712 }
1713 
1714 
1715 // lesser-used data in canvas item, plus room for extension.
1716 // Be careful adding to this - check all usages.
1717 class Q3CanvasItemExtra {
Q3CanvasItemExtra()1718     Q3CanvasItemExtra() : vx(0.0), vy(0.0) { }
1719     double vx,vy;
1720     friend class Q3CanvasItem;
1721 };
1722 
1723 
1724 /*!
1725     \class Q3CanvasItem
1726     \compat
1727     \brief The Q3CanvasItem class provides an abstract graphic object on a Q3Canvas.
1728 
1729     A variety of Q3CanvasItem subclasses provide immediately usable
1730     behaviour. This class is a pure abstract superclass providing the
1731     behaviour that is shared among all the concrete canvas item classes.
1732     Q3CanvasItem is not intended for direct subclassing. It is much easier
1733     to subclass one of its subclasses, e.g. Q3CanvasPolygonalItem (the
1734     commonest base class), Q3CanvasRectangle, Q3CanvasSprite, Q3CanvasEllipse
1735     or Q3CanvasText.
1736 
1737     Canvas items are added to a canvas by constructing them and passing the
1738     canvas to the canvas item's constructor. An item can be moved to a
1739     different canvas using setCanvas().
1740 
1741     Items appear on the canvas after their \link show() show()\endlink
1742     function has been called (or \link setVisible()
1743     setVisible(true)\endlink), and \e after update() has been called. The
1744     canvas only shows items that are \link setVisible() visible\endlink,
1745     and then only if \l update() is called. If you created the canvas
1746     without passing a width and height to the constructor you'll also need
1747     to call \link Q3Canvas::resize() resize()\endlink. Since the canvas
1748     background defaults to white and canvas items default to white,
1749     you may need to change colors to see your items.
1750 
1751     A Q3CanvasItem object can be moved in the x(), y() and z() dimensions
1752     using functions such as move(), moveBy(), setX(), setY() and setZ(). A
1753     canvas item can be set in motion, `animated', using setAnimated() and
1754     given a velocity in the x and y directions with setXVelocity() and
1755     setYVelocity() -- the same effect can be achieved by calling
1756     setVelocity(). Use the collidesWith() function to see if the canvas item
1757     will collide on the \e next advance(1) and use collisions() to see what
1758     collisions have occurred.
1759 
1760     Use Q3CanvasSprite or your own subclass of Q3CanvasSprite to create canvas
1761     items which are animated, i.e. which change over time.
1762 
1763     The size of a canvas item is given by boundingRect(). Use
1764     boundingRectAdvanced() to see what the size of the canvas item will be
1765     \e after the next advance(1) call.
1766 
1767     The rtti() function is used for identifying subclasses of Q3CanvasItem.
1768     The canvas() function returns a pointer to the canvas which contains the
1769     canvas item.
1770 
1771     Q3CanvasItem provides the show() and isVisible() functions like those in
1772     QWidget.
1773 
1774     Q3CanvasItem also provides the setEnabled(), setActive() and
1775     setSelected() functions; these functions set the relevant boolean and
1776     cause a repaint but the boolean values they set are not used in
1777     Q3CanvasItem itself. You can make use of these booleans in your subclasses.
1778 
1779     By default, canvas items have no velocity, no size, and are not in
1780     motion. The subclasses provided in Qt do not change these defaults
1781     except where noted.
1782 
1783     \sa QtCanvas, {Porting to Graphics View}
1784 */
1785 
1786 /*!
1787     \enum Q3CanvasItem::RttiValues
1788 
1789     This enum is used to name the different types of canvas item.
1790 
1791     \value Rtti_Item Canvas item abstract base class
1792     \value Rtti_Ellipse
1793     \value Rtti_Line
1794     \value Rtti_Polygon
1795     \value Rtti_PolygonalItem
1796     \value Rtti_Rectangle
1797     \value Rtti_Spline
1798     \value Rtti_Sprite
1799     \value Rtti_Text
1800 
1801 */
1802 
1803 /*!
1804     \fn void Q3CanvasItem::update()
1805 
1806     Call this function to repaint the canvas's changed chunks.
1807 */
1808 
1809 /*!
1810     Constructs a Q3CanvasItem on canvas \a canvas.
1811 
1812     \sa setCanvas()
1813 */
Q3CanvasItem(Q3Canvas * canvas)1814 Q3CanvasItem::Q3CanvasItem(Q3Canvas* canvas) :
1815     cnv(canvas),
1816     myx(0),myy(0),myz(0)
1817 {
1818     ani=0;
1819     vis=0;
1820     val=0;
1821     sel=0;
1822     ena=0;
1823     act=0;
1824 
1825     ext = 0;
1826     if (cnv) cnv->addItem(this);
1827 }
1828 
1829 /*!
1830     Destroys the Q3CanvasItem and removes it from its canvas.
1831 */
~Q3CanvasItem()1832 Q3CanvasItem::~Q3CanvasItem()
1833 {
1834     if (cnv) {
1835 	cnv->removeItem(this);
1836 	cnv->removeAnimation(this);
1837     }
1838     delete ext;
1839 }
1840 
extra()1841 Q3CanvasItemExtra& Q3CanvasItem::extra()
1842 {
1843     if (!ext)
1844 	ext = new Q3CanvasItemExtra;
1845     return *ext;
1846 }
1847 
1848 /*!
1849     \fn double Q3CanvasItem::x() const
1850 
1851     Returns the horizontal position of the canvas item. Note that
1852     subclasses often have an origin other than the top-left corner.
1853 */
1854 
1855 /*!
1856     \fn double Q3CanvasItem::y() const
1857 
1858     Returns the vertical position of the canvas item. Note that
1859     subclasses often have an origin other than the top-left corner.
1860 */
1861 
1862 /*!
1863     \fn double Q3CanvasItem::z() const
1864 
1865     Returns the z index of the canvas item, which is used for visual
1866     order: higher-z items obscure (are in front of) lower-z items.
1867 */
1868 
1869 /*!
1870     \fn void Q3CanvasItem::setX(double x)
1871 
1872     Moves the canvas item so that its x-position is \a x.
1873 
1874     \sa x(), move()
1875 */
1876 
1877 /*!
1878     \fn void Q3CanvasItem::setY(double y)
1879 
1880     Moves the canvas item so that its y-position is \a y.
1881 
1882     \sa y(), move()
1883 */
1884 
1885 /*!
1886     \fn void Q3CanvasItem::setZ(double z)
1887 
1888     Sets the z index of the canvas item to \a z. Higher-z items
1889     obscure (are in front of) lower-z items.
1890 
1891     \sa z(), move()
1892 */
1893 
1894 
1895 /*!
1896     Moves the canvas item relative to its current position by (\a dx,
1897     \a dy).
1898 */
moveBy(double dx,double dy)1899 void Q3CanvasItem::moveBy(double dx, double dy)
1900 {
1901     if (dx || dy) {
1902 	removeFromChunks();
1903 	myx += dx;
1904 	myy += dy;
1905 	addToChunks();
1906     }
1907 }
1908 
1909 
1910 /*!
1911     Moves the canvas item to the absolute position (\a x, \a y).
1912 */
move(double x,double y)1913 void Q3CanvasItem::move(double x, double y)
1914 {
1915     moveBy(x-myx, y-myy);
1916 }
1917 
1918 
1919 /*!
1920     Returns true if the canvas item is in motion; otherwise returns
1921     false.
1922 
1923     \sa setVelocity(), setAnimated()
1924 */
animated() const1925 bool Q3CanvasItem::animated() const
1926 {
1927     return (bool)ani;
1928 }
1929 
1930 /*!
1931     Sets the canvas item to be in motion if \a y is true, or not if \a
1932     y is false. The speed and direction of the motion is set with
1933     setVelocity(), or with setXVelocity() and setYVelocity().
1934 
1935     \sa advance(), Q3Canvas::advance()
1936 */
setAnimated(bool y)1937 void Q3CanvasItem::setAnimated(bool y)
1938 {
1939     if (y != (bool)ani) {
1940 	ani = (uint)y;
1941 	if (y) {
1942 	    cnv->addAnimation(this);
1943 	} else {
1944 	    cnv->removeAnimation(this);
1945 	}
1946     }
1947 }
1948 
1949 /*!
1950     \fn void Q3CanvasItem::setXVelocity(double vx)
1951 
1952     Sets the horizontal component of the canvas item's velocity to \a vx.
1953 
1954     \sa setYVelocity() setVelocity()
1955 */
1956 
1957 /*!
1958     \fn void Q3CanvasItem::setYVelocity(double vy)
1959 
1960     Sets the vertical component of the canvas item's velocity to \a vy.
1961 
1962     \sa setXVelocity() setVelocity()
1963 */
1964 
1965 /*!
1966     Sets the canvas item to be in motion, moving by \a vx and \a vy
1967     pixels in the horizontal and vertical directions respectively.
1968 
1969     \sa advance() setXVelocity() setYVelocity()
1970 */
setVelocity(double vx,double vy)1971 void Q3CanvasItem::setVelocity(double vx, double vy)
1972 {
1973     if (ext || vx!=0.0 || vy!=0.0) {
1974 	if (!ani)
1975 	    setAnimated(true);
1976 	extra().vx = vx;
1977 	extra().vy = vy;
1978     }
1979 }
1980 
1981 /*!
1982     Returns the horizontal velocity component of the canvas item.
1983 */
xVelocity() const1984 double Q3CanvasItem::xVelocity() const
1985 {
1986     return ext ? ext->vx : 0;
1987 }
1988 
1989 /*!
1990     Returns the vertical velocity component of the canvas item.
1991 */
yVelocity() const1992 double Q3CanvasItem::yVelocity() const
1993 {
1994     return ext ? ext->vy : 0;
1995 }
1996 
1997 /*!
1998     The default implementation moves the canvas item, if it is
1999     animated(), by the preset velocity if \a phase is 1, and does
2000     nothing if \a phase is 0.
2001 
2002     Note that if you reimplement this function, the reimplementation
2003     must not change the canvas in any way, for example it must not add
2004     or remove items.
2005 
2006     \sa Q3Canvas::advance() setVelocity()
2007 */
advance(int phase)2008 void Q3CanvasItem::advance(int phase)
2009 {
2010     if (ext && phase==1)
2011 	moveBy(ext->vx,ext->vy);
2012 }
2013 
2014 /*!
2015     \fn void Q3CanvasItem::draw(QPainter& painter)
2016 
2017     This abstract virtual function draws the canvas item using \a painter.
2018 */
2019 
2020 /*!
2021     Sets the Q3Canvas upon which the canvas item is to be drawn to \a c.
2022 
2023     \sa canvas()
2024 */
setCanvas(Q3Canvas * c)2025 void Q3CanvasItem::setCanvas(Q3Canvas* c)
2026 {
2027     bool v=isVisible();
2028     setVisible(false);
2029     if (cnv) {
2030 	if (ext)
2031 	    cnv->removeAnimation(this);
2032 	cnv->removeItem(this);
2033     }
2034     cnv=c;
2035     if (cnv) {
2036 	cnv->addItem(this);
2037 	if (ext)
2038 	    cnv->addAnimation(this);
2039     }
2040     setVisible(v);
2041 }
2042 
2043 /*!
2044     \fn Q3Canvas* Q3CanvasItem::canvas() const
2045 
2046     Returns the canvas containing the canvas item.
2047 */
2048 
2049 /*! Shorthand for setVisible(true). */
show()2050 void Q3CanvasItem::show()
2051 {
2052     setVisible(true);
2053 }
2054 
2055 /*! Shorthand for setVisible(false). */
hide()2056 void Q3CanvasItem::hide()
2057 {
2058     setVisible(false);
2059 }
2060 
2061 /*!
2062     Makes the canvas item visible if \a yes is true, or invisible if
2063     \a yes is false. The change takes effect when Q3Canvas::update() is
2064     next called.
2065 */
setVisible(bool yes)2066 void Q3CanvasItem::setVisible(bool yes)
2067 {
2068     if ((bool)vis!=yes) {
2069 	if (yes) {
2070 	    vis=(uint)yes;
2071 	    addToChunks();
2072 	} else {
2073 	    removeFromChunks();
2074 	    vis=(uint)yes;
2075 	}
2076     }
2077 }
2078 /*!
2079     \obsolete
2080     \fn bool Q3CanvasItem::visible() const
2081     Use isVisible() instead.
2082 */
2083 
2084 /*!
2085     \fn bool Q3CanvasItem::isVisible() const
2086 
2087     Returns true if the canvas item is visible; otherwise returns
2088     false.
2089 
2090     Note that in this context true does \e not mean that the canvas
2091     item is currently in a view, merely that if a view is showing the
2092     area where the canvas item is positioned, and the item is not
2093     obscured by items with higher z values, and the view is not
2094     obscured by overlaying windows, it would be visible.
2095 
2096     \sa setVisible(), z()
2097 */
2098 
2099 /*!
2100     \obsolete
2101     \fn bool Q3CanvasItem::selected() const
2102     Use isSelected() instead.
2103 */
2104 
2105 /*!
2106     \fn bool Q3CanvasItem::isSelected() const
2107 
2108     Returns true if the canvas item is selected; otherwise returns false.
2109 */
2110 
2111 /*!
2112     Sets the selected flag of the item to \a yes. If this changes the
2113     item's selected state the item will be redrawn when
2114     Q3Canvas::update() is next called.
2115 
2116     The Q3Canvas, Q3CanvasItem and the Qt-supplied Q3CanvasItem
2117     subclasses do not make use of this value. The setSelected()
2118     function is supplied because many applications need it, but it is
2119     up to you how you use the isSelected() value.
2120 */
setSelected(bool yes)2121 void Q3CanvasItem::setSelected(bool yes)
2122 {
2123     if ((bool)sel!=yes) {
2124 	sel=(uint)yes;
2125 	changeChunks();
2126     }
2127 }
2128 
2129 /*!
2130     \obsolete
2131     \fn bool Q3CanvasItem::enabled() const
2132     Use isEnabled() instead.
2133 */
2134 
2135 /*!
2136     \fn bool Q3CanvasItem::isEnabled() const
2137 
2138     Returns true if the Q3CanvasItem is enabled; otherwise returns false.
2139 */
2140 
2141 /*!
2142     Sets the enabled flag of the item to \a yes. If this changes the
2143     item's enabled state the item will be redrawn when
2144     Q3Canvas::update() is next called.
2145 
2146     The Q3Canvas, Q3CanvasItem and the Qt-supplied Q3CanvasItem
2147     subclasses do not make use of this value. The setEnabled()
2148     function is supplied because many applications need it, but it is
2149     up to you how you use the isEnabled() value.
2150 */
setEnabled(bool yes)2151 void Q3CanvasItem::setEnabled(bool yes)
2152 {
2153     if (ena!=(uint)yes) {
2154 	ena=(uint)yes;
2155 	changeChunks();
2156     }
2157 }
2158 
2159 /*!
2160     \obsolete
2161     \fn bool Q3CanvasItem::active() const
2162     Use isActive() instead.
2163 */
2164 
2165 /*!
2166     \fn bool Q3CanvasItem::isActive() const
2167 
2168     Returns true if the Q3CanvasItem is active; otherwise returns false.
2169 */
2170 
2171 /*!
2172     Sets the active flag of the item to \a yes. If this changes the
2173     item's active state the item will be redrawn when
2174     Q3Canvas::update() is next called.
2175 
2176     The Q3Canvas, Q3CanvasItem and the Qt-supplied Q3CanvasItem
2177     subclasses do not make use of this value. The setActive() function
2178     is supplied because many applications need it, but it is up to you
2179     how you use the isActive() value.
2180 */
setActive(bool yes)2181 void Q3CanvasItem::setActive(bool yes)
2182 {
2183     if (act!=(uint)yes) {
2184 	act=(uint)yes;
2185 	changeChunks();
2186     }
2187 }
2188 
qt_testCollision(const Q3CanvasSprite * s1,const Q3CanvasSprite * s2)2189 bool qt_testCollision(const Q3CanvasSprite* s1, const Q3CanvasSprite* s2)
2190 {
2191     const QImage* s2image = s2->imageAdvanced()->collision_mask;
2192     QRect s2area = s2->boundingRectAdvanced();
2193 
2194     QRect cyourarea(s2area.x(),s2area.y(),
2195 	    s2area.width(),s2area.height());
2196 
2197     QImage* s1image=s1->imageAdvanced()->collision_mask;
2198 
2199     QRect s1area = s1->boundingRectAdvanced();
2200 
2201     QRect ourarea = s1area.intersected(cyourarea);
2202 
2203     if (ourarea.isEmpty())
2204 	return false;
2205 
2206     int x2=ourarea.x()-cyourarea.x();
2207     int y2=ourarea.y()-cyourarea.y();
2208     int x1=ourarea.x()-s1area.x();
2209     int y1=ourarea.y()-s1area.y();
2210     int w=ourarea.width();
2211     int h=ourarea.height();
2212 
2213     if (!s2image) {
2214 	if (!s1image)
2215 	    return w>0 && h>0;
2216 	// swap everything around
2217 	int t;
2218 	t=x1; x1=x2; x2=t;
2219 	t=y1; x1=y2; y2=t;
2220 	s2image = s1image;
2221 	s1image = 0;
2222     }
2223 
2224     // s2image != 0
2225 
2226     // A non-linear search may be more efficient.
2227     // Perhaps spiralling out from the center, or a simpler
2228     // vertical expansion from the centreline.
2229 
2230     // We assume that sprite masks don't have
2231     // different bit orders.
2232     //
2233     // Q_ASSERT(s1image->bitOrder()==s2image->bitOrder());
2234 
2235     if (s1image) {
2236 	if (s1image->bitOrder() == QImage::LittleEndian) {
2237 	    for (int j=0; j<h; j++) {
2238 		uchar* ml = s1image->scanLine(y1+j);
2239 		const uchar* yl = s2image->scanLine(y2+j);
2240 		for (int i=0; i<w; i++) {
2241 		    if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7))
2242 		    && *(ml + ((x1+i) >> 3)) & (1 << ((x1+i) & 7)))
2243 		    {
2244 			return true;
2245 		    }
2246 		}
2247 	    }
2248 	} else {
2249 	    for (int j=0; j<h; j++) {
2250 		uchar* ml = s1image->scanLine(y1+j);
2251 		const uchar* yl = s2image->scanLine(y2+j);
2252 		for (int i=0; i<w; i++) {
2253 		    if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7)))
2254 		    && *(ml + ((x1+i) >> 3)) & (1 << (7-((x1+i) & 7))))
2255 		    {
2256 			return true;
2257 		    }
2258 		}
2259 	    }
2260 	}
2261     } else {
2262 	if (s2image->bitOrder() == QImage::LittleEndian) {
2263 	    for (int j=0; j<h; j++) {
2264 		const uchar* yl = s2image->scanLine(y2+j);
2265 		for (int i=0; i<w; i++) {
2266 		    if (*(yl + ((x2+i) >> 3)) & (1 << ((x2+i) & 7)))
2267 		    {
2268 			return true;
2269 		    }
2270 		}
2271 	    }
2272 	} else {
2273 	    for (int j=0; j<h; j++) {
2274 		const uchar* yl = s2image->scanLine(y2+j);
2275 		for (int i=0; i<w; i++) {
2276 		    if (*(yl + ((x2+i) >> 3)) & (1 << (7-((x2+i) & 7))))
2277 		    {
2278 			return true;
2279 		    }
2280 		}
2281 	    }
2282 	}
2283     }
2284 
2285     return false;
2286 }
2287 
collision_double_dispatch(const Q3CanvasSprite * s1,const Q3CanvasPolygonalItem * p1,const Q3CanvasRectangle * r1,const Q3CanvasEllipse * e1,const Q3CanvasText * t1,const Q3CanvasSprite * s2,const Q3CanvasPolygonalItem * p2,const Q3CanvasRectangle * r2,const Q3CanvasEllipse * e2,const Q3CanvasText * t2)2288 static bool collision_double_dispatch(const Q3CanvasSprite* s1,
2289 				       const Q3CanvasPolygonalItem* p1,
2290 				       const Q3CanvasRectangle* r1,
2291 				       const Q3CanvasEllipse* e1,
2292 				       const Q3CanvasText* t1,
2293 				       const Q3CanvasSprite* s2,
2294 				       const Q3CanvasPolygonalItem* p2,
2295 				       const Q3CanvasRectangle* r2,
2296 				       const Q3CanvasEllipse* e2,
2297 				       const Q3CanvasText* t2)
2298 {
2299     const Q3CanvasItem* i1 = s1 ?
2300 			    (const Q3CanvasItem*)s1 : p1 ?
2301 			    (const Q3CanvasItem*)p1 : r1 ?
2302 			    (const Q3CanvasItem*)r1 : e1 ?
2303 			    (const Q3CanvasItem*)e1 : (const Q3CanvasItem*)t1;
2304     const Q3CanvasItem* i2 = s2 ?
2305 			    (const Q3CanvasItem*)s2 : p2 ?
2306 			    (const Q3CanvasItem*)p2 : r2 ?
2307 			    (const Q3CanvasItem*)r2 : e2 ?
2308 			    (const Q3CanvasItem*)e2 : (const Q3CanvasItem*)t2;
2309 
2310     if (s1 && s2) {
2311 	// a
2312 	return qt_testCollision(s1,s2);
2313     } else if ((r1 || t1 || s1) && (r2 || t2 || s2)) {
2314 	// b
2315 	QRect rc1 = i1->boundingRectAdvanced();
2316 	QRect rc2 = i2->boundingRectAdvanced();
2317 	return rc1.intersects(rc2);
2318     } else if (e1 && e2
2319 		&& e1->angleLength()>=360*16 && e2->angleLength()>=360*16
2320 		&& e1->width()==e1->height()
2321 		&& e2->width()==e2->height()) {
2322 	// c
2323 	double xd = (e1->x()+e1->xVelocity())-(e2->x()+e1->xVelocity());
2324 	double yd = (e1->y()+e1->yVelocity())-(e2->y()+e1->yVelocity());
2325 	double rd = (e1->width()+e2->width())/2;
2326 	return xd*xd+yd*yd <= rd*rd;
2327     } else if (p1 && (p2 || s2 || t2)) {
2328 	// d
2329 	Q3PointArray pa1 = p1->areaPointsAdvanced();
2330 	Q3PointArray pa2 = p2 ? p2->areaPointsAdvanced()
2331 			  : Q3PointArray(i2->boundingRectAdvanced());
2332 	bool col= !(QRegion(pa1) & QRegion(pa2,true)).isEmpty();
2333 
2334 	return col;
2335     } else {
2336 	return collision_double_dispatch(s2,p2,r2,e2,t2,
2337 					 s1,p1,r1,e1,t1);
2338     }
2339 }
2340 
2341 /*!
2342     \fn bool Q3CanvasItem::collidesWith(const Q3CanvasItem* other) const
2343 
2344     Returns true if the canvas item will collide with the \a other
2345     item \e after they have moved by their current velocities;
2346     otherwise returns false.
2347 
2348     \sa collisions()
2349 */
2350 
2351 
2352 /*!
2353     \class Q3CanvasSprite
2354     \compat
2355     \brief The Q3CanvasSprite class provides an animated canvas item on a Q3Canvas.
2356 
2357     A canvas sprite is an object which can contain any number of images
2358     (referred to as frames), only one of which is current, i.e.
2359     displayed, at any one time. The images can be passed in the
2360     constructor or set or changed later with setSequence(). If you
2361     subclass Q3CanvasSprite you can change the frame that is displayed
2362     periodically, e.g. whenever Q3CanvasItem::advance(1) is called to
2363     create the effect of animation.
2364 
2365     The current frame can be set with setFrame() or with move(). The
2366     number of frames available is given by frameCount(). The bounding
2367     rectangle of the current frame is returned by boundingRect().
2368 
2369     The current frame's image can be retrieved with image(); use
2370     imageAdvanced() to retrieve the image for the frame that will be
2371     shown after advance(1) is called. Use the image() overload passing
2372     it an integer index to retrieve a particular image from the list of
2373     frames.
2374 
2375     Use width() and height() to retrieve the dimensions of the current
2376     frame.
2377 
2378     Use leftEdge() and rightEdge() to retrieve the current frame's
2379     left-hand and right-hand x-coordinates respectively. Use
2380     bottomEdge() and topEdge() to retrieve the current frame's bottom
2381     and top y-coordinates respectively. These functions have an overload
2382     which will accept an integer frame number to retrieve the
2383     coordinates of a particular frame.
2384 
2385     Q3CanvasSprite draws very quickly, at the expense of memory.
2386 
2387     The current frame's image can be drawn on a painter with draw().
2388 
2389     Like any other canvas item, canvas sprites can be moved with
2390     move() which sets the x and y coordinates and the frame number, as
2391     well as with Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by
2392     setting coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY()
2393     and Q3CanvasItem::setZ().
2394 
2395     \sa QtCanvas, {Porting to Graphics View}
2396 */
2397 
2398 
2399 /*!
2400   \reimp
2401 */
collidesWith(const Q3CanvasItem * i) const2402 bool Q3CanvasSprite::collidesWith(const Q3CanvasItem* i) const
2403 {
2404     return i->collidesWith(this,0,0,0,0);
2405 }
2406 
2407 /*!
2408     Returns true if the canvas item collides with any of the given
2409     items; otherwise returns false. The parameters, \a s, \a p, \a r,
2410     \a e and \a t, are all the same object, this is just a type
2411     resolution trick.
2412 */
collidesWith(const Q3CanvasSprite * s,const Q3CanvasPolygonalItem * p,const Q3CanvasRectangle * r,const Q3CanvasEllipse * e,const Q3CanvasText * t) const2413 bool Q3CanvasSprite::collidesWith(const Q3CanvasSprite* s,
2414 				  const Q3CanvasPolygonalItem* p,
2415 				  const Q3CanvasRectangle* r,
2416 				  const Q3CanvasEllipse* e,
2417 				  const Q3CanvasText* t) const
2418 {
2419     return collision_double_dispatch(s,p,r,e,t,this,0,0,0,0);
2420 }
2421 
2422 /*!
2423   \reimp
2424 */
collidesWith(const Q3CanvasItem * i) const2425 bool Q3CanvasPolygonalItem::collidesWith(const Q3CanvasItem* i) const
2426 {
2427     return i->collidesWith(0,this,0,0,0);
2428 }
2429 
collidesWith(const Q3CanvasSprite * s,const Q3CanvasPolygonalItem * p,const Q3CanvasRectangle * r,const Q3CanvasEllipse * e,const Q3CanvasText * t) const2430 bool Q3CanvasPolygonalItem::collidesWith( const Q3CanvasSprite* s,
2431 				 const Q3CanvasPolygonalItem* p,
2432 				 const Q3CanvasRectangle* r,
2433 				 const Q3CanvasEllipse* e,
2434 				 const Q3CanvasText* t) const
2435 {
2436     return collision_double_dispatch(s,p,r,e,t,0,this,0,0,0);
2437 }
2438 
2439 /*!
2440   \reimp
2441 */
collidesWith(const Q3CanvasItem * i) const2442 bool Q3CanvasRectangle::collidesWith(const Q3CanvasItem* i) const
2443 {
2444     return i->collidesWith(0,this,this,0,0);
2445 }
2446 
collidesWith(const Q3CanvasSprite * s,const Q3CanvasPolygonalItem * p,const Q3CanvasRectangle * r,const Q3CanvasEllipse * e,const Q3CanvasText * t) const2447 bool Q3CanvasRectangle::collidesWith( const Q3CanvasSprite* s,
2448 				 const Q3CanvasPolygonalItem* p,
2449 				 const Q3CanvasRectangle* r,
2450 				 const Q3CanvasEllipse* e,
2451 				 const Q3CanvasText* t) const
2452 {
2453     return collision_double_dispatch(s,p,r,e,t,0,this,this,0,0);
2454 }
2455 
2456 
2457 /*!
2458   \reimp
2459 */
collidesWith(const Q3CanvasItem * i) const2460 bool Q3CanvasEllipse::collidesWith(const Q3CanvasItem* i) const
2461 {
2462     return i->collidesWith(0,this,0,this,0);
2463 }
2464 
collidesWith(const Q3CanvasSprite * s,const Q3CanvasPolygonalItem * p,const Q3CanvasRectangle * r,const Q3CanvasEllipse * e,const Q3CanvasText * t) const2465 bool Q3CanvasEllipse::collidesWith( const Q3CanvasSprite* s,
2466 				 const Q3CanvasPolygonalItem* p,
2467 				 const Q3CanvasRectangle* r,
2468 				 const Q3CanvasEllipse* e,
2469 				 const Q3CanvasText* t) const
2470 {
2471     return collision_double_dispatch(s,p,r,e,t,0,this,0,this,0);
2472 }
2473 
2474 /*!
2475   \reimp
2476 */
collidesWith(const Q3CanvasItem * i) const2477 bool Q3CanvasText::collidesWith(const Q3CanvasItem* i) const
2478 {
2479     return i->collidesWith(0,0,0,0,this);
2480 }
2481 
collidesWith(const Q3CanvasSprite * s,const Q3CanvasPolygonalItem * p,const Q3CanvasRectangle * r,const Q3CanvasEllipse * e,const Q3CanvasText * t) const2482 bool Q3CanvasText::collidesWith( const Q3CanvasSprite* s,
2483 				 const Q3CanvasPolygonalItem* p,
2484 				 const Q3CanvasRectangle* r,
2485 				 const Q3CanvasEllipse* e,
2486 				 const Q3CanvasText* t) const
2487 {
2488     return collision_double_dispatch(s,p,r,e,t,0,0,0,0,this);
2489 }
2490 
2491 /*!
2492     Returns the list of canvas items that this canvas item has
2493     collided with.
2494 
2495     A collision is generally defined as occurring when the pixels of
2496     one item draw on the pixels of another item, but not all
2497     subclasses are so precise. Also, since pixel-wise collision
2498     detection can be slow, this function works in either exact or
2499     inexact mode, according to the \a exact parameter.
2500 
2501     If \a exact is true, the canvas items returned have been
2502     accurately tested for collision with the canvas item.
2503 
2504     If \a exact is false, the canvas items returned are \e near the
2505     canvas item. You can test the canvas items returned using
2506     collidesWith() if any are interesting collision candidates. By
2507     using this approach, you can ignore some canvas items for which
2508     collisions are not relevant.
2509 
2510     The returned list is a list of Q3CanvasItems, but often you will
2511     need to cast the items to their subclass types. The safe way to do
2512     this is to use rtti() before casting. This provides some of the
2513     functionality of the standard C++ dynamic cast operation even on
2514     compilers where dynamic casts are not available.
2515 
2516     Note that a canvas item may be `on' a canvas, e.g. it was created
2517     with the canvas as parameter, even though its coordinates place it
2518     beyond the edge of the canvas's area. Collision detection only
2519     works for canvas items which are wholly or partly within the
2520     canvas's area.
2521 
2522     Note that if items have a velocity (see \l setVelocity()), then
2523     collision testing is done based on where the item \e will be when
2524     it moves, not its current location. For example, a "ball" item
2525     doesn't need to actually embed into a "wall" item before a
2526     collision is detected. For items without velocity, plain
2527     intersection is used.
2528 */
collisions(bool exact) const2529 Q3CanvasItemList Q3CanvasItem::collisions(bool exact) const
2530 {
2531     return canvas()->collisions(chunks(),this,exact);
2532 }
2533 
2534 /*!
2535     Returns a list of canvas items that collide with the point \a p.
2536     The list is ordered by z coordinates, from highest z coordinate
2537     (front-most item) to lowest z coordinate (rear-most item).
2538 */
collisions(const QPoint & p) const2539 Q3CanvasItemList Q3Canvas::collisions(const QPoint& p) const
2540 {
2541     return collisions(QRect(p,QSize(1,1)));
2542 }
2543 
2544 /*!
2545     \overload
2546 
2547     Returns a list of items which collide with the rectangle \a r. The
2548     list is ordered by z coordinates, from highest z coordinate
2549     (front-most item) to lowest z coordinate (rear-most item).
2550 */
collisions(const QRect & r) const2551 Q3CanvasItemList Q3Canvas::collisions(const QRect& r) const
2552 {
2553     Q3CanvasRectangle i(r,(Q3Canvas*)this);
2554     i.setPen(NoPen);
2555     i.show(); // doesn't actually show, since we destroy it
2556     Q3CanvasItemList l = i.collisions(true);
2557     l.sort();
2558     return l;
2559 }
2560 
2561 /*!
2562     \overload
2563 
2564     Returns a list of canvas items which intersect with the chunks
2565     listed in \a chunklist, excluding \a item. If \a exact is true,
2566     only those which actually \link Q3CanvasItem::collidesWith()
2567     collide with\endlink \a item are returned; otherwise canvas items
2568     are included just for being in the chunks.
2569 
2570     This is a utility function mainly used to implement the simpler
2571     Q3CanvasItem::collisions() function.
2572 */
collisions(const Q3PointArray & chunklist,const Q3CanvasItem * item,bool exact) const2573 Q3CanvasItemList Q3Canvas::collisions(const Q3PointArray& chunklist,
2574 	    const Q3CanvasItem* item, bool exact) const
2575 {
2576     Q3PtrDict<void> seen;
2577     Q3CanvasItemList result;
2578     for (int i=0; i<(int)chunklist.count(); i++) {
2579 	int x = chunklist[i].x();
2580 	int y = chunklist[i].y();
2581 	if (validChunk(x,y)) {
2582 	    const Q3CanvasItemList* l = chunk(x,y).listPtr();
2583 	    for (Q3CanvasItemList::ConstIterator it=l->begin(); it!=l->end(); ++it) {
2584 		Q3CanvasItem *g=*it;
2585 		if (g != item) {
2586 		    if (!seen.find(g)) {
2587 			seen.replace(g,(void*)1);
2588 			if (!exact || item->collidesWith(g))
2589 			    result.append(g);
2590 		    }
2591 		}
2592 	    }
2593 	}
2594     }
2595     return result;
2596 }
2597 
2598 /*!
2599   \internal
2600   Adds the item to all the chunks it covers.
2601 */
addToChunks()2602 void Q3CanvasItem::addToChunks()
2603 {
2604     if (isVisible() && canvas()) {
2605 	Q3PointArray pa = chunks();
2606 	for (int i=0; i<(int)pa.count(); i++)
2607 	    canvas()->addItemToChunk(this,pa[i].x(),pa[i].y());
2608 	val=(uint)true;
2609     }
2610 }
2611 
2612 /*!
2613   \internal
2614   Removes the item from all the chunks it covers.
2615 */
removeFromChunks()2616 void Q3CanvasItem::removeFromChunks()
2617 {
2618     if (isVisible() && canvas()) {
2619 	Q3PointArray pa = chunks();
2620 	for (int i=0; i<(int)pa.count(); i++)
2621 	    canvas()->removeItemFromChunk(this,pa[i].x(),pa[i].y());
2622     }
2623 }
2624 
2625 /*!
2626   \internal
2627   Sets all the chunks covered by the item to be refreshed with Q3Canvas::update()
2628   is next called.
2629 */
changeChunks()2630 void Q3CanvasItem::changeChunks()
2631 {
2632     if (isVisible() && canvas()) {
2633 	if (!val)
2634 	    addToChunks();
2635 	Q3PointArray pa = chunks();
2636 	for (int i=0; i<(int)pa.count(); i++)
2637 	    canvas()->setChangedChunk(pa[i].x(),pa[i].y());
2638     }
2639 }
2640 
2641 /*!
2642     \fn QRect Q3CanvasItem::boundingRect() const
2643 
2644     Returns the bounding rectangle in pixels that the canvas item covers.
2645 
2646     \sa boundingRectAdvanced()
2647 */
2648 
2649 /*!
2650     Returns the bounding rectangle of pixels that the canvas item \e
2651     will cover after advance(1) is called.
2652 
2653     \sa boundingRect()
2654 */
boundingRectAdvanced() const2655 QRect Q3CanvasItem::boundingRectAdvanced() const
2656 {
2657     int dx = int(x()+xVelocity())-int(x());
2658     int dy = int(y()+yVelocity())-int(y());
2659     QRect r = boundingRect();
2660     r.moveBy(dx,dy);
2661     return r;
2662 }
2663 
2664 /*!
2665     \class Q3CanvasPixmap
2666     \compat
2667     \brief The Q3CanvasPixmap class provides pixmaps for Q3CanvasSprites.
2668 
2669     If you want to show a single pixmap on a Q3Canvas use a
2670     Q3CanvasSprite with just one pixmap.
2671 
2672     When pixmaps are inserted into a Q3CanvasPixmapArray they are held
2673     as Q3CanvasPixmaps. \l{Q3CanvasSprite}s are used to show pixmaps on
2674     \l{Q3Canvas}es and hold their pixmaps in a Q3CanvasPixmapArray. If
2675     you retrieve a frame (pixmap) from a Q3CanvasSprite it will be
2676     returned as a Q3CanvasPixmap.
2677 
2678     The pixmap is a QPixmap and can only be set in the constructor.
2679     There are three different constructors, one taking a QPixmap, one
2680     a QImage and one a file name that refers to a file in any
2681     supported file format (see QImageReader).
2682 
2683     Q3CanvasPixmap can have a hotspot which is defined in terms of an (x,
2684     y) offset. When you create a Q3CanvasPixmap from a PNG file or from
2685     a QImage that has a QImage::offset(), the offset() is initialized
2686     appropriately, otherwise the constructor leaves it at (0, 0). You
2687     can set it later using setOffset(). When the Q3CanvasPixmap is used
2688     in a Q3CanvasSprite, the offset position is the point at
2689     Q3CanvasItem::x() and Q3CanvasItem::y(), not the top-left corner of
2690     the pixmap.
2691 
2692     Note that for Q3CanvasPixmap objects created by a Q3CanvasSprite, the
2693     position of each Q3CanvasPixmap object is set so that the hotspot
2694     stays in the same position.
2695 
2696     \sa Q3CanvasPixmapArray Q3CanvasItem Q3CanvasSprite, QtCanvas, {Porting to Graphics View}
2697 */
2698 
2699 #ifndef QT_NO_IMAGEIO
2700 
2701 /*!
2702     Constructs a Q3CanvasPixmap that uses the image stored in \a
2703     datafilename.
2704 */
Q3CanvasPixmap(const QString & datafilename)2705 Q3CanvasPixmap::Q3CanvasPixmap(const QString& datafilename)
2706 {
2707     QImage image(datafilename);
2708     init(image);
2709 }
2710 
2711 #endif
2712 
2713 /*!
2714     Constructs a Q3CanvasPixmap from the image \a image.
2715 */
Q3CanvasPixmap(const QImage & image)2716 Q3CanvasPixmap::Q3CanvasPixmap(const QImage& image)
2717 {
2718     init(image);
2719 }
2720 /*!
2721     Constructs a Q3CanvasPixmap from the pixmap \a pm using the offset
2722     \a offset.
2723 */
Q3CanvasPixmap(const QPixmap & pm,const QPoint & offset)2724 Q3CanvasPixmap::Q3CanvasPixmap(const QPixmap& pm, const QPoint& offset)
2725 {
2726     init(pm,offset.x(),offset.y());
2727 }
2728 
init(const QImage & image)2729 void Q3CanvasPixmap::init(const QImage& image)
2730 {
2731     convertFromImage(image);
2732     hotx = image.offset().x();
2733     hoty = image.offset().y();
2734 #ifndef QT_NO_IMAGE_DITHER_TO_1
2735     if(image.hasAlphaBuffer()) {
2736 	QImage i = image.createAlphaMask();
2737 	collision_mask = new QImage(i);
2738     } else
2739 #endif
2740 	collision_mask = 0;
2741 }
2742 
init(const QPixmap & pixmap,int hx,int hy)2743 void Q3CanvasPixmap::init(const QPixmap& pixmap, int hx, int hy)
2744 {
2745     (QPixmap&)*this = pixmap;
2746     hotx = hx;
2747     hoty = hy;
2748     if(pixmap.hasAlphaChannel())  {
2749 	QImage i = mask().convertToImage();
2750 	collision_mask = new QImage(i);
2751     } else
2752 	collision_mask = 0;
2753 }
2754 
2755 /*!
2756     Destroys the pixmap.
2757 */
~Q3CanvasPixmap()2758 Q3CanvasPixmap::~Q3CanvasPixmap()
2759 {
2760     delete collision_mask;
2761 }
2762 
2763 /*!
2764     \fn int Q3CanvasPixmap::offsetX() const
2765 
2766     Returns the x-offset of the pixmap's hotspot.
2767 
2768     \sa setOffset()
2769 */
2770 
2771 /*!
2772     \fn int Q3CanvasPixmap::offsetY() const
2773 
2774     Returns the y-offset of the pixmap's hotspot.
2775 
2776     \sa setOffset()
2777 */
2778 
2779 /*!
2780     \fn void Q3CanvasPixmap::setOffset(int x, int y)
2781 
2782     Sets the offset of the pixmap's hotspot to (\a x, \a y).
2783 
2784     \warning Do not call this function if any Q3CanvasSprites are
2785     currently showing this pixmap.
2786 */
2787 
2788 /*!
2789     \class Q3CanvasPixmapArray
2790     \compat
2791     \brief The Q3CanvasPixmapArray class provides an array of Q3CanvasPixmaps.
2792 
2793     This class is used by Q3CanvasSprite to hold an array of pixmaps.
2794     It is used to implement animated sprites, i.e. images that change
2795     over time, with each pixmap in the array holding one frame.
2796 
2797     Depending on the constructor you use you can load multiple pixmaps
2798     into the array either from a directory (specifying a wildcard
2799     pattern for the files), or from a list of QPixmaps. You can also
2800     read in a set of pixmaps after construction using readPixmaps().
2801 
2802     Individual pixmaps can be set with setImage() and retrieved with
2803     image(). The number of pixmaps in the array is returned by
2804     count().
2805 
2806     Q3CanvasSprite uses an image's mask for collision detection. You
2807     can change this by reading in a separate set of image masks using
2808     readCollisionMasks().
2809 
2810     \sa QtCanvas, {Porting to Graphics View}
2811 */
2812 
2813 /*!
2814     Constructs an invalid array (i.e. isValid() will return false).
2815     You must call readPixmaps() before being able to use this
2816     Q3CanvasPixmapArray.
2817 */
Q3CanvasPixmapArray()2818 Q3CanvasPixmapArray::Q3CanvasPixmapArray()
2819 : framecount(0), img(0)
2820 {
2821 }
2822 
2823 #ifndef QT_NO_IMAGEIO
2824 /*!
2825     Constructs a Q3CanvasPixmapArray from files.
2826 
2827     The \a fc parameter sets the number of frames to be loaded for
2828     this image.
2829 
2830     If \a fc is not 0, \a datafilenamepattern should contain "%1",
2831     e.g. "foo%1.png". The actual filenames are formed by replacing the
2832     %1 with four-digit integers from 0 to (fc - 1), e.g. foo0000.png,
2833     foo0001.png, foo0002.png, etc.
2834 
2835     If \a fc is 0, \a datafilenamepattern is asssumed to be a
2836     filename, and the image contained in this file will be loaded as
2837     the first (and only) frame.
2838 
2839     If \a datafilenamepattern does not exist, is not readable, isn't
2840     an image, or some other error occurs, the array ends up empty and
2841     isValid() returns false.
2842 */
2843 
Q3CanvasPixmapArray(const QString & datafilenamepattern,int fc)2844 Q3CanvasPixmapArray::Q3CanvasPixmapArray(const QString& datafilenamepattern,
2845 					int fc)
2846 : framecount(0), img(0)
2847 {
2848     readPixmaps(datafilenamepattern,fc);
2849 }
2850 #endif
2851 
2852 /*!
2853   \obsolete
2854   Use Q3CanvasPixmapArray::Q3CanvasPixmapArray(Q3ValueList<QPixmap>, Q3PointArray)
2855   instead.
2856 
2857   Constructs a Q3CanvasPixmapArray from the list of QPixmaps \a
2858   list. The \a hotspots list has to be of the same size as \a list.
2859 */
Q3CanvasPixmapArray(Q3PtrList<QPixmap> list,Q3PtrList<QPoint> hotspots)2860 Q3CanvasPixmapArray::Q3CanvasPixmapArray(Q3PtrList<QPixmap> list, Q3PtrList<QPoint> hotspots) :
2861     framecount(list.count()),
2862     img(new Q3CanvasPixmap*[list.count()])
2863 {
2864     if (list.count() != hotspots.count()) {
2865 	qWarning("Q3CanvasPixmapArray: lists have different lengths");
2866 	reset();
2867 	img = 0;
2868     } else {
2869 	list.first();
2870 	hotspots.first();
2871 	for (int i=0; i<framecount; i++) {
2872 	    img[i]=new Q3CanvasPixmap(*list.current(), *hotspots.current());
2873 	    list.next();
2874 	    hotspots.next();
2875 	}
2876     }
2877 }
2878 
2879 /*!
2880     Constructs a Q3CanvasPixmapArray from the list of QPixmaps in the
2881     \a list. Each pixmap will get a hotspot according to the \a
2882     hotspots array. If no hotspots are specified, each one is set to
2883     be at position (0, 0).
2884 
2885     If an error occurs, isValid() will return false.
2886 */
Q3CanvasPixmapArray(Q3ValueList<QPixmap> list,Q3PointArray hotspots)2887 Q3CanvasPixmapArray::Q3CanvasPixmapArray(Q3ValueList<QPixmap> list, Q3PointArray hotspots) :
2888     framecount((int)list.size()),
2889     img(new Q3CanvasPixmap*[list.size()])
2890 {
2891     bool have_hotspots = (hotspots.size() != 0);
2892     if (have_hotspots && list.count() != hotspots.count()) {
2893 	qWarning("Q3CanvasPixmapArray: lists have different lengths");
2894 	reset();
2895 	img = 0;
2896     } else {
2897 	Q3ValueList<QPixmap>::iterator it;
2898 	it = list.begin();
2899 	for (int i=0; i<framecount; i++) {
2900 	    QPoint hs = have_hotspots ? hotspots[i] : QPoint(0, 0);
2901 	    img[i]=new Q3CanvasPixmap(*it, hs);
2902 	    ++it;
2903 	}
2904     }
2905 }
2906 
2907 /*!
2908     Destroys the pixmap array and all the pixmaps it contains.
2909 */
~Q3CanvasPixmapArray()2910 Q3CanvasPixmapArray::~Q3CanvasPixmapArray()
2911 {
2912     reset();
2913 }
2914 
reset()2915 void Q3CanvasPixmapArray::reset()
2916 {
2917     for (int i=0; i<framecount; i++)
2918 	delete img[i];
2919     delete [] img;
2920     img = 0;
2921     framecount = 0;
2922 }
2923 
2924 #ifndef QT_NO_IMAGEIO
2925 /*!
2926     Reads one or more pixmaps into the pixmap array.
2927 
2928     If \a fc is not 0, \a filenamepattern should contain "%1", e.g.
2929     "foo%1.png". The actual filenames are formed by replacing the %1
2930     with four-digit integers from 0 to (fc - 1), e.g. foo0000.png,
2931     foo0001.png, foo0002.png, etc.
2932 
2933     If \a fc is 0, \a filenamepattern is asssumed to be a filename,
2934     and the image contained in this file will be loaded as the first
2935     (and only) frame.
2936 
2937     If \a filenamepattern does not exist, is not readable, isn't an
2938     image, or some other error occurs, this function will return
2939     false, and isValid() will return false; otherwise this function
2940     will return true.
2941 
2942     \sa isValid()
2943 */
readPixmaps(const QString & filenamepattern,int fc)2944 bool Q3CanvasPixmapArray::readPixmaps(const QString& filenamepattern,
2945 				      int fc)
2946 {
2947     return readPixmaps(filenamepattern,fc,false);
2948 }
2949 
2950 /*!
2951     Reads new collision masks for the array.
2952 
2953     By default, Q3CanvasSprite uses the image mask of a sprite to
2954     detect collisions. Use this function to set your own collision
2955     image masks.
2956 
2957     If count() is 1 \a filename must specify a real filename to read
2958     the mask from. If count() is greater than 1, the \a filename must
2959     contain a "%1" that will get replaced by the number of the mask to
2960     be loaded, just like Q3CanvasPixmapArray::readPixmaps().
2961 
2962     All collision masks must be 1-bit images or this function call
2963     will fail.
2964 
2965     If the file isn't readable, contains the wrong number of images,
2966     or there is some other error, this function will return false, and
2967     the array will be flagged as invalid; otherwise this function
2968     returns true.
2969 
2970     \sa isValid()
2971 */
readCollisionMasks(const QString & filename)2972 bool Q3CanvasPixmapArray::readCollisionMasks(const QString& filename)
2973 {
2974     return readPixmaps(filename,framecount,true);
2975 }
2976 
2977 
readPixmaps(const QString & datafilenamepattern,int fc,bool maskonly)2978 bool Q3CanvasPixmapArray::readPixmaps(const QString& datafilenamepattern,
2979 				      int fc, bool maskonly)
2980 {
2981     if (!maskonly) {
2982 	reset();
2983 	framecount = fc;
2984 	if (!framecount)
2985 	    framecount=1;
2986 	img = new Q3CanvasPixmap*[framecount];
2987     }
2988     if (!img)
2989         return false;
2990 
2991     bool ok = true;
2992     bool arg = fc > 1;
2993     if (!arg)
2994 	framecount=1;
2995     for (int i=0; i<framecount; i++) {
2996 	QString r;
2997 	r.sprintf("%04d",i);
2998 	if (maskonly) {
2999             if (!img[i]->collision_mask)
3000                 img[i]->collision_mask = new QImage();
3001 	    img[i]->collision_mask->load(
3002 		arg ? datafilenamepattern.arg(r) : datafilenamepattern);
3003 	    ok = ok
3004 	       && !img[i]->collision_mask->isNull()
3005 	       && img[i]->collision_mask->depth()==1;
3006 	} else {
3007 	    img[i]=new Q3CanvasPixmap(
3008 		arg ? datafilenamepattern.arg(r) : datafilenamepattern);
3009 	    ok = ok && !img[i]->isNull();
3010 	}
3011     }
3012     if (!ok) {
3013 	reset();
3014     }
3015     return ok;
3016 }
3017 #endif
3018 
3019 /*!
3020   \obsolete
3021 
3022   Use isValid() instead.
3023 
3024   This returns false if the array is valid, and true if it is not.
3025 */
operator !()3026 bool Q3CanvasPixmapArray::operator!()
3027 {
3028     return img==0;
3029 }
3030 
3031 /*!
3032     Returns true if the pixmap array is valid; otherwise returns
3033     false.
3034 */
isValid() const3035 bool Q3CanvasPixmapArray::isValid() const
3036 {
3037     return (img != 0);
3038 }
3039 
3040 /*!
3041     \fn Q3CanvasPixmap* Q3CanvasPixmapArray::image(int i) const
3042 
3043     Returns pixmap \a i in the array, if \a i is non-negative and less
3044     than than count(), and returns an unspecified value otherwise.
3045 */
3046 
3047 // ### wouldn't it be better to put empty Q3CanvasPixmaps in there instead of
3048 // initializing the additional elements in the array to 0? Lars
3049 /*!
3050     Replaces the pixmap at index \a i with pixmap \a p.
3051 
3052     The array takes ownership of \a p and will delete \a p when the
3053     array itself is deleted.
3054 
3055     If \a i is beyond the end of the array the array is extended to at
3056     least i+1 elements, with elements count() to i-1 being initialized
3057     to 0.
3058 */
setImage(int i,Q3CanvasPixmap * p)3059 void Q3CanvasPixmapArray::setImage(int i, Q3CanvasPixmap* p)
3060 {
3061     if (i >= framecount) {
3062 	Q3CanvasPixmap** newimg = new Q3CanvasPixmap*[i+1];
3063 	memcpy(newimg, img, sizeof(Q3CanvasPixmap *)*framecount);
3064 	memset(newimg + framecount, 0, sizeof(Q3CanvasPixmap *)*(i+1 - framecount));
3065 	framecount = i+1;
3066 	delete [] img;
3067 	img = newimg;
3068     }
3069     delete img[i]; img[i]=p;
3070 }
3071 
3072 /*!
3073     \fn uint Q3CanvasPixmapArray::count() const
3074 
3075     Returns the number of pixmaps in the array.
3076 */
3077 
3078 /*!
3079     Returns the x-coordinate of the current left edge of the sprite.
3080     (This may change as the sprite animates since different frames may
3081     have different left edges.)
3082 
3083     \sa rightEdge() bottomEdge() topEdge()
3084 */
leftEdge() const3085 int Q3CanvasSprite::leftEdge() const
3086 {
3087     return int(x()) - image()->hotx;
3088 }
3089 
3090 /*!
3091     \overload
3092 
3093     Returns what the x-coordinate of the left edge of the sprite would
3094     be if the sprite (actually its hotspot) were moved to x-position
3095     \a nx.
3096 
3097     \sa rightEdge() bottomEdge() topEdge()
3098 */
leftEdge(int nx) const3099 int Q3CanvasSprite::leftEdge(int nx) const
3100 {
3101     return nx - image()->hotx;
3102 }
3103 
3104 /*!
3105     Returns the y-coordinate of the top edge of the sprite. (This may
3106     change as the sprite animates since different frames may have
3107     different top edges.)
3108 
3109     \sa leftEdge() rightEdge() bottomEdge()
3110 */
topEdge() const3111 int Q3CanvasSprite::topEdge() const
3112 {
3113     return int(y()) - image()->hoty;
3114 }
3115 
3116 /*!
3117     \overload
3118 
3119     Returns what the y-coordinate of the top edge of the sprite would
3120     be if the sprite (actually its hotspot) were moved to y-position
3121     \a ny.
3122 
3123     \sa leftEdge() rightEdge() bottomEdge()
3124 */
topEdge(int ny) const3125 int Q3CanvasSprite::topEdge(int ny) const
3126 {
3127     return ny - image()->hoty;
3128 }
3129 
3130 /*!
3131     Returns the x-coordinate of the current right edge of the sprite.
3132     (This may change as the sprite animates since different frames may
3133     have different right edges.)
3134 
3135     \sa leftEdge() bottomEdge() topEdge()
3136 */
rightEdge() const3137 int Q3CanvasSprite::rightEdge() const
3138 {
3139     return leftEdge() + image()->width()-1;
3140 }
3141 
3142 /*!
3143     \overload
3144 
3145     Returns what the x-coordinate of the right edge of the sprite
3146     would be if the sprite (actually its hotspot) were moved to
3147     x-position \a nx.
3148 
3149     \sa leftEdge() bottomEdge() topEdge()
3150 */
rightEdge(int nx) const3151 int Q3CanvasSprite::rightEdge(int nx) const
3152 {
3153     return leftEdge(nx) + image()->width()-1;
3154 }
3155 
3156 /*!
3157     Returns the y-coordinate of the current bottom edge of the sprite.
3158     (This may change as the sprite animates since different frames may
3159     have different bottom edges.)
3160 
3161     \sa leftEdge() rightEdge() topEdge()
3162 */
bottomEdge() const3163 int Q3CanvasSprite::bottomEdge() const
3164 {
3165     return topEdge() + image()->height()-1;
3166 }
3167 
3168 /*!
3169     \overload
3170 
3171     Returns what the y-coordinate of the top edge of the sprite would
3172     be if the sprite (actually its hotspot) were moved to y-position
3173     \a ny.
3174 
3175     \sa leftEdge() rightEdge() topEdge()
3176 */
bottomEdge(int ny) const3177 int Q3CanvasSprite::bottomEdge(int ny) const
3178 {
3179     return topEdge(ny) + image()->height()-1;
3180 }
3181 
3182 /*!
3183     \fn Q3CanvasPixmap* Q3CanvasSprite::image() const
3184 
3185     Returns the current frame's image.
3186 
3187     \sa frame(), setFrame()
3188 */
3189 
3190 /*!
3191     \fn Q3CanvasPixmap* Q3CanvasSprite::image(int f) const
3192     \overload
3193 
3194     Returns the image for frame \a f. Does not do any bounds checking on \a f.
3195 */
3196 
3197 /*!
3198     Returns the image the sprite \e will have after advance(1) is
3199     called. By default this is the same as image().
3200 */
imageAdvanced() const3201 Q3CanvasPixmap* Q3CanvasSprite::imageAdvanced() const
3202 {
3203     return image();
3204 }
3205 
3206 /*!
3207     Returns the bounding rectangle for the image in the sprite's
3208     current frame. This assumes that the images are tightly cropped
3209     (i.e. do not have transparent pixels all along a side).
3210 */
boundingRect() const3211 QRect Q3CanvasSprite::boundingRect() const
3212 {
3213     return QRect(leftEdge(), topEdge(), width(), height());
3214 }
3215 
3216 
3217 /*!
3218   \internal
3219   Returns the chunks covered by the item.
3220 */
chunks() const3221 Q3PointArray Q3CanvasItem::chunks() const
3222 {
3223     Q3PointArray r;
3224     int n=0;
3225     QRect br = boundingRect();
3226     if (isVisible() && canvas()) {
3227 	int chunksize=canvas()->chunkSize();
3228 	br &= QRect(0,0,canvas()->width(),canvas()->height());
3229 	if (br.isValid()) {
3230 	    r.resize((br.width()/chunksize+2)*(br.height()/chunksize+2));
3231 	    for (int j=br.top()/chunksize; j<=br.bottom()/chunksize; j++) {
3232 		for (int i=br.left()/chunksize; i<=br.right()/chunksize; i++) {
3233 		    r[n++] = QPoint(i,j);
3234 		}
3235 	    }
3236 	}
3237     }
3238     r.resize(n);
3239     return r;
3240 }
3241 
3242 
3243 /*!
3244   \internal
3245   Add the sprite to the chunks in its Q3Canvas which it overlaps.
3246 */
addToChunks()3247 void Q3CanvasSprite::addToChunks()
3248 {
3249     if (isVisible() && canvas()) {
3250 	int chunksize=canvas()->chunkSize();
3251 	for (int j=topEdge()/chunksize; j<=bottomEdge()/chunksize; j++) {
3252 	    for (int i=leftEdge()/chunksize; i<=rightEdge()/chunksize; i++) {
3253 		canvas()->addItemToChunk(this,i,j);
3254 	    }
3255 	}
3256     }
3257 }
3258 
3259 /*!
3260   \internal
3261   Remove the sprite from the chunks in its Q3Canvas which it overlaps.
3262 
3263   \sa addToChunks()
3264 */
removeFromChunks()3265 void Q3CanvasSprite::removeFromChunks()
3266 {
3267     if (isVisible() && canvas()) {
3268 	int chunksize=canvas()->chunkSize();
3269 	for (int j=topEdge()/chunksize; j<=bottomEdge()/chunksize; j++) {
3270 	    for (int i=leftEdge()/chunksize; i<=rightEdge()/chunksize; i++) {
3271 		canvas()->removeItemFromChunk(this,i,j);
3272 	    }
3273 	}
3274     }
3275 }
3276 
3277 /*!
3278     The width of the sprite for the current frame's image.
3279 
3280     \sa frame()
3281 */
3282 //### mark: Why don't we have width(int) and height(int) to be
3283 //consistent with leftEdge() and leftEdge(int)?
width() const3284 int Q3CanvasSprite::width() const
3285 {
3286     return image()->width();
3287 }
3288 
3289 /*!
3290     The height of the sprite for the current frame's image.
3291 
3292     \sa frame()
3293 */
height() const3294 int Q3CanvasSprite::height() const
3295 {
3296     return image()->height();
3297 }
3298 
3299 
3300 /*!
3301     Draws the current frame's image at the sprite's current position
3302     on painter \a painter.
3303 */
draw(QPainter & painter)3304 void Q3CanvasSprite::draw(QPainter& painter)
3305 {
3306     painter.drawPixmap(leftEdge(),topEdge(),*image());
3307 }
3308 
3309 /*!
3310     \class Q3CanvasView
3311     \compat
3312     \brief The Q3CanvasView class provides an on-screen view of a Q3Canvas.
3313 
3314     A Q3CanvasView is widget which provides a view of a Q3Canvas.
3315 
3316     If you want users to be able to interact with a canvas view,
3317     subclass Q3CanvasView. You might then reimplement
3318     Q3ScrollView::contentsMousePressEvent(). For example:
3319 
3320     \snippet doc/src/snippets/code/src_qt3support_canvas_q3canvas.cpp 1
3321 
3322     The canvas view shows canvas canvas(); this can be changed using
3323     setCanvas().
3324 
3325     A transformation matrix can be used to transform the view of the
3326     canvas in various ways, for example, zooming in or out or rotating.
3327     For example:
3328 
3329     \snippet doc/src/snippets/code/src_qt3support_canvas_q3canvas.cpp 2
3330 
3331     Use setWorldMatrix() to set the canvas view's world matrix: you must
3332     ensure that the world matrix is invertible. The current world matrix
3333     is retrievable with worldMatrix(), and its inversion is retrievable
3334     with inverseWorldMatrix().
3335 
3336     Example:
3337 
3338     The following code finds the part of the canvas that is visible in
3339     this view, i.e. the bounding rectangle of the view in canvas coordinates.
3340 
3341     \snippet doc/src/snippets/code/src_qt3support_canvas_q3canvas.cpp 3
3342 
3343     \sa QMatrix QPainter::setWorldMatrix(), QtCanvas, {Porting to Graphics View}
3344 */
3345 
3346 /*!
3347     Constructs a Q3CanvasView with parent \a parent, and name \a name,
3348     using the widget flags \a f. The canvas view is not associated
3349     with a canvas, so you must to call setCanvas() to view a
3350     canvas.
3351 */
Q3CanvasView(QWidget * parent,const char * name,Qt::WindowFlags f)3352 Q3CanvasView::Q3CanvasView(QWidget* parent, const char* name, Qt::WindowFlags f)
3353     : Q3ScrollView(parent,name,f|WResizeNoErase|WStaticContents)
3354 {
3355     d = new Q3CanvasViewData;
3356     viewing = 0;
3357     setCanvas(0);
3358 }
3359 
3360 /*!
3361     \overload
3362 
3363     Constructs a Q3CanvasView which views canvas \a canvas, with parent
3364     \a parent, and name \a name, using the widget flags \a f.
3365 */
Q3CanvasView(Q3Canvas * canvas,QWidget * parent,const char * name,Qt::WindowFlags f)3366 Q3CanvasView::Q3CanvasView(Q3Canvas* canvas, QWidget* parent, const char* name, Qt::WindowFlags f)
3367     : Q3ScrollView(parent,name,f|WResizeNoErase|WStaticContents)
3368 {
3369     d = new Q3CanvasViewData;
3370     viewing = 0;
3371     setCanvas(canvas);
3372 }
3373 
3374 /*!
3375     Destroys the canvas view. The associated canvas is \e not deleted.
3376 */
~Q3CanvasView()3377 Q3CanvasView::~Q3CanvasView()
3378 {
3379     delete d;
3380     d = 0;
3381     setCanvas(0);
3382 }
3383 
3384 /*!
3385     \fn Q3Canvas* Q3CanvasView::canvas() const
3386 
3387     Returns a pointer to the canvas which the Q3CanvasView is currently
3388     showing.
3389 */
3390 
3391 
3392 /*!
3393     Sets the canvas that the Q3CanvasView is showing to the canvas \a
3394     canvas.
3395 */
setCanvas(Q3Canvas * canvas)3396 void Q3CanvasView::setCanvas(Q3Canvas* canvas)
3397 {
3398     if (viewing == canvas)
3399         return;
3400 
3401     if (viewing) {
3402 	disconnect(viewing);
3403 	viewing->removeView(this);
3404     }
3405     viewing=canvas;
3406     if (viewing) {
3407 	connect(viewing,SIGNAL(resized()), this, SLOT(updateContentsSize()));
3408 	viewing->addView(this);
3409 	viewing->setAllChanged();
3410     }
3411     if (d) // called by d'tor
3412         updateContentsSize();
3413     update();
3414 }
3415 
3416 #ifndef QT_NO_TRANSFORMATIONS
3417 /*!
3418     Returns a reference to the canvas view's current transformation matrix.
3419 
3420     \sa setWorldMatrix() inverseWorldMatrix()
3421 */
worldMatrix() const3422 const QMatrix &Q3CanvasView::worldMatrix() const
3423 {
3424     return d->xform;
3425 }
3426 
3427 /*!
3428     Returns a reference to the inverse of the canvas view's current
3429     transformation matrix.
3430 
3431     \sa setWorldMatrix() worldMatrix()
3432 */
inverseWorldMatrix() const3433 const QMatrix &Q3CanvasView::inverseWorldMatrix() const
3434 {
3435     return d->ixform;
3436 }
3437 
3438 /*!
3439     Sets the transformation matrix of the Q3CanvasView to \a wm. The
3440     matrix must be invertible (i.e. if you create a world matrix that
3441     zooms out by 2 times, then the inverse of this matrix is one that
3442     will zoom in by 2 times).
3443 
3444     When you use this, you should note that the performance of the
3445     Q3CanvasView will decrease considerably.
3446 
3447     Returns false if \a wm is not invertable; otherwise returns true.
3448 
3449     \sa worldMatrix() inverseWorldMatrix() QMatrix::isInvertible()
3450 */
setWorldMatrix(const QMatrix & wm)3451 bool Q3CanvasView::setWorldMatrix(const QMatrix & wm)
3452 {
3453     bool ok = wm.isInvertible();
3454     if (ok) {
3455 	d->xform = wm;
3456 	d->ixform = wm.invert();
3457 	updateContentsSize();
3458 	viewport()->update();
3459     }
3460     return ok;
3461 }
3462 #endif
3463 
updateContentsSize()3464 void Q3CanvasView::updateContentsSize()
3465 {
3466     if (viewing) {
3467 	QRect br;
3468 #ifndef QT_NO_TRANSFORMATIONS
3469 	br = d->xform.map(QRect(0,0,viewing->width(),viewing->height()));
3470 #else
3471 	br = QRect(0,0,viewing->width(),viewing->height());
3472 #endif
3473 
3474 	if (br.width() < contentsWidth()) {
3475 	    QRect r(contentsToViewport(QPoint(br.width(),0)),
3476 		    QSize(contentsWidth()-br.width(),contentsHeight()));
3477             d->eraseRegion = r;
3478 	}
3479 	if (br.height() < contentsHeight()) {
3480 	    QRect r(contentsToViewport(QPoint(0,br.height())),
3481 		    QSize(contentsWidth(),contentsHeight()-br.height()));
3482             d->eraseRegion |= r;
3483 	}
3484 
3485 	resizeContents(br.width(),br.height());
3486     } else {
3487         d->eraseRegion = rect();
3488 	resizeContents(1,1);
3489     }
3490 }
3491 
3492 /*!
3493     Repaints part of the Q3Canvas that the canvas view is showing
3494     starting at \a cx by \a cy, with a width of \a cw and a height of \a
3495     ch using the painter \a p.
3496 */
drawContents(QPainter * p,int cx,int cy,int cw,int ch)3497 void Q3CanvasView::drawContents(QPainter *p, int cx, int cy, int cw, int ch)
3498 {
3499     QRect r(cx,cy,cw,ch);
3500     if (!d->eraseRegion.isEmpty()) {
3501         const QVector<QRect> rects = d->eraseRegion.rects();
3502         for (int i = 0; i < rects.size(); ++i)
3503             p->eraseRect(rects.at(i));
3504 
3505         d->eraseRegion = QRegion();
3506     }
3507 
3508     if (viewing) {
3509         viewing->drawViewArea(this,p,r,false);
3510     } else {
3511 	p->eraseRect(r);
3512     }
3513 }
3514 
3515 /*!
3516   \reimp
3517   \internal
3518 
3519   (Implemented to get rid of a compiler warning.)
3520 */
drawContents(QPainter *)3521 void Q3CanvasView::drawContents(QPainter *)
3522 {
3523 }
3524 
3525 /*!
3526     Suggests a size sufficient to view the entire canvas.
3527 */
sizeHint() const3528 QSize Q3CanvasView::sizeHint() const
3529 {
3530     if (!canvas())
3531 	return Q3ScrollView::sizeHint();
3532     // should maybe take transformations into account
3533     return (canvas()->size() + 2 * QSize(frameWidth(), frameWidth()))
3534 	   .boundedTo(3 * QApplication::desktop()->size() / 4);
3535 }
3536 
3537 /*!
3538     \class Q3CanvasPolygonalItem
3539     \compat
3540     \brief The Q3CanvasPolygonalItem class provides a polygonal canvas item
3541     on a Q3Canvas.
3542 
3543     The mostly rectangular classes, such as Q3CanvasSprite and
3544     Q3CanvasText, use the object's bounding rectangle for movement,
3545     repainting and collision calculations. For most other items, the
3546     bounding rectangle can be far too large -- a diagonal line being
3547     the worst case, and there are many other cases which are also bad.
3548     Q3CanvasPolygonalItem provides polygon-based bounding rectangle
3549     handling, etc., which is much faster for non-rectangular items.
3550 
3551     Derived classes should try to define as small an area as possible
3552     to maximize efficiency, but the polygon must \e definitely be
3553     contained completely within the polygonal area. Calculating the
3554     exact requirements is usually difficult, but if you allow a small
3555     overestimate it can be easy and quick, while still getting almost
3556     all of Q3CanvasPolygonalItem's speed.
3557 
3558     Note that all subclasses \e must call hide() in their destructor
3559     since hide() needs to be able to access areaPoints().
3560 
3561     Normally, Q3CanvasPolygonalItem uses the odd-even algorithm for
3562     determining whether an object intersects this object. You can
3563     change this to the winding algorithm using setWinding().
3564 
3565     The bounding rectangle is available using boundingRect(). The
3566     points bounding the polygonal item are retrieved with
3567     areaPoints(). Use areaPointsAdvanced() to retrieve the bounding
3568     points the polygonal item \e will have after
3569     Q3CanvasItem::advance(1) has been called.
3570 
3571     If the shape of the polygonal item is about to change while the
3572     item is visible, call invalidate() before updating with a
3573     different result from \l areaPoints().
3574 
3575     By default, Q3CanvasPolygonalItem objects have a black pen and no
3576     brush (the default QPen and QBrush constructors). You can change
3577     this with setPen() and setBrush(), but note that some
3578     Q3CanvasPolygonalItem subclasses only use the brush, ignoring the
3579     pen setting.
3580 
3581     The polygonal item can be drawn on a painter with draw().
3582     Subclasses must reimplement drawShape() to draw themselves.
3583 
3584     Like any other canvas item polygonal items can be moved with
3585     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting coordinates
3586     with Q3CanvasItem::setX(), Q3CanvasItem::setY() and Q3CanvasItem::setZ().
3587 
3588     \sa QtCanvas, {Porting to Graphics View}
3589 */
3590 
3591 
3592 /*
3593   Since most polygonal items don't have a pen, the default is
3594   NoPen and a black brush.
3595 */
defaultPolygonPen()3596 static const QPen& defaultPolygonPen()
3597 {
3598     static QPen* dp=0;
3599     if (!dp)
3600 	dp = new QPen;
3601     return *dp;
3602 }
3603 
defaultPolygonBrush()3604 static const QBrush& defaultPolygonBrush()
3605 {
3606     static QBrush* db=0;
3607     if (!db)
3608 	db = new QBrush;
3609     return *db;
3610 }
3611 
3612 /*!
3613     Constructs a Q3CanvasPolygonalItem on the canvas \a canvas.
3614 */
Q3CanvasPolygonalItem(Q3Canvas * canvas)3615 Q3CanvasPolygonalItem::Q3CanvasPolygonalItem(Q3Canvas* canvas) :
3616     Q3CanvasItem(canvas),
3617     br(defaultPolygonBrush()),
3618     pn(defaultPolygonPen())
3619 {
3620     wind=0;
3621 }
3622 
3623 /*!
3624     Note that all subclasses \e must call hide() in their destructor
3625     since hide() needs to be able to access areaPoints().
3626 */
~Q3CanvasPolygonalItem()3627 Q3CanvasPolygonalItem::~Q3CanvasPolygonalItem()
3628 {
3629 }
3630 
3631 /*!
3632     Returns true if the polygonal item uses the winding algorithm to
3633     determine the "inside" of the polygon. Returns false if it uses
3634     the odd-even algorithm.
3635 
3636     The default is to use the odd-even algorithm.
3637 
3638     \sa setWinding()
3639 */
winding() const3640 bool Q3CanvasPolygonalItem::winding() const
3641 {
3642     return wind;
3643 }
3644 
3645 /*!
3646     If \a enable is true, the polygonal item will use the winding
3647     algorithm to determine the "inside" of the polygon; otherwise the
3648     odd-even algorithm will be used.
3649 
3650     The default is to use the odd-even algorithm.
3651 
3652     \sa winding()
3653 */
setWinding(bool enable)3654 void Q3CanvasPolygonalItem::setWinding(bool enable)
3655 {
3656     wind = enable;
3657 }
3658 
3659 /*!
3660     Invalidates all information about the area covered by the canvas
3661     item. The item will be updated automatically on the next call that
3662     changes the item's status, for example, move() or update(). Call
3663     this function if you are going to change the shape of the item (as
3664     returned by areaPoints()) while the item is visible.
3665 */
invalidate()3666 void Q3CanvasPolygonalItem::invalidate()
3667 {
3668     val = (uint)false;
3669     removeFromChunks();
3670 }
3671 
3672 /*!
3673     \fn Q3CanvasPolygonalItem::isValid() const
3674 
3675     Returns true if the polygonal item's area information has not been
3676     invalidated; otherwise returns false.
3677 
3678     \sa invalidate()
3679 */
3680 
3681 /*!
3682     Returns the points the polygonal item \e will have after
3683     Q3CanvasItem::advance(1) is called, i.e. what the points are when
3684     advanced by the current xVelocity() and yVelocity().
3685 */
areaPointsAdvanced() const3686 Q3PointArray Q3CanvasPolygonalItem::areaPointsAdvanced() const
3687 {
3688     int dx = int(x()+xVelocity())-int(x());
3689     int dy = int(y()+yVelocity())-int(y());
3690     Q3PointArray r = areaPoints();
3691     r.detach(); // Explicit sharing is stupid.
3692     if (dx || dy)
3693 	r.translate(dx,dy);
3694     return r;
3695 }
3696 
3697 //#define QCANVAS_POLYGONS_DEBUG
3698 #ifdef QCANVAS_POLYGONS_DEBUG
3699 static QWidget* dbg_wid=0;
3700 static QPainter* dbg_ptr=0;
3701 #endif
3702 
3703 class QPolygonalProcessor {
3704 public:
QPolygonalProcessor(Q3Canvas * c,const Q3PointArray & pa)3705     QPolygonalProcessor(Q3Canvas* c, const Q3PointArray& pa) :
3706 	canvas(c)
3707     {
3708 	QRect pixelbounds = pa.boundingRect();
3709 	int cs = canvas->chunkSize();
3710     QRect canvasbounds = pixelbounds.intersected(canvas->rect());
3711     bounds.setLeft(canvasbounds.left()/cs);
3712     bounds.setRight(canvasbounds.right()/cs);
3713     bounds.setTop(canvasbounds.top()/cs);
3714     bounds.setBottom(canvasbounds.bottom()/cs);
3715     bitmap = QImage(bounds.width() + 1, bounds.height(), 1, 2, QImage::LittleEndian);
3716     pnt = 0;
3717 	bitmap.fill(0);
3718 #ifdef QCANVAS_POLYGONS_DEBUG
3719 	dbg_start();
3720 #endif
3721     }
3722 
add(int x,int y)3723     inline void add(int x, int y)
3724     {
3725 	if (pnt >= (int)result.size()) {
3726 	    result.resize(pnt*2+10);
3727 	}
3728 	result[pnt++] = QPoint(x+bounds.x(),y+bounds.y());
3729 #ifdef QCANVAS_POLYGONS_DEBUG
3730 	if (dbg_ptr) {
3731 	    int cs = canvas->chunkSize();
3732 	    QRect r(x*cs+bounds.x()*cs,y*cs+bounds.y()*cs,cs-1,cs-1);
3733 	    dbg_ptr->setPen(Qt::blue);
3734 	    dbg_ptr->drawRect(r);
3735 	}
3736 #endif
3737     }
3738 
addBits(int x1,int x2,uchar newbits,int xo,int yo)3739     inline void addBits(int x1, int x2, uchar newbits, int xo, int yo)
3740     {
3741 	for (int i=x1; i<=x2; i++)
3742 	    if (newbits & (1<<i))
3743 		add(xo+i,yo);
3744     }
3745 
3746 #ifdef QCANVAS_POLYGONS_DEBUG
dbg_start()3747     void dbg_start()
3748     {
3749 	if (!dbg_wid) {
3750 	    dbg_wid = new QWidget;
3751 	    dbg_wid->resize(800,600);
3752 	    dbg_wid->show();
3753 	    dbg_ptr = new QPainter(dbg_wid);
3754 	    dbg_ptr->setBrush(Qt::NoBrush);
3755 	}
3756 	dbg_ptr->fillRect(dbg_wid->rect(),Qt::white);
3757     }
3758 #endif
3759 
doSpans(int n,QPoint * pt,int * w)3760     void doSpans(int n, QPoint* pt, int* w)
3761     {
3762 	int cs = canvas->chunkSize();
3763 	for (int j=0; j<n; j++) {
3764 	    int y = pt[j].y()/cs-bounds.y();
3765         if (y >= bitmap.height() || y < 0) continue;
3766 	    uchar* l = bitmap.scanLine(y);
3767 	    int x = pt[j].x();
3768 	    int x1 = x/cs-bounds.x();
3769         if (x1 > bounds.width()) continue;
3770         x1  = QMAX(0,x1);
3771 	    int x2 = (x+w[j])/cs-bounds.x();
3772         if (x2 < 0) continue;
3773         x2 = QMIN(bounds.width(), x2);
3774 	    int x1q = x1/8;
3775 	    int x1r = x1%8;
3776 	    int x2q = x2/8;
3777 	    int x2r = x2%8;
3778 #ifdef QCANVAS_POLYGONS_DEBUG
3779 	    if (dbg_ptr) dbg_ptr->setPen(Qt::yellow);
3780 #endif
3781 	    if (x1q == x2q) {
3782 		uchar newbits = (~l[x1q]) & (((2<<(x2r-x1r))-1)<<x1r);
3783 		if (newbits) {
3784 #ifdef QCANVAS_POLYGONS_DEBUG
3785 		    if (dbg_ptr) dbg_ptr->setPen(Qt::darkGreen);
3786 #endif
3787 		    addBits(x1r,x2r,newbits,x1q*8,y);
3788 		    l[x1q] |= newbits;
3789 		}
3790 	    } else {
3791 #ifdef QCANVAS_POLYGONS_DEBUG
3792 		if (dbg_ptr) dbg_ptr->setPen(Qt::blue);
3793 #endif
3794 		uchar newbits1 = (~l[x1q]) & (0xff<<x1r);
3795 		if (newbits1) {
3796 #ifdef QCANVAS_POLYGONS_DEBUG
3797 		    if (dbg_ptr) dbg_ptr->setPen(Qt::green);
3798 #endif
3799 		    addBits(x1r,7,newbits1,x1q*8,y);
3800 		    l[x1q] |= newbits1;
3801 		}
3802 		for (int i=x1q+1; i<x2q; i++) {
3803 		    if (l[i] != 0xff) {
3804 			addBits(0,7,~l[i],i*8,y);
3805 			l[i]=0xff;
3806 		    }
3807 		}
3808 		uchar newbits2 = (~l[x2q]) & (0xff>>(7-x2r));
3809 		if (newbits2) {
3810 #ifdef QCANVAS_POLYGONS_DEBUG
3811 		    if (dbg_ptr) dbg_ptr->setPen(Qt::red);
3812 #endif
3813 		    addBits(0,x2r,newbits2,x2q*8,y);
3814 		    l[x2q] |= newbits2;
3815 		}
3816 	    }
3817 #ifdef QCANVAS_POLYGONS_DEBUG
3818 	    if (dbg_ptr) {
3819 		dbg_ptr->drawLine(pt[j],pt[j]+QPoint(w[j],0));
3820 	    }
3821 #endif
3822 	}
3823 	result.resize(pnt);
3824     }
3825 
3826     int pnt;
3827     Q3PointArray result;
3828     Q3Canvas* canvas;
3829     QRect bounds;
3830     QImage bitmap;
3831 };
3832 
3833 
chunks() const3834 Q3PointArray Q3CanvasPolygonalItem::chunks() const
3835 {
3836     Q3PointArray pa = areaPoints();
3837 
3838     if (!pa.size()) {
3839 	pa.detach(); // Explicit sharing is stupid.
3840 	return pa;
3841     }
3842 
3843     QPolygonalProcessor processor(canvas(),pa);
3844 
3845     scanPolygon(pa, wind, processor);
3846 
3847     return processor.result;
3848 }
3849 /*!
3850     Simply calls Q3CanvasItem::chunks().
3851 */
chunks() const3852 Q3PointArray Q3CanvasRectangle::chunks() const
3853 {
3854     // No need to do a polygon scan!
3855     return Q3CanvasItem::chunks();
3856 }
3857 
3858 /*!
3859     Returns the bounding rectangle of the polygonal item, based on
3860     areaPoints().
3861 */
boundingRect() const3862 QRect Q3CanvasPolygonalItem::boundingRect() const
3863 {
3864     return areaPoints().boundingRect();
3865 }
3866 
3867 /*!
3868     Reimplemented from Q3CanvasItem, this draws the polygonal item by
3869     setting the pen and brush for the item on the painter \a p and
3870     calling drawShape().
3871 */
draw(QPainter & p)3872 void Q3CanvasPolygonalItem::draw(QPainter & p)
3873 {
3874     p.setPen(pn);
3875     p.setBrush(br);
3876     drawShape(p);
3877 }
3878 
3879 /*!
3880     \fn void Q3CanvasPolygonalItem::drawShape(QPainter & p)
3881 
3882     Subclasses must reimplement this function to draw their shape. The
3883     pen and brush of \a p are already set to pen() and brush() prior
3884     to calling this function.
3885 
3886     \sa draw()
3887 */
3888 
3889 /*!
3890     \fn QPen Q3CanvasPolygonalItem::pen() const
3891 
3892     Returns the QPen used to draw the outline of the item, if any.
3893 
3894     \sa setPen()
3895 */
3896 
3897 /*!
3898     \fn QBrush Q3CanvasPolygonalItem::brush() const
3899 
3900     Returns the QBrush used to fill the item, if filled.
3901 
3902     \sa setBrush()
3903 */
3904 
3905 /*!
3906     Sets the QPen used when drawing the item to the pen \a p.
3907     Note that many Q3CanvasPolygonalItems do not use the pen value.
3908 
3909     \sa setBrush(), pen(), drawShape()
3910 */
setPen(QPen p)3911 void Q3CanvasPolygonalItem::setPen(QPen p)
3912 {
3913     if (pn != p) {
3914 	removeFromChunks();
3915 	pn = p;
3916 	addToChunks();
3917     }
3918 }
3919 
3920 /*!
3921     Sets the QBrush used when drawing the polygonal item to the brush \a b.
3922 
3923     \sa setPen(), brush(), drawShape()
3924 */
setBrush(QBrush b)3925 void Q3CanvasPolygonalItem::setBrush(QBrush b)
3926 {
3927     if (br != b) {
3928 	br = b;
3929 	changeChunks();
3930     }
3931 }
3932 
3933 
3934 /*!
3935     \class Q3CanvasPolygon
3936     \compat
3937     \brief The Q3CanvasPolygon class provides a polygon on a Q3Canvas.
3938 
3939     Paints a polygon with a QBrush. The polygon's points can be set in
3940     the constructor or set or changed later using setPoints(). Use
3941     points() to retrieve the points, or areaPoints() to retrieve the
3942     points relative to the canvas's origin.
3943 
3944     The polygon can be drawn on a painter with drawShape().
3945 
3946     Like any other canvas item polygons can be moved with
3947     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting
3948     coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY() and
3949     Q3CanvasItem::setZ().
3950 
3951     Note: Q3CanvasPolygon does not use the pen.
3952 
3953     \sa QtCanvas, {Porting to Graphics View}
3954 */
3955 
3956 /*!
3957     Constructs a point-less polygon on the canvas \a canvas. You
3958     should call setPoints() before using it further.
3959 */
Q3CanvasPolygon(Q3Canvas * canvas)3960 Q3CanvasPolygon::Q3CanvasPolygon(Q3Canvas* canvas) :
3961     Q3CanvasPolygonalItem(canvas)
3962 {
3963 }
3964 
3965 /*!
3966     Destroys the polygon.
3967 */
~Q3CanvasPolygon()3968 Q3CanvasPolygon::~Q3CanvasPolygon()
3969 {
3970     hide();
3971 }
3972 
3973 /*!
3974     Draws the polygon using the painter \a p.
3975 
3976     Note that Q3CanvasPolygon does not support an outline (the pen is
3977     always NoPen).
3978 */
drawShape(QPainter & p)3979 void Q3CanvasPolygon::drawShape(QPainter & p)
3980 {
3981     // ### why can't we draw outlines? We could use drawPolyline for it. Lars
3982     // ### see other message. Warwick
3983 
3984     p.setPen(NoPen); // since QRegion(Q3PointArray) excludes outline :-()-:
3985     p.drawPolygon(poly);
3986 }
3987 
3988 /*!
3989     Sets the points of the polygon to be \a pa. These points will have
3990     their x and y coordinates automatically translated by x(), y() as
3991     the polygon is moved.
3992 */
setPoints(Q3PointArray pa)3993 void Q3CanvasPolygon::setPoints(Q3PointArray pa)
3994 {
3995     removeFromChunks();
3996     poly = pa;
3997     poly.detach(); // Explicit sharing is stupid.
3998     poly.translate((int)x(),(int)y());
3999     addToChunks();
4000 }
4001 
4002 /*!
4003   \reimp
4004 */
moveBy(double dx,double dy)4005 void Q3CanvasPolygon::moveBy(double dx, double dy)
4006 {
4007     // Note: does NOT call Q3CanvasPolygonalItem::moveBy(), since that
4008     // only does half this work.
4009     //
4010     int idx = int(x()+dx)-int(x());
4011     int idy = int(y()+dy)-int(y());
4012     if (idx || idy) {
4013 	removeFromChunks();
4014 	poly.translate(idx,idy);
4015     }
4016     myx+=dx;
4017     myy+=dy;
4018     if (idx || idy) {
4019 	addToChunks();
4020     }
4021 }
4022 
4023 /*!
4024     \class Q3CanvasSpline
4025     \compat
4026     \brief The Q3CanvasSpline class provides multi-bezier splines on a Q3Canvas.
4027 
4028     A Q3CanvasSpline is a sequence of 4-point bezier curves joined
4029     together to make a curved shape.
4030 
4031     You set the control points of the spline with setControlPoints().
4032 
4033     If the bezier is closed(), then the first control point will be
4034     re-used as the last control point. Therefore, a closed bezier must
4035     have a multiple of 3 control points and an open bezier must have
4036     one extra point.
4037 
4038     The beziers are not necessarily joined "smoothly". To ensure this,
4039     set control points appropriately (general reference texts about
4040     beziers will explain this in detail).
4041 
4042     Like any other canvas item splines can be moved with
4043     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting
4044     coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY() and
4045     Q3CanvasItem::setZ().
4046 
4047     \sa QtCanvas, {Porting to Graphics View}
4048 */
4049 
4050 /*!
4051     Create a spline with no control points on the canvas \a canvas.
4052 
4053     \sa setControlPoints()
4054 */
Q3CanvasSpline(Q3Canvas * canvas)4055 Q3CanvasSpline::Q3CanvasSpline(Q3Canvas* canvas) :
4056     Q3CanvasPolygon(canvas),
4057     cl(true)
4058 {
4059 }
4060 
4061 /*!
4062     Destroy the spline.
4063 */
~Q3CanvasSpline()4064 Q3CanvasSpline::~Q3CanvasSpline()
4065 {
4066 }
4067 
4068 /*!
4069     Set the spline control points to \a ctrl.
4070 
4071     If \a close is true, then the first point in \a ctrl will be
4072     re-used as the last point, and the number of control points must
4073     be a multiple of 3. If \a close is false, one additional control
4074     point is required, and the number of control points must be one of
4075     (4, 7, 10, 13, ...).
4076 
4077     If the number of control points doesn't meet the above conditions,
4078     the number of points will be truncated to the largest number of
4079     points that do meet the requirement.
4080 */
setControlPoints(Q3PointArray ctrl,bool close)4081 void Q3CanvasSpline::setControlPoints(Q3PointArray ctrl, bool close)
4082 {
4083     if ((int)ctrl.count() % 3 != (close ? 0 : 1)) {
4084 	qWarning("Q3CanvasSpline::setControlPoints(): Number of points doesn't fit.");
4085 	int numCurves = (ctrl.count() - (close ? 0 : 1))/ 3;
4086 	ctrl.resize(numCurves*3 + (close ? 0 : 1));
4087     }
4088 
4089     cl = close;
4090     bez = ctrl;
4091     recalcPoly();
4092 }
4093 
4094 /*!
4095     Returns the current set of control points.
4096 
4097     \sa setControlPoints(), closed()
4098 */
controlPoints() const4099 Q3PointArray Q3CanvasSpline::controlPoints() const
4100 {
4101     return bez;
4102 }
4103 
4104 /*!
4105     Returns true if the control points are a closed set; otherwise
4106     returns false.
4107 */
closed() const4108 bool Q3CanvasSpline::closed() const
4109 {
4110     return cl;
4111 }
4112 
recalcPoly()4113 void Q3CanvasSpline::recalcPoly()
4114 {
4115     Q3PtrList<Q3PointArray> segs;
4116     segs.setAutoDelete(true);
4117     int n=0;
4118     for (int i=0; i<(int)bez.count()-1; i+=3) {
4119 	Q3PointArray ctrl(4);
4120 	ctrl[0] = bez[i+0];
4121 	ctrl[1] = bez[i+1];
4122 	ctrl[2] = bez[i+2];
4123 	if (cl)
4124 	    ctrl[3] = bez[(i+3)%(int)bez.count()];
4125 	else
4126 	    ctrl[3] = bez[i+3];
4127 	Q3PointArray *seg = new Q3PointArray(ctrl.cubicBezier());
4128 	n += seg->count()-1;
4129 	segs.append(seg);
4130     }
4131     Q3PointArray p(n+1);
4132     n=0;
4133     for (Q3PointArray* seg = segs.first(); seg; seg = segs.next()) {
4134 	for (int i=0; i<(int)seg->count()-1; i++)
4135 	    p[n++] = seg->point(i);
4136 	if (n == (int)p.count()-1)
4137 	    p[n] = seg->point(seg->count()-1);
4138     }
4139     Q3CanvasPolygon::setPoints(p);
4140 }
4141 
4142 /*!
4143     \fn Q3PointArray Q3CanvasPolygonalItem::areaPoints() const
4144 
4145     This function must be reimplemented by subclasses. It \e must
4146     return the points bounding (i.e. outside and not touching) the
4147     shape or drawing errors will occur.
4148 */
4149 
4150 /*!
4151     \fn Q3PointArray Q3CanvasPolygon::points() const
4152 
4153     Returns the vertices of the polygon, not translated by the position.
4154 
4155     \sa setPoints(), areaPoints()
4156 */
points() const4157 Q3PointArray Q3CanvasPolygon::points() const
4158 {
4159     Q3PointArray pa = areaPoints();
4160     pa.translate(int(-x()),int(-y()));
4161     return pa;
4162 }
4163 
4164 /*!
4165     Returns the vertices of the polygon translated by the polygon's
4166     current x(), y() position, i.e. relative to the canvas's origin.
4167 
4168     \sa setPoints(), points()
4169 */
areaPoints() const4170 Q3PointArray Q3CanvasPolygon::areaPoints() const
4171 {
4172     return poly.copy();
4173 }
4174 
4175 /*!
4176     \class Q3CanvasLine
4177     \compat
4178     \brief The Q3CanvasLine class provides a line on a Q3Canvas.
4179 
4180     The line inherits functionality from Q3CanvasPolygonalItem, for
4181     example the setPen() function. The start and end points of the
4182     line are set with setPoints().
4183 
4184     Like any other canvas item lines can be moved with
4185     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting
4186     coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY() and
4187     Q3CanvasItem::setZ().
4188 
4189     \sa QtCanvas, {Porting to Graphics View}
4190 */
4191 
4192 /*!
4193     Constructs a line from (0,0) to (0,0) on \a canvas.
4194 
4195     \sa setPoints()
4196 */
Q3CanvasLine(Q3Canvas * canvas)4197 Q3CanvasLine::Q3CanvasLine(Q3Canvas* canvas) :
4198     Q3CanvasPolygonalItem(canvas)
4199 {
4200     x1 = y1 = x2 = y2 = 0;
4201 }
4202 
4203 /*!
4204     Destroys the line.
4205 */
~Q3CanvasLine()4206 Q3CanvasLine::~Q3CanvasLine()
4207 {
4208     hide();
4209 }
4210 
4211 /*!
4212   \reimp
4213 */
setPen(QPen p)4214 void Q3CanvasLine::setPen(QPen p)
4215 {
4216     Q3CanvasPolygonalItem::setPen(p);
4217 }
4218 
4219 /*!
4220     \fn QPoint Q3CanvasLine::startPoint () const
4221 
4222     Returns the start point of the line.
4223 
4224     \sa setPoints(), endPoint()
4225 */
4226 
4227 /*!
4228     \fn QPoint Q3CanvasLine::endPoint () const
4229 
4230     Returns the end point of the line.
4231 
4232     \sa setPoints(), startPoint()
4233 */
4234 
4235 /*!
4236     Sets the line's start point to (\a xa, \a ya) and its end point to
4237     (\a xb, \a yb).
4238 */
setPoints(int xa,int ya,int xb,int yb)4239 void Q3CanvasLine::setPoints(int xa, int ya, int xb, int yb)
4240 {
4241     if (x1 != xa || x2 != xb || y1 != ya || y2 != yb) {
4242 	removeFromChunks();
4243 	x1 = xa;
4244 	y1 = ya;
4245 	x2 = xb;
4246 	y2 = yb;
4247 	addToChunks();
4248     }
4249 }
4250 
4251 /*!
4252   \reimp
4253 */
drawShape(QPainter & p)4254 void Q3CanvasLine::drawShape(QPainter &p)
4255 {
4256     p.drawLine((int)(x()+x1), (int)(y()+y1), (int)(x()+x2), (int)(y()+y2));
4257 }
4258 
4259 /*!
4260     \reimp
4261 
4262     Note that the area defined by the line is somewhat thicker than
4263     the line that is actually drawn.
4264 */
areaPoints() const4265 Q3PointArray Q3CanvasLine::areaPoints() const
4266 {
4267     Q3PointArray p(4);
4268     int xi = int(x());
4269     int yi = int(y());
4270     int pw = pen().width();
4271     int dx = QABS(x1-x2);
4272     int dy = QABS(y1-y2);
4273     pw = pw*4/3+2; // approx pw*sqrt(2)
4274     int px = x1<x2 ? -pw : pw ;
4275     int py = y1<y2 ? -pw : pw ;
4276     if (dx && dy && (dx > dy ? (dx*2/dy <= 2) : (dy*2/dx <= 2))) {
4277 	// steep
4278 	if (px == py) {
4279 	    p[0] = QPoint(x1+xi   ,y1+yi+py);
4280 	    p[1] = QPoint(x2+xi-px,y2+yi  );
4281 	    p[2] = QPoint(x2+xi   ,y2+yi-py);
4282 	    p[3] = QPoint(x1+xi+px,y1+yi  );
4283 	} else {
4284 	    p[0] = QPoint(x1+xi+px,y1+yi  );
4285 	    p[1] = QPoint(x2+xi   ,y2+yi-py);
4286 	    p[2] = QPoint(x2+xi-px,y2+yi  );
4287 	    p[3] = QPoint(x1+xi   ,y1+yi+py);
4288 	}
4289     } else if (dx > dy) {
4290 	// horizontal
4291 	p[0] = QPoint(x1+xi+px,y1+yi+py);
4292 	p[1] = QPoint(x2+xi-px,y2+yi+py);
4293 	p[2] = QPoint(x2+xi-px,y2+yi-py);
4294 	p[3] = QPoint(x1+xi+px,y1+yi-py);
4295     } else {
4296 	// vertical
4297 	p[0] = QPoint(x1+xi+px,y1+yi+py);
4298 	p[1] = QPoint(x2+xi+px,y2+yi-py);
4299 	p[2] = QPoint(x2+xi-px,y2+yi-py);
4300 	p[3] = QPoint(x1+xi-px,y1+yi+py);
4301     }
4302     return p;
4303 }
4304 
4305 /*!
4306     \reimp
4307 
4308 */
4309 
moveBy(double dx,double dy)4310 void Q3CanvasLine::moveBy(double dx, double dy)
4311 {
4312     Q3CanvasPolygonalItem::moveBy(dx, dy);
4313 }
4314 
4315 /*!
4316     \class Q3CanvasRectangle
4317     \compat
4318     \brief The Q3CanvasRectangle class provides a rectangle on a Q3Canvas.
4319 
4320     This item paints a single rectangle which may have any pen() and
4321     brush(), but may not be tilted/rotated. For rotated rectangles,
4322     use Q3CanvasPolygon.
4323 
4324     The rectangle's size and initial position can be set in the
4325     constructor. The size can be set or changed later using setSize().
4326     Use height() and width() to retrieve the rectangle's dimensions.
4327 
4328     The rectangle can be drawn on a painter with drawShape().
4329 
4330     Like any other canvas item rectangles can be moved with
4331     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting
4332     coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY() and
4333     Q3CanvasItem::setZ().
4334 
4335     \sa QtCanvas, {Porting to Graphics View}
4336 */
4337 
4338 /*!
4339     Constructs a rectangle at position (0,0) with both width and
4340     height set to 32 pixels on \a canvas.
4341 */
Q3CanvasRectangle(Q3Canvas * canvas)4342 Q3CanvasRectangle::Q3CanvasRectangle(Q3Canvas* canvas) :
4343     Q3CanvasPolygonalItem(canvas),
4344     w(32), h(32)
4345 {
4346 }
4347 
4348 /*!
4349     Constructs a rectangle positioned and sized by \a r on \a canvas.
4350 */
Q3CanvasRectangle(const QRect & r,Q3Canvas * canvas)4351 Q3CanvasRectangle::Q3CanvasRectangle(const QRect& r, Q3Canvas* canvas) :
4352     Q3CanvasPolygonalItem(canvas),
4353     w(r.width()), h(r.height())
4354 {
4355     move(r.x(),r.y());
4356 }
4357 
4358 /*!
4359     Constructs a rectangle at position (\a x, \a y) and size \a width
4360     by \a height, on \a canvas.
4361 */
Q3CanvasRectangle(int x,int y,int width,int height,Q3Canvas * canvas)4362 Q3CanvasRectangle::Q3CanvasRectangle(int x, int y, int width, int height,
4363 	Q3Canvas* canvas) :
4364     Q3CanvasPolygonalItem(canvas),
4365     w(width), h(height)
4366 {
4367     move(x,y);
4368 }
4369 
4370 /*!
4371     Destroys the rectangle.
4372 */
~Q3CanvasRectangle()4373 Q3CanvasRectangle::~Q3CanvasRectangle()
4374 {
4375     hide();
4376 }
4377 
4378 
4379 /*!
4380     Returns the width of the rectangle.
4381 */
width() const4382 int Q3CanvasRectangle::width() const
4383 {
4384     return w;
4385 }
4386 
4387 /*!
4388     Returns the height of the rectangle.
4389 */
height() const4390 int Q3CanvasRectangle::height() const
4391 {
4392     return h;
4393 }
4394 
4395 /*!
4396     Sets the \a width and \a height of the rectangle.
4397 */
setSize(int width,int height)4398 void Q3CanvasRectangle::setSize(int width, int height)
4399 {
4400     if (w != width || h != height) {
4401 	removeFromChunks();
4402 	w = width;
4403 	h = height;
4404 	addToChunks();
4405     }
4406 }
4407 
4408 /*!
4409     \fn QSize Q3CanvasRectangle::size() const
4410 
4411     Returns the width() and height() of the rectangle.
4412 
4413     \sa rect(), setSize()
4414 */
4415 
4416 /*!
4417     \fn QRect Q3CanvasRectangle::rect() const
4418 
4419     Returns the integer-converted x(), y() position and size() of the
4420     rectangle as a QRect.
4421 */
4422 
4423 /*!
4424   \reimp
4425 */
areaPoints() const4426 Q3PointArray Q3CanvasRectangle::areaPoints() const
4427 {
4428     Q3PointArray pa(4);
4429     int pw = (pen().width()+1)/2;
4430     if (pw < 1) pw = 1;
4431     if (pen() == NoPen) pw = 0;
4432     pa[0] = QPoint((int)x()-pw,(int)y()-pw);
4433     pa[1] = pa[0] + QPoint(w+pw*2,0);
4434     pa[2] = pa[1] + QPoint(0,h+pw*2);
4435     pa[3] = pa[0] + QPoint(0,h+pw*2);
4436     return pa;
4437 }
4438 
4439 /*!
4440     Draws the rectangle on painter \a p.
4441 */
drawShape(QPainter & p)4442 void Q3CanvasRectangle::drawShape(QPainter & p)
4443 {
4444     p.drawRect((int)x(), (int)y(), w, h);
4445 }
4446 
4447 
4448 /*!
4449     \class Q3CanvasEllipse
4450     \compat
4451     \brief The Q3CanvasEllipse class provides an ellipse or ellipse segment on a Q3Canvas.
4452 
4453     A canvas item that paints an ellipse or ellipse segment with a QBrush.
4454     The ellipse's height, width, start angle and angle length can be set
4455     at construction time. The size can be changed at runtime with
4456     setSize(), and the angles can be changed (if you're displaying an
4457     ellipse segment rather than a whole ellipse) with setAngles().
4458 
4459     Note that angles are specified in 16ths of a degree.
4460 
4461     \target anglediagram
4462     \img qcanvasellipse.png Ellipse
4463 
4464     If a start angle and length angle are set then an ellipse segment
4465     will be drawn. The start angle is the angle that goes from zero in a
4466     counter-clockwise direction (shown in green in the diagram). The
4467     length angle is the angle from the start angle in a
4468     counter-clockwise direction (shown in blue in the diagram). The blue
4469     segment is the segment of the ellipse that would be drawn. If no
4470     start angle and length angle are specified the entire ellipse is
4471     drawn.
4472 
4473     The ellipse can be drawn on a painter with drawShape().
4474 
4475     Like any other canvas item ellipses can be moved with move() and
4476     moveBy(), or by setting coordinates with setX(), setY() and setZ().
4477 
4478     Note: Q3CanvasEllipse does not use the pen.
4479 
4480     \sa QtCanvas, {Porting to Graphics View}
4481 */
4482 
4483 /*!
4484     Constructs a 32x32 ellipse, centered at (0, 0) on \a canvas.
4485 */
Q3CanvasEllipse(Q3Canvas * canvas)4486 Q3CanvasEllipse::Q3CanvasEllipse(Q3Canvas* canvas) :
4487     Q3CanvasPolygonalItem(canvas),
4488     w(32), h(32),
4489     a1(0), a2(360*16)
4490 {
4491 }
4492 
4493 /*!
4494     Constructs a \a width by \a height pixel ellipse, centered at
4495     (0, 0) on \a canvas.
4496 */
Q3CanvasEllipse(int width,int height,Q3Canvas * canvas)4497 Q3CanvasEllipse::Q3CanvasEllipse(int width, int height, Q3Canvas* canvas) :
4498     Q3CanvasPolygonalItem(canvas),
4499     w(width),h(height),
4500     a1(0),a2(360*16)
4501 {
4502 }
4503 
4504 // ### add a constructor taking degrees in float. 1/16 degrees is stupid. Lars
4505 // ### it's how QPainter does it, so Q3Canvas does too for consistency. If it's
4506 // ###  a good idea, it should be added to QPainter, not just to Q3Canvas. Warwick
4507 /*!
4508     Constructs a \a width by \a height pixel ellipse, centered at
4509     (0, 0) on \a canvas. Only a segment of the ellipse is drawn,
4510     starting at angle \a startangle, and extending for angle \a angle
4511     (the angle length).
4512 
4513     Note that angles are specified in sixteenths of a degree.
4514 */
Q3CanvasEllipse(int width,int height,int startangle,int angle,Q3Canvas * canvas)4515 Q3CanvasEllipse::Q3CanvasEllipse(int width, int height,
4516     int startangle, int angle, Q3Canvas* canvas) :
4517     Q3CanvasPolygonalItem(canvas),
4518     w(width),h(height),
4519     a1(startangle),a2(angle)
4520 {
4521 }
4522 
4523 /*!
4524     Destroys the ellipse.
4525 */
~Q3CanvasEllipse()4526 Q3CanvasEllipse::~Q3CanvasEllipse()
4527 {
4528     hide();
4529 }
4530 
4531 /*!
4532     Returns the width of the ellipse.
4533 */
width() const4534 int Q3CanvasEllipse::width() const
4535 {
4536     return w;
4537 }
4538 
4539 /*!
4540     Returns the height of the ellipse.
4541 */
height() const4542 int Q3CanvasEllipse::height() const
4543 {
4544     return h;
4545 }
4546 
4547 /*!
4548     Sets the \a width and \a height of the ellipse.
4549 */
setSize(int width,int height)4550 void Q3CanvasEllipse::setSize(int width, int height)
4551 {
4552     if (w != width || h != height) {
4553 	removeFromChunks();
4554 	w = width;
4555 	h = height;
4556 	addToChunks();
4557     }
4558 }
4559 
4560 /*!
4561     \fn int Q3CanvasEllipse::angleStart() const
4562 
4563     Returns the start angle in 16ths of a degree. Initially
4564     this will be 0.
4565 
4566     \sa setAngles(), angleLength()
4567 */
4568 
4569 /*!
4570     \fn int Q3CanvasEllipse::angleLength() const
4571 
4572     Returns the length angle (the extent of the ellipse segment) in
4573     16ths of a degree. Initially this will be 360 * 16 (a complete
4574     ellipse).
4575 
4576     \sa setAngles(), angleStart()
4577 */
4578 
4579 /*!
4580     Sets the angles for the ellipse. The start angle is \a start and
4581     the extent of the segment is \a length (the angle length) from the
4582     \a start. The angles are specified in 16ths of a degree. By
4583     default the ellipse will start at 0 and have an angle length of
4584     360 * 16 (a complete ellipse).
4585 
4586     \sa angleStart(), angleLength()
4587 */
setAngles(int start,int length)4588 void Q3CanvasEllipse::setAngles(int start, int length)
4589 {
4590     if (a1 != start || a2 != length) {
4591 	removeFromChunks();
4592 	a1 = start;
4593 	a2 = length;
4594 	addToChunks();
4595     }
4596 }
4597 
4598 /*!
4599   \reimp
4600 */
areaPoints() const4601 Q3PointArray Q3CanvasEllipse::areaPoints() const
4602 {
4603     Q3PointArray r;
4604     // makeArc at 0,0, then translate so that fixed point math doesn't overflow
4605     r.makeArc(int(x()-w/2.0+0.5)-1, int(y()-h/2.0+0.5)-1, w+3, h+3, a1, a2);
4606     r.resize(r.size()+1);
4607     r.setPoint(r.size()-1,int(x()),int(y()));
4608     return r;
4609 }
4610 
4611 // ### support outlines! Lars
4612 // ### QRegion doesn't, so we cannot (try it). Warwick
4613 /*!
4614     Draws the ellipse, centered at x(), y() using the painter \a p.
4615 
4616     Note that Q3CanvasEllipse does not support an outline (the pen is
4617     always NoPen).
4618 */
drawShape(QPainter & p)4619 void Q3CanvasEllipse::drawShape(QPainter & p)
4620 {
4621     p.setPen(NoPen); // since QRegion(Q3PointArray) excludes outline :-()-:
4622     if (!a1 && a2 == 360*16) {
4623 	p.drawEllipse(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h);
4624     } else {
4625 	p.drawPie(int(x()-w/2.0+0.5), int(y()-h/2.0+0.5), w, h, a1, a2);
4626     }
4627 }
4628 
4629 
4630 /*!
4631     \class Q3CanvasText
4632     \compat
4633     \brief The Q3CanvasText class provides a text object on a Q3Canvas.
4634 
4635     A canvas text item has text with font, color and alignment
4636     attributes. The text and font can be set in the constructor or set
4637     or changed later with setText() and setFont(). The color is set
4638     with setColor() and the alignment with setTextFlags(). The text
4639     item's bounding rectangle is retrieved with boundingRect().
4640 
4641     The text can be drawn on a painter with draw().
4642 
4643     Like any other canvas item text items can be moved with
4644     Q3CanvasItem::move() and Q3CanvasItem::moveBy(), or by setting
4645     coordinates with Q3CanvasItem::setX(), Q3CanvasItem::setY() and
4646     Q3CanvasItem::setZ().
4647 
4648     \sa QtCanvas, {Porting to Graphics View}
4649 */
4650 
4651 /*!
4652     Constructs a Q3CanvasText with the text "\<text\>", on \a canvas.
4653 */
Q3CanvasText(Q3Canvas * canvas)4654 Q3CanvasText::Q3CanvasText(Q3Canvas* canvas) :
4655     Q3CanvasItem(canvas),
4656     txt(QLatin1String("<text>")), flags(0)
4657 {
4658     setRect();
4659 }
4660 
4661 // ### add textflags to the constructor? Lars
4662 /*!
4663     Constructs a Q3CanvasText with the text \a t, on canvas \a canvas.
4664 */
Q3CanvasText(const QString & t,Q3Canvas * canvas)4665 Q3CanvasText::Q3CanvasText(const QString& t, Q3Canvas* canvas) :
4666     Q3CanvasItem(canvas),
4667     txt(t), flags(0)
4668 {
4669     setRect();
4670 }
4671 
4672 // ### see above
4673 /*!
4674     Constructs a Q3CanvasText with the text \a t and font \a f, on the
4675     canvas \a canvas.
4676 */
Q3CanvasText(const QString & t,QFont f,Q3Canvas * canvas)4677 Q3CanvasText::Q3CanvasText(const QString& t, QFont f, Q3Canvas* canvas) :
4678     Q3CanvasItem(canvas),
4679     txt(t), flags(0),
4680     fnt(f)
4681 {
4682     setRect();
4683 }
4684 
4685 /*!
4686     Destroys the canvas text item.
4687 */
~Q3CanvasText()4688 Q3CanvasText::~Q3CanvasText()
4689 {
4690     removeFromChunks();
4691 }
4692 
4693 /*!
4694     Returns the bounding rectangle of the text.
4695 */
boundingRect() const4696 QRect Q3CanvasText::boundingRect() const { return brect; }
4697 
setRect()4698 void Q3CanvasText::setRect()
4699 {
4700     brect = QFontMetrics(fnt).boundingRect(int(x()), int(y()), 0, 0, flags, txt);
4701 }
4702 
4703 /*!
4704     \fn int Q3CanvasText::textFlags() const
4705 
4706     Returns the currently set alignment flags.
4707 
4708     \sa setTextFlags() Qt::AlignmentFlag
4709 */
4710 
4711 
4712 /*!
4713     Sets the alignment flags to \a f. These are a bitwise OR of the
4714     flags available to QPainter::drawText() -- see the
4715     \l{Qt::AlignmentFlag}s.
4716 
4717     \sa setFont() setColor()
4718 */
setTextFlags(int f)4719 void Q3CanvasText::setTextFlags(int f)
4720 {
4721     if (flags != f) {
4722 	removeFromChunks();
4723 	flags = f;
4724 	setRect();
4725 	addToChunks();
4726     }
4727 }
4728 
4729 /*!
4730     Returns the text item's text.
4731 
4732     \sa setText()
4733 */
text() const4734 QString Q3CanvasText::text() const
4735 {
4736     return txt;
4737 }
4738 
4739 
4740 /*!
4741     Sets the text item's text to \a t. The text may contain newlines.
4742 
4743     \sa text(), setFont(), setColor() setTextFlags()
4744 */
setText(const QString & t)4745 void Q3CanvasText::setText(const QString& t)
4746 {
4747     if (txt != t) {
4748 	removeFromChunks();
4749 	txt = t;
4750 	setRect();
4751 	addToChunks();
4752     }
4753 }
4754 
4755 /*!
4756     Returns the font in which the text is drawn.
4757 
4758     \sa setFont()
4759 */
font() const4760 QFont Q3CanvasText::font() const
4761 {
4762     return fnt;
4763 }
4764 
4765 /*!
4766     Sets the font in which the text is drawn to font \a f.
4767 
4768     \sa font()
4769 */
setFont(const QFont & f)4770 void Q3CanvasText::setFont(const QFont& f)
4771 {
4772     if (f != fnt) {
4773 	removeFromChunks();
4774 	fnt = f;
4775 	setRect();
4776 	addToChunks();
4777     }
4778 }
4779 
4780 /*!
4781     Returns the color of the text.
4782 
4783     \sa setColor()
4784 */
color() const4785 QColor Q3CanvasText::color() const
4786 {
4787     return col;
4788 }
4789 
4790 /*!
4791     Sets the color of the text to the color \a c.
4792 
4793     \sa color(), setFont()
4794 */
setColor(const QColor & c)4795 void Q3CanvasText::setColor(const QColor& c)
4796 {
4797     col=c;
4798     changeChunks();
4799 }
4800 
4801 
4802 /*!
4803   \reimp
4804 */
moveBy(double dx,double dy)4805 void Q3CanvasText::moveBy(double dx, double dy)
4806 {
4807     int idx = int(x()+dx)-int(x());
4808     int idy = int(y()+dy)-int(y());
4809     if (idx || idy) {
4810 	removeFromChunks();
4811     }
4812     myx+=dx;
4813     myy+=dy;
4814     if (idx || idy) {
4815 	brect.moveBy(idx,idy);
4816 	addToChunks();
4817     }
4818 }
4819 
4820 /*!
4821     Draws the text using the painter \a painter.
4822 */
draw(QPainter & painter)4823 void Q3CanvasText::draw(QPainter& painter)
4824 {
4825     painter.setFont(fnt);
4826     painter.setPen(col);
4827     painter.drawText(painter.fontMetrics().boundingRect(int(x()), int(y()), 0, 0, flags, txt), flags, txt);
4828 }
4829 
4830 /*!
4831   \internal
4832 */
changeChunks()4833 void Q3CanvasText::changeChunks()
4834 {
4835     if (isVisible() && canvas()) {
4836 	int chunksize=canvas()->chunkSize();
4837 	for (int j=brect.top()/chunksize; j<=brect.bottom()/chunksize; j++) {
4838 	    for (int i=brect.left()/chunksize; i<=brect.right()/chunksize; i++) {
4839 		canvas()->setChangedChunk(i,j);
4840 	    }
4841 	}
4842     }
4843 }
4844 
4845 /*!
4846     Adds the text item to the appropriate chunks.
4847 */
addToChunks()4848 void Q3CanvasText::addToChunks()
4849 {
4850     if (isVisible() && canvas()) {
4851 	int chunksize=canvas()->chunkSize();
4852 	for (int j=brect.top()/chunksize; j<=brect.bottom()/chunksize; j++) {
4853 	    for (int i=brect.left()/chunksize; i<=brect.right()/chunksize; i++) {
4854 		canvas()->addItemToChunk(this,i,j);
4855 	    }
4856 	}
4857     }
4858 }
4859 
4860 /*!
4861     Removes the text item from the appropriate chunks.
4862 */
removeFromChunks()4863 void Q3CanvasText::removeFromChunks()
4864 {
4865     if (isVisible() && canvas()) {
4866 	int chunksize=canvas()->chunkSize();
4867 	for (int j=brect.top()/chunksize; j<=brect.bottom()/chunksize; j++) {
4868 	    for (int i=brect.left()/chunksize; i<=brect.right()/chunksize; i++) {
4869 		canvas()->removeItemFromChunk(this,i,j);
4870 	    }
4871 	}
4872     }
4873 }
4874 
4875 
4876 /*!
4877     Returns 0 (Q3CanvasItem::Rtti_Item).
4878 
4879     Make your derived classes return their own values for rtti(), so
4880     that you can distinguish between objects returned by
4881     Q3Canvas::at(). You should use values greater than 1000 to allow
4882     for extensions to this class.
4883 
4884     Overuse of this functionality can damage its extensibility. For
4885     example, once you have identified a base class of a Q3CanvasItem
4886     found by Q3Canvas::at(), cast it to that type and call meaningful
4887     methods rather than acting upon the object based on its rtti
4888     value.
4889 
4890     For example:
4891 
4892     \snippet doc/src/snippets/code/src_qt3support_canvas_q3canvas.cpp 4
4893 */
rtti() const4894 int Q3CanvasItem::rtti() const { return RTTI; }
4895 int Q3CanvasItem::RTTI = Rtti_Item;
4896 
4897 /*!
4898     Returns 1 (Q3CanvasItem::Rtti_Sprite).
4899 
4900     \sa Q3CanvasItem::rtti()
4901 */
rtti() const4902 int Q3CanvasSprite::rtti() const { return RTTI; }
4903 int Q3CanvasSprite::RTTI = Rtti_Sprite;
4904 
4905 /*!
4906     Returns 2 (Q3CanvasItem::Rtti_PolygonalItem).
4907 
4908     \sa Q3CanvasItem::rtti()
4909 */
rtti() const4910 int Q3CanvasPolygonalItem::rtti() const { return RTTI; }
4911 int Q3CanvasPolygonalItem::RTTI = Rtti_PolygonalItem;
4912 
4913 /*!
4914     Returns 3 (Q3CanvasItem::Rtti_Text).
4915 
4916     \sa Q3CanvasItem::rtti()
4917 */
rtti() const4918 int Q3CanvasText::rtti() const { return RTTI; }
4919 int Q3CanvasText::RTTI = Rtti_Text;
4920 
4921 /*!
4922     Returns 4 (Q3CanvasItem::Rtti_Polygon).
4923 
4924     \sa Q3CanvasItem::rtti()
4925 */
rtti() const4926 int Q3CanvasPolygon::rtti() const { return RTTI; }
4927 int Q3CanvasPolygon::RTTI = Rtti_Polygon;
4928 
4929 /*!
4930     Returns 5 (Q3CanvasItem::Rtti_Rectangle).
4931 
4932     \sa Q3CanvasItem::rtti()
4933 */
rtti() const4934 int Q3CanvasRectangle::rtti() const { return RTTI; }
4935 int Q3CanvasRectangle::RTTI = Rtti_Rectangle;
4936 
4937 /*!
4938     Returns 6 (Q3CanvasItem::Rtti_Ellipse).
4939 
4940     \sa Q3CanvasItem::rtti()
4941 */
rtti() const4942 int Q3CanvasEllipse::rtti() const { return RTTI; }
4943 int Q3CanvasEllipse::RTTI = Rtti_Ellipse;
4944 
4945 /*!
4946     Returns 7 (Q3CanvasItem::Rtti_Line).
4947 
4948     \sa Q3CanvasItem::rtti()
4949 */
rtti() const4950 int Q3CanvasLine::rtti() const { return RTTI; }
4951 int Q3CanvasLine::RTTI = Rtti_Line;
4952 
4953 /*!
4954     Returns 8 (Q3CanvasItem::Rtti_Spline).
4955 
4956     \sa Q3CanvasItem::rtti()
4957 */
rtti() const4958 int Q3CanvasSpline::rtti() const { return RTTI; }
4959 int Q3CanvasSpline::RTTI = Rtti_Spline;
4960 
4961 /*!
4962     Constructs a Q3CanvasSprite which uses images from the
4963     Q3CanvasPixmapArray \a a.
4964 
4965     The sprite in initially positioned at (0, 0) on \a canvas, using
4966     frame 0.
4967 */
Q3CanvasSprite(Q3CanvasPixmapArray * a,Q3Canvas * canvas)4968 Q3CanvasSprite::Q3CanvasSprite(Q3CanvasPixmapArray* a, Q3Canvas* canvas) :
4969     Q3CanvasItem(canvas),
4970     frm(0),
4971     anim_val(0),
4972     anim_state(0),
4973     anim_type(0),
4974     images(a)
4975 {
4976 }
4977 
4978 
4979 /*!
4980     Set the array of images used for displaying the sprite to the
4981     Q3CanvasPixmapArray \a a.
4982 
4983     If the current frame() is larger than the number of images in \a
4984     a, the current frame will be reset to 0.
4985 */
setSequence(Q3CanvasPixmapArray * a)4986 void Q3CanvasSprite::setSequence(Q3CanvasPixmapArray* a)
4987 {
4988     bool isvisible = isVisible();
4989     if (isvisible && images)
4990 	hide();
4991     images = a;
4992     if (frm >= (int)images->count())
4993 	frm = 0;
4994     if (isvisible)
4995 	show();
4996 }
4997 
4998 /*!
4999 \internal
5000 
5001 Marks any chunks the sprite touches as changed.
5002 */
changeChunks()5003 void Q3CanvasSprite::changeChunks()
5004 {
5005     if (isVisible() && canvas()) {
5006 	int chunksize=canvas()->chunkSize();
5007 	for (int j=topEdge()/chunksize; j<=bottomEdge()/chunksize; j++) {
5008 	    for (int i=leftEdge()/chunksize; i<=rightEdge()/chunksize; i++) {
5009 		canvas()->setChangedChunk(i,j);
5010 	    }
5011 	}
5012     }
5013 }
5014 
5015 /*!
5016     Destroys the sprite and removes it from the canvas. Does \e not
5017     delete the images.
5018 */
~Q3CanvasSprite()5019 Q3CanvasSprite::~Q3CanvasSprite()
5020 {
5021     removeFromChunks();
5022 }
5023 
5024 /*!
5025     Sets the animation frame used for displaying the sprite to \a f,
5026     an index into the Q3CanvasSprite's Q3CanvasPixmapArray. The call
5027     will be ignored if \a f is larger than frameCount() or smaller
5028     than 0.
5029 
5030     \sa frame() move()
5031 */
setFrame(int f)5032 void Q3CanvasSprite::setFrame(int f)
5033 {
5034     move(x(),y(),f);
5035 }
5036 
5037 /*!
5038     \enum Q3CanvasSprite::FrameAnimationType
5039 
5040     This enum is used to identify the different types of frame
5041     animation offered by Q3CanvasSprite.
5042 
5043     \value Cycle at each advance the frame number will be incremented by
5044     1 (modulo the frame count).
5045     \value Oscillate at each advance the frame number will be
5046     incremented by 1 up to the frame count then decremented to by 1 to
5047     0, repeating this sequence forever.
5048 */
5049 
5050 /*!
5051     Sets the animation characteristics for the sprite.
5052 
5053     For \a type == \c Cycle, the frames will increase by \a step
5054     at each advance, modulo the frameCount().
5055 
5056     For \a type == \c Oscillate, the frames will increase by \a step
5057     at each advance, up to the frameCount(), then decrease by \a step
5058     back to 0, repeating forever.
5059 
5060     The \a state parameter is for internal use.
5061 */
setFrameAnimation(FrameAnimationType type,int step,int state)5062 void Q3CanvasSprite::setFrameAnimation(FrameAnimationType type, int step, int state)
5063 {
5064     anim_val = step;
5065     anim_type = type;
5066     anim_state = state;
5067     setAnimated(true);
5068 }
5069 
5070 /*!
5071     Extends the default Q3CanvasItem implementation to provide the
5072     functionality of setFrameAnimation().
5073 
5074     The \a phase is 0 or 1: see Q3CanvasItem::advance() for details.
5075 
5076     \sa Q3CanvasItem::advance() setVelocity()
5077 */
advance(int phase)5078 void Q3CanvasSprite::advance(int phase)
5079 {
5080     if (phase==1) {
5081 	int nf = frame();
5082 	if (anim_type == Oscillate) {
5083 	    if (anim_state)
5084 		nf += anim_val;
5085 	    else
5086 		nf -= anim_val;
5087 	    if (nf < 0) {
5088 		nf = abs(anim_val);
5089 		anim_state = !anim_state;
5090 	    } else if (nf >= frameCount()) {
5091 		nf = frameCount()-1-abs(anim_val);
5092 		anim_state = !anim_state;
5093 	    }
5094 	} else {
5095 	    nf = (nf + anim_val + frameCount()) % frameCount();
5096 	}
5097 	move(x()+xVelocity(),y()+yVelocity(),nf);
5098     }
5099 }
5100 
5101 
5102 /*!
5103     \fn int Q3CanvasSprite::frame() const
5104 
5105     Returns the index of the current animation frame in the
5106     Q3CanvasSprite's Q3CanvasPixmapArray.
5107 
5108     \sa setFrame(), move()
5109 */
5110 
5111 /*!
5112     \fn int Q3CanvasSprite::frameCount() const
5113 
5114     Returns the number of frames in the Q3CanvasSprite's
5115     Q3CanvasPixmapArray.
5116 */
5117 
5118 
5119 /*!
5120     Moves the sprite to (\a x, \a y).
5121 */
move(double x,double y)5122 void Q3CanvasSprite::move(double x, double y) { Q3CanvasItem::move(x,y); }
5123 
5124 /*!
5125     \fn void Q3CanvasSprite::move(double nx, double ny, int nf)
5126 
5127     Moves the sprite to (\a nx, \a ny) and sets the current
5128     frame to \a nf. \a nf will be ignored if it is larger than
5129     frameCount() or smaller than 0.
5130 */
move(double nx,double ny,int nf)5131 void Q3CanvasSprite::move(double nx, double ny, int nf)
5132 {
5133     if (isVisible() && canvas()) {
5134 	hide();
5135 	Q3CanvasItem::move(nx,ny);
5136 	if (nf >= 0 && nf < frameCount())
5137 	    frm=nf;
5138 	show();
5139     } else {
5140 	Q3CanvasItem::move(nx,ny);
5141 	if (nf >= 0 && nf < frameCount())
5142 	    frm=nf;
5143     }
5144 }
5145 
5146 class Q3CanvasPolygonScanner : public Q3PolygonScanner {
5147     QPolygonalProcessor& processor;
5148 public:
Q3CanvasPolygonScanner(QPolygonalProcessor & p)5149     Q3CanvasPolygonScanner(QPolygonalProcessor& p) :
5150 	processor(p)
5151     {
5152     }
processSpans(int n,QPoint * point,int * width)5153     void processSpans(int n, QPoint* point, int* width)
5154     {
5155 	processor.doSpans(n,point,width);
5156     }
5157 };
5158 
scanPolygon(const Q3PointArray & pa,int winding,QPolygonalProcessor & process) const5159 void Q3CanvasPolygonalItem::scanPolygon(const Q3PointArray& pa, int winding, QPolygonalProcessor& process) const
5160 {
5161     Q3CanvasPolygonScanner scanner(process);
5162     scanner.scan(pa,winding);
5163 }
5164 
5165 QT_END_NAMESPACE
5166