src/qt3support/canvas/q3canvas.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    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:
       
    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:
       
    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();
       
    93     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
       
   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 */
       
   123 Q3CanvasClusterizer::Q3CanvasClusterizer(int maxclusters) :
       
   124     cluster(new QRect[maxclusters]),
       
   125     count(0),
       
   126     maxcl(maxclusters)
       
   127 { }
       
   128 
       
   129 Q3CanvasClusterizer::~Q3CanvasClusterizer()
       
   130 {
       
   131     delete [] cluster;
       
   132 }
       
   133 
       
   134 void Q3CanvasClusterizer::clear()
       
   135 {
       
   136     count=0;
       
   137 }
       
   138 
       
   139 void Q3CanvasClusterizer::add(int x, int y)
       
   140 {
       
   141     add(QRect(x,y,1,1));
       
   142 }
       
   143 
       
   144 void Q3CanvasClusterizer::add(int x, int y, int w, int h)
       
   145 {
       
   146     add(QRect(x,y,w,h));
       
   147 }
       
   148 
       
   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 
       
   276 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 
       
   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 
       
   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:
       
   302     Q3CanvasItemPtr() : ptr(0) { }
       
   303     Q3CanvasItemPtr(Q3CanvasItem* p) : ptr(p) { }
       
   304 
       
   305     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     }
       
   312     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     }
       
   319     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     }
       
   326     bool operator==(const Q3CanvasItemPtr& that) const
       
   327     {
       
   328 	    return that.ptr == ptr;
       
   329     }
       
   330     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 */
       
   354 void Q3CanvasItemList::sort()
       
   355 {
       
   356     qHeapSort(*((Q3ValueList<Q3CanvasItemPtr>*)this));
       
   357 }
       
   358 
       
   359 /*!
       
   360   \internal
       
   361 */
       
   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 */
       
   377 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:
       
   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 
       
   391     void sort()
       
   392     {
       
   393 	list.sort();
       
   394     }
       
   395 
       
   396     const Q3CanvasItemList* listPtr() const
       
   397     {
       
   398 	return &list;
       
   399     }
       
   400 
       
   401     void add(Q3CanvasItem* item)
       
   402     {
       
   403 	list.prepend(item);
       
   404 	changed = true;
       
   405     }
       
   406 
       
   407     void remove(Q3CanvasItem* item)
       
   408     {
       
   409 	list.remove(item);
       
   410 	changed = true;
       
   411     }
       
   412 
       
   413     void change()
       
   414     {
       
   415 	changed = true;
       
   416     }
       
   417 
       
   418     bool hasChanged() const
       
   419     {
       
   420 	return changed;
       
   421     }
       
   422 
       
   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 
       
   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 
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 
       
   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 */
       
   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 */
       
   704 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 */
       
   713 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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
   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 */
       
  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 paramater 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  1462 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 */
       
  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 */
       
  1493 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 {
       
  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 */
       
  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 */
       
  1832 Q3CanvasItem::~Q3CanvasItem()
       
  1833 {
       
  1834     if (cnv) {
       
  1835 	cnv->removeItem(this);
       
  1836 	cnv->removeAnimation(this);
       
  1837     }
       
  1838     delete ext;
       
  1839 }
       
  1840 
       
  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 */
       
  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 */
       
  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 */
       
  1925 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 */
       
  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 */
       
  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 */
       
  1984 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 */
       
  1992 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 */
       
  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 */
       
  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). */
       
  2050 void Q3CanvasItem::show()
       
  2051 {
       
  2052     setVisible(true);
       
  2053 }
       
  2054 
       
  2055 /*! Shorthand for setVisible(false). */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  2181 void Q3CanvasItem::setActive(bool yes)
       
  2182 {
       
  2183     if (act!=(uint)yes) {
       
  2184 	act=(uint)yes;
       
  2185 	changeChunks();
       
  2186     }
       
  2187 }
       
  2188 
       
  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 
       
  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 */
       
  2402 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 */
       
  2413 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 */
       
  2425 bool Q3CanvasPolygonalItem::collidesWith(const Q3CanvasItem* i) const
       
  2426 {
       
  2427     return i->collidesWith(0,this,0,0,0);
       
  2428 }
       
  2429 
       
  2430 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 */
       
  2442 bool Q3CanvasRectangle::collidesWith(const Q3CanvasItem* i) const
       
  2443 {
       
  2444     return i->collidesWith(0,this,this,0,0);
       
  2445 }
       
  2446 
       
  2447 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 */
       
  2460 bool Q3CanvasEllipse::collidesWith(const Q3CanvasItem* i) const
       
  2461 {
       
  2462     return i->collidesWith(0,this,0,this,0);
       
  2463 }
       
  2464 
       
  2465 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 */
       
  2477 bool Q3CanvasText::collidesWith(const Q3CanvasItem* i) const
       
  2478 {
       
  2479     return i->collidesWith(0,0,0,0,this);
       
  2480 }
       
  2481 
       
  2482 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 */
       
  2529 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 */
       
  2539 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 */
       
  2551 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 */
       
  2573 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 */
       
  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 */
       
  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 */
       
  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 */
       
  2655 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 */
       
  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 */
       
  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 */
       
  2724 Q3CanvasPixmap::Q3CanvasPixmap(const QPixmap& pm, const QPoint& offset)
       
  2725 {
       
  2726     init(pm,offset.x(),offset.y());
       
  2727 }
       
  2728 
       
  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 
       
  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 */
       
  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 */
       
  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 
       
  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 */
       
  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 */
       
  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 */
       
  2910 Q3CanvasPixmapArray::~Q3CanvasPixmapArray()
       
  2911 {
       
  2912     reset();
       
  2913 }
       
  2914 
       
  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 */
       
  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 */
       
  2972 bool Q3CanvasPixmapArray::readCollisionMasks(const QString& filename)
       
  2973 {
       
  2974     return readPixmaps(filename,framecount,true);
       
  2975 }
       
  2976 
       
  2977 
       
  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 */
       
  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 */
       
  3035 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 */
       
  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 */
       
  3085 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 */
       
  3099 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 */
       
  3111 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 */
       
  3125 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 */
       
  3137 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 */
       
  3151 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 */
       
  3163 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 */
       
  3177 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 */
       
  3201 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 */
       
  3211 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 */
       
  3221 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 */
       
  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 */
       
  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)?
       
  3284 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 */
       
  3294 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  3422 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 */
       
  3433 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 */
       
  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 
       
  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 */
       
  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 */
       
  3521 void Q3CanvasView::drawContents(QPainter *)
       
  3522 {
       
  3523 }
       
  3524 
       
  3525 /*!
       
  3526     Suggests a size sufficient to view the entire canvas.
       
  3527 */
       
  3528 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 */
       
  3596 static const QPen& defaultPolygonPen()
       
  3597 {
       
  3598     static QPen* dp=0;
       
  3599     if (!dp)
       
  3600 	dp = new QPen;
       
  3601     return *dp;
       
  3602 }
       
  3603 
       
  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 */
       
  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 */
       
  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 */
       
  3640 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 */
       
  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 */
       
  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 */
       
  3686 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:
       
  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 
       
  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 
       
  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
       
  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 
       
  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 
       
  3834 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 */
       
  3852 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 */
       
  3862 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 */
       
  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 */
       
  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 */
       
  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 */
       
  3960 Q3CanvasPolygon::Q3CanvasPolygon(Q3Canvas* canvas) :
       
  3961     Q3CanvasPolygonalItem(canvas)
       
  3962 {
       
  3963 }
       
  3964 
       
  3965 /*!
       
  3966     Destroys the polygon.
       
  3967 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  4055 Q3CanvasSpline::Q3CanvasSpline(Q3Canvas* canvas) :
       
  4056     Q3CanvasPolygon(canvas),
       
  4057     cl(true)
       
  4058 {
       
  4059 }
       
  4060 
       
  4061 /*!
       
  4062     Destroy the spline.
       
  4063 */
       
  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 */
       
  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 */
       
  4099 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 */
       
  4108 bool Q3CanvasSpline::closed() const
       
  4109 {
       
  4110     return cl;
       
  4111 }
       
  4112 
       
  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 */
       
  4157 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 */
       
  4170 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 */
       
  4197 Q3CanvasLine::Q3CanvasLine(Q3Canvas* canvas) :
       
  4198     Q3CanvasPolygonalItem(canvas)
       
  4199 {
       
  4200     x1 = y1 = x2 = y2 = 0;
       
  4201 }
       
  4202 
       
  4203 /*!
       
  4204     Destroys the line.
       
  4205 */
       
  4206 Q3CanvasLine::~Q3CanvasLine()
       
  4207 {
       
  4208     hide();
       
  4209 }
       
  4210 
       
  4211 /*!
       
  4212   \reimp
       
  4213 */
       
  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 */
       
  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 */
       
  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 */
       
  4265 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 
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  4373 Q3CanvasRectangle::~Q3CanvasRectangle()
       
  4374 {
       
  4375     hide();
       
  4376 }
       
  4377 
       
  4378 
       
  4379 /*!
       
  4380     Returns the width of the rectangle.
       
  4381 */
       
  4382 int Q3CanvasRectangle::width() const
       
  4383 {
       
  4384     return w;
       
  4385 }
       
  4386 
       
  4387 /*!
       
  4388     Returns the height of the rectangle.
       
  4389 */
       
  4390 int Q3CanvasRectangle::height() const
       
  4391 {
       
  4392     return h;
       
  4393 }
       
  4394 
       
  4395 /*!
       
  4396     Sets the \a width and \a height of the rectangle.
       
  4397 */
       
  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 */
       
  4426 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  4526 Q3CanvasEllipse::~Q3CanvasEllipse()
       
  4527 {
       
  4528     hide();
       
  4529 }
       
  4530 
       
  4531 /*!
       
  4532     Returns the width of the ellipse.
       
  4533 */
       
  4534 int Q3CanvasEllipse::width() const
       
  4535 {
       
  4536     return w;
       
  4537 }
       
  4538 
       
  4539 /*!
       
  4540     Returns the height of the ellipse.
       
  4541 */
       
  4542 int Q3CanvasEllipse::height() const
       
  4543 {
       
  4544     return h;
       
  4545 }
       
  4546 
       
  4547 /*!
       
  4548     Sets the \a width and \a height of the ellipse.
       
  4549 */
       
  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 */
       
  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 */
       
  4601 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  4688 Q3CanvasText::~Q3CanvasText()
       
  4689 {
       
  4690     removeFromChunks();
       
  4691 }
       
  4692 
       
  4693 /*!
       
  4694     Returns the bounding rectangle of the text.
       
  4695 */
       
  4696 QRect Q3CanvasText::boundingRect() const { return brect; }
       
  4697 
       
  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 */
       
  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 */
       
  4734 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 */
       
  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 */
       
  4760 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 */
       
  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 */
       
  4785 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 */
       
  4795 void Q3CanvasText::setColor(const QColor& c)
       
  4796 {
       
  4797     col=c;
       
  4798     changeChunks();
       
  4799 }
       
  4800 
       
  4801 
       
  4802 /*!
       
  4803   \reimp
       
  4804 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  4894 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 */
       
  4902 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 */
       
  4910 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 */
       
  4918 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 */
       
  4926 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 */
       
  4934 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 */
       
  4942 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 */
       
  4950 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 */
       
  4958 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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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 */
       
  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:
       
  5149     Q3CanvasPolygonScanner(QPolygonalProcessor& p) :
       
  5150 	processor(p)
       
  5151     {
       
  5152     }
       
  5153     void processSpans(int n, QPoint* point, int* width)
       
  5154     {
       
  5155 	processor.doSpans(n,point,width);
       
  5156     }
       
  5157 };
       
  5158 
       
  5159 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