diff options
author | Timothy Pearson <[email protected]> | 2011-07-10 15:24:15 -0500 |
---|---|---|
committer | Timothy Pearson <[email protected]> | 2011-07-10 15:24:15 -0500 |
commit | bd0f3345a938b35ce6a12f6150373b0955b8dd12 (patch) | |
tree | 7a520322212d48ebcb9fbe1087e7fca28b76185c /src/kernel/qpainter.cpp | |
download | qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.tar.gz qt3-bd0f3345a938b35ce6a12f6150373b0955b8dd12.zip |
Add Qt3 development HEAD version
Diffstat (limited to 'src/kernel/qpainter.cpp')
-rw-r--r-- | src/kernel/qpainter.cpp | 3966 |
1 files changed, 3966 insertions, 0 deletions
diff --git a/src/kernel/qpainter.cpp b/src/kernel/qpainter.cpp new file mode 100644 index 0000000..e5e9026 --- /dev/null +++ b/src/kernel/qpainter.cpp @@ -0,0 +1,3966 @@ +/**************************************************************************** +** +** Implementation of QPainter, QPen and QBrush classes +** +** Created : 940112 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the kernel module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at [email protected]. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qpainter.h" +#include "qpainter_p.h" +#include "qbitmap.h" +#include "qptrstack.h" +#include "qptrdict.h" +#include "qdatastream.h" +#include "qwidget.h" +#include "qimage.h" +#include "qpaintdevicemetrics.h" +#include "qapplication.h" +#include "qrichtext_p.h" +#include "qregexp.h" +#include "qcleanuphandler.h" +#ifdef Q_WS_QWS +#include "qgfx_qws.h" +#endif +#include <string.h> + +#include "qtextlayout_p.h" +#include "qfontengine_p.h" + +#ifndef QT_NO_TRANSFORMATIONS +typedef QPtrStack<QWMatrix> QWMatrixStack; +#endif + +// POSIX Large File Support redefines truncate -> truncate64 +#if defined(truncate) +# undef truncate +#endif + +/*! + \class QPainter qpainter.h + \brief The QPainter class does low-level painting e.g. on widgets. + + \ingroup graphics + \ingroup images + \mainclass + + The painter provides highly optimized functions to do most of the + drawing GUI programs require. QPainter can draw everything from + simple lines to complex shapes like pies and chords. It can also + draw aligned text and pixmaps. Normally, it draws in a "natural" + coordinate system, but it can also do view and world + transformation. + + The typical use of a painter is: + + \list + \i Construct a painter. + \i Set a pen, a brush etc. + \i Draw. + \i Destroy the painter. + \endlist + + Mostly, all this is done inside a paint event. (In fact, 99% of + all QPainter use is in a reimplementation of + QWidget::paintEvent(), and the painter is heavily optimized for + such use.) Here's one very simple example: + + \code + void SimpleExampleWidget::paintEvent() + { + QPainter paint( this ); + paint.setPen( Qt::blue ); + paint.drawText( rect(), AlignCenter, "The Text" ); + } + \endcode + + Usage is simple, and there are many settings you can use: + + \list + + \i font() is the currently set font. If you set a font that isn't + available, Qt finds a close match. In fact font() returns what + you set using setFont() and fontInfo() returns the font actually + being used (which may be the same). + + \i brush() is the currently set brush; the color or pattern that's + used for filling e.g. circles. + + \i pen() is the currently set pen; the color or stipple that's + used for drawing lines or boundaries. + + \i backgroundMode() is \c Opaque or \c Transparent, i.e. whether + backgroundColor() is used or not. + + \i backgroundColor() only applies when backgroundMode() is Opaque + and pen() is a stipple. In that case, it describes the color of + the background pixels in the stipple. + + \i rasterOp() is how pixels drawn interact with the pixels already + there. + + \i brushOrigin() is the origin of the tiled brushes, normally the + origin of the window. + + \i viewport(), window(), worldMatrix() and many more make up the + painter's coordinate transformation system. See \link + coordsys.html The Coordinate System \endlink for an explanation of + this, or see below for a very brief overview of the functions. + + \i hasClipping() is whether the painter clips at all. (The paint + device clips, too.) If the painter clips, it clips to clipRegion(). + + \i pos() is the current position, set by moveTo() and used by + lineTo(). + + \endlist + + Note that some of these settings mirror settings in some paint + devices, e.g. QWidget::font(). QPainter::begin() (or the QPainter + constructor) copies these attributes from the paint device. + Calling, for example, QWidget::setFont() doesn't take effect until + the next time a painter begins painting on it. + + save() saves all of these settings on an internal stack, restore() + pops them back. + + The core functionality of QPainter is drawing, and there are + functions to draw most primitives: drawPoint(), drawPoints(), + drawLine(), drawRect(), drawWinFocusRect(), drawRoundRect(), + drawEllipse(), drawArc(), drawPie(), drawChord(), + drawLineSegments(), drawPolyline(), drawPolygon(), + drawConvexPolygon() and drawCubicBezier(). All of these functions + take integer coordinates; there are no floating-point versions + since we want drawing to be as fast as possible. + + There are functions to draw pixmaps/images, namely drawPixmap(), + drawImage() and drawTiledPixmap(). drawPixmap() and drawImage() + produce the same result, except that drawPixmap() is faster + on-screen and drawImage() faster and sometimes better on QPrinter + and QPicture. + + Text drawing is done using drawText(), and when you need + fine-grained positioning, boundingRect() tells you where a given + drawText() command would draw. + + There is a drawPicture() function that draws the contents of an + entire QPicture using this painter. drawPicture() is the only + function that disregards all the painter's settings: the QPicture + has its own settings. + + Normally, the QPainter operates on the device's own coordinate + system (usually pixels), but QPainter has good support for + coordinate transformation. See \link coordsys.html The Coordinate + System \endlink for a more general overview and a simple example. + + The most common functions used are scale(), rotate(), translate() + and shear(), all of which operate on the worldMatrix(). + setWorldMatrix() can replace or add to the currently set + worldMatrix(). + + setViewport() sets the rectangle on which QPainter operates. The + default is the entire device, which is usually fine, except on + printers. setWindow() sets the coordinate system, that is, the + rectangle that maps to viewport(). What's drawn inside the + window() ends up being inside the viewport(). The window's + default is the same as the viewport, and if you don't use the + transformations, they are optimized away, gaining another little + bit of speed. + + After all the coordinate transformation is done, QPainter can clip + the drawing to an arbitrary rectangle or region. hasClipping() is + TRUE if QPainter clips, and clipRegion() returns the clip region. + You can set it using either setClipRegion() or setClipRect(). + Note that the clipping can be slow. It's all system-dependent, + but as a rule of thumb, you can assume that drawing speed is + inversely proportional to the number of rectangles in the clip + region. + + After QPainter's clipping, the paint device may also clip. For + example, most widgets clip away the pixels used by child widgets, + and most printers clip away an area near the edges of the paper. + This additional clipping is not reflected by the return value of + clipRegion() or hasClipping(). + + QPainter also includes some less-used functions that are very + useful on those occasions when they're needed. + + isActive() indicates whether the painter is active. begin() (and + the most usual constructor) makes it active. end() (and the + destructor) deactivates it. If the painter is active, device() + returns the paint device on which the painter paints. + + Sometimes it is desirable to make someone else paint on an unusual + QPaintDevice. QPainter supports a static function to do this, + redirect(). We recommend not using it, but for some hacks it's + perfect. + + setTabStops() and setTabArray() can change where the tab stops + are, but these are very seldomly used. + + \warning Note that QPainter does not attempt to work around + coordinate limitations in the underlying window system. Some + platforms may behave incorrectly with coordinates as small as + +/-4000. + + \headerfile qdrawutil.h + + \sa QPaintDevice QWidget QPixmap QPrinter QPicture + \link simple-application.html Application Walkthrough \endlink + \link coordsys.html Coordinate System Overview \endlink +*/ + +/*! + \fn QGfx * QPainter::internalGfx() + + \internal +*/ + +/*! + \enum QPainter::CoordinateMode + \value CoordDevice + \value CoordPainter + + \sa clipRegion() +*/ +/*! + \enum QPainter::TextDirection + \value Auto + \value RTL right to left + \value LTR left to right + + \sa drawText() +*/ + +/*! + \enum Qt::PaintUnit + \value PixelUnit + \value LoMetricUnit \e obsolete + \value HiMetricUnit \e obsolete + \value LoEnglishUnit \e obsolete + \value HiEnglishUnit \e obsolete + \value TwipsUnit \e obsolete +*/ + +/*! + \enum Qt::BrushStyle + + \value NoBrush + \value SolidPattern + \value Dense1Pattern + \value Dense2Pattern + \value Dense3Pattern + \value Dense4Pattern + \value Dense5Pattern + \value Dense6Pattern + \value Dense7Pattern + \value HorPattern + \value VerPattern + \value CrossPattern + \value BDiagPattern + \value FDiagPattern + \value DiagCrossPattern + \value CustomPattern + + \img brush-styles.png Brush Styles + +*/ + +/*! + \enum Qt::RasterOp + + This enum type is used to describe the way things are written to + the paint device. Each bit of the \e src (what you write) + interacts with the corresponding bit of the \e dst pixel. + + \value CopyROP dst = src + \value OrROP dst = src OR dst + \value XorROP dst = src XOR dst + \value NotAndROP dst = (NOT src) AND dst + \value EraseROP an alias for \c NotAndROP + \value NotCopyROP dst = NOT src + \value NotOrROP dst = (NOT src) OR dst + \value NotXorROP dst = (NOT src) XOR dst + \value AndROP dst = src AND dst + \value NotEraseROP an alias for \c AndROP + \value NotROP dst = NOT dst + \value ClearROP dst = 0 + \value SetROP dst = 1 + \value NopROP dst = dst + \value AndNotROP dst = src AND (NOT dst) + \value OrNotROP dst = src OR (NOT dst) + \value NandROP dst = NOT (src AND dst) + \value NorROP dst = NOT (src OR dst) + + By far the most useful ones are \c CopyROP and \c XorROP. + + On Qt/Embedded, only \c CopyROP, \c XorROP, and \c NotROP are supported. +*/ + +/*! + \enum Qt::AlignmentFlags + + This enum type is used to describe alignment. It contains + horizontal and vertical flags. + + The horizontal flags are: + + \value AlignAuto Aligns according to the language. Left for most, + right for Arabic and Hebrew. + \value AlignLeft Aligns with the left edge. + \value AlignRight Aligns with the right edge. + \value AlignHCenter Centers horizontally in the available space. + \value AlignJustify Justifies the text in the available space. + Does not work for everything and may be interpreted as + AlignAuto in some cases. + + The vertical flags are: + + \value AlignTop Aligns with the top. + \value AlignBottom Aligns with the bottom. + \value AlignVCenter Centers vertically in the available space. + + You can use only one of the horizontal flags at a time. There is + one two-dimensional flag: + + \value AlignCenter Centers in both dimensions. + + You can use at most one horizontal and one vertical flag at a time. \c + AlignCenter counts as both horizontal and vertical. + + Masks: + + \value AlignHorizontal_Mask + \value AlignVertical_Mask + + Conflicting combinations of flags have undefined meanings. +*/ + +/*! + \enum Qt::TextFlags + + This enum type is used to define some modifier flags. Some of + these flags only make sense in the context of printing: + + \value SingleLine Treats all whitespace as spaces and prints just + one line. + \value DontClip If it's impossible to stay within the given bounds, + it prints outside. + \value ExpandTabs Makes the U+0009 (ASCII tab) character move to + the next tab stop. + \value ShowPrefix Displays the string "\&P" as <u>P</u> + (see QButton for an example). For an ampersand, use "\&\&". + \value WordBreak Breaks lines at appropriate points, e.g. at word + boundaries. + \value BreakAnywhere Breaks lines anywhere, even within words. + \value NoAccel Same as ShowPrefix but doesn't draw the underlines. + + You can use as many modifier flags as you want, except that \c + SingleLine and \c WordBreak cannot be combined. + + Flags that are inappropriate for a given use (e.g. ShowPrefix to + QGridLayout::addWidget()) are generally ignored. + +*/ + +/*! + \enum Qt::PenStyle + + This enum type defines the pen styles that can be drawn using + QPainter. The styles are + + \value NoPen no line at all. For example, QPainter::drawRect() + fills but does not draw any boundary line. + + \value SolidLine a simple line. + + \value DashLine dashes separated by a few pixels. + + \value DotLine dots separated by a few pixels. + + \value DashDotLine alternate dots and dashes. + + \value DashDotDotLine one dash, two dots, one dash, two dots. + + \value MPenStyle mask of the pen styles. + + \img pen-styles.png Pen Styles +*/ + +/*! + \enum Qt::PenCapStyle + + This enum type defines the pen cap styles supported by Qt, i.e. + the line end caps that can be drawn using QPainter. + + \value FlatCap a square line end that does not cover the end + point of the line. + \value SquareCap a square line end that covers the end point and + extends beyond it with half the line width. + \value RoundCap a rounded line end. + \value MPenCapStyle mask of the pen cap styles. + + \img pen-cap-styles.png Pen Cap Styles +*/ + +/*! + \enum Qt::PenJoinStyle + + This enum type defines the pen join styles supported by Qt, i.e. + which joins between two connected lines can be drawn using + QPainter. + + \value MiterJoin The outer edges of the lines are extended to + meet at an angle, and this area is filled. + \value BevelJoin The triangular notch between the two lines is filled. + \value RoundJoin A circular arc between the two lines is filled. + \value MPenJoinStyle mask of the pen join styles. + + \img pen-join-styles.png Pen Join Styles +*/ + +/*! + \enum Qt::BGMode + + Background mode + + \value TransparentMode + \value OpaqueMode +*/ + +/*! + Constructs a painter. + + Notice that all painter settings (setPen, setBrush etc.) are reset + to default values when begin() is called. + + \sa begin(), end() +*/ + +QPainter::QPainter() +{ + init(); +} + + +/*! + Constructs a painter that begins painting the paint device \a pd + immediately. Depending on the underlying graphic system the + painter will paint over children of the paintdevice if \a + unclipped is TRUE. + + This constructor is convenient for short-lived painters, e.g. in a + \link QWidget::paintEvent() paint event\endlink and should be used + only once. The constructor calls begin() for you and the QPainter + destructor automatically calls end(). + + Here's an example using begin() and end(): + \code + void MyWidget::paintEvent( QPaintEvent * ) + { + QPainter p; + p.begin( this ); + p.drawLine( ... ); // drawing code + p.end(); + } + \endcode + + The same example using this constructor: + \code + void MyWidget::paintEvent( QPaintEvent * ) + { + QPainter p( this ); + p.drawLine( ... ); // drawing code + } + \endcode + + Since the constructor cannot provide feedback when the initialization + of the painter failed you should rather use begin() and end() to paint + on external devices, e.g. printers. + + \sa begin(), end() +*/ + +QPainter::QPainter( const QPaintDevice *pd, bool unclipped ) +{ + init(); + if ( begin( pd, unclipped ) ) + flags |= CtorBegin; +} + + +/*! + Constructs a painter that begins painting the paint device \a pd + immediately, with the default arguments taken from \a + copyAttributes. The painter will paint over children of the paint + device if \a unclipped is TRUE (although this is not supported on + all platforms). + + \sa begin() +*/ + +QPainter::QPainter( const QPaintDevice *pd, + const QWidget *copyAttributes, bool unclipped ) +{ + init(); + if ( begin( pd, copyAttributes, unclipped ) ) + flags |= CtorBegin; +} + + +/*! + Destroys the painter. +*/ + +QPainter::~QPainter() +{ + if ( isActive() ) + end(); + else + killPStack(); + if ( tabarray ) // delete tab array + delete [] tabarray; +#ifndef QT_NO_TRANSFORMATIONS + if ( wm_stack ) + delete (QWMatrixStack *)wm_stack; +#endif + destroy(); +} + + +/*! + \overload bool QPainter::begin( const QPaintDevice *pd, const QWidget *copyAttributes, bool unclipped ) + + This version opens the painter on a paint device \a pd and sets + the initial pen, background color and font from \a copyAttributes, + painting over the paint device's children when \a unclipped is + TRUE. This is equivalent to: + + \code + QPainter p; + p.begin( pd ); + p.setPen( copyAttributes->foregroundColor() ); + p.setBackgroundColor( copyAttributes->backgroundColor() ); + p.setFont( copyAttributes->font() ); + \endcode + + This begin function is convenient for double buffering. When you + draw in a pixmap instead of directly in a widget (to later bitBlt + the pixmap into the widget) you will need to set the widget's + font etc. This function does exactly that. + + Example: + \code + void MyWidget::paintEvent( QPaintEvent * ) + { + QPixmap pm(size()); + QPainter p; + p.begin(&pm, this); + // ... potentially flickering paint operation ... + p.end(); + bitBlt(this, 0, 0, &pm); + } + \endcode + + \sa end() +*/ + +bool QPainter::begin( const QPaintDevice *pd, const QWidget *copyAttributes, bool unclipped ) +{ + if ( copyAttributes == 0 ) { +#if defined(QT_CHECK_NULL) + qWarning( "QPainter::begin: The widget to copy attributes from cannot " + "be null" ); +#endif + return FALSE; + } + if ( begin( pd, unclipped ) ) { + setPen( copyAttributes->foregroundColor() ); + setBackgroundColor( copyAttributes->backgroundColor() ); + setFont( copyAttributes->font() ); + return TRUE; + } + return FALSE; +} + + +/*! + \internal + Sets or clears a pointer flag. +*/ + +void QPainter::setf( uint b, bool v ) +{ + if ( v ) + setf( b ); + else + clearf( b ); +} + + +/*! + \fn bool QPainter::isActive() const + + Returns TRUE if the painter is active painting, i.e. begin() has + been called and end() has not yet been called; otherwise returns + FALSE. + + \sa QPaintDevice::paintingActive() +*/ + +/*! + \fn QPaintDevice *QPainter::device() const + + Returns the paint device on which this painter is currently + painting, or 0 if the painter is not active. + + \sa QPaintDevice::paintingActive() +*/ + + +struct QPState { // painter state + QFont font; + QPen pen; + QPoint curPt; + QBrush brush; + QColor bgc; + uchar bgm; + uchar rop; + QPoint bro; + QRect wr, vr; +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix wm; +#else + int xlatex; + int xlatey; +#endif + bool vxf; + bool wxf; + QRegion rgn; + bool clip; + int ts; + int *ta; + void* wm_stack; +}; + +//TODO lose the worldmatrix stack + +typedef QPtrStack<QPState> QPStateStack; + + +void QPainter::killPStack() +{ +#if defined(QT_CHECK_STATE) + if ( ps_stack && !((QPStateStack *)ps_stack)->isEmpty() ) + qWarning( "QPainter::killPStack: non-empty save/restore stack when " + "end() was called" ); +#endif + delete (QPStateStack *)ps_stack; + ps_stack = 0; +} + +/*! + Saves the current painter state (pushes the state onto a stack). A + save() must be followed by a corresponding restore(). end() + unwinds the stack. + + \sa restore() +*/ + +void QPainter::save() +{ + if ( testf(ExtDev) ) { + if ( testf(DirtyFont) ) + updateFont(); + if ( testf(DirtyPen) ) + updatePen(); + if ( testf(DirtyBrush) ) + updateBrush(); + pdev->cmd( QPaintDevice::PdcSave, this, 0 ); + } + QPStateStack *pss = (QPStateStack *)ps_stack; + if ( pss == 0 ) { + pss = new QPtrStack<QPState>; + Q_CHECK_PTR( pss ); + pss->setAutoDelete( TRUE ); + ps_stack = pss; + } + QPState *ps = new QPState; + Q_CHECK_PTR( ps ); + ps->font = cfont; + ps->pen = cpen; + ps->curPt = pos(); + ps->brush = cbrush; + ps->bgc = bg_col; + ps->bgm = bg_mode; + ps->rop = rop; + ps->bro = bro; +#ifndef QT_NO_TRANSFORMATIONS + ps->wr = QRect( wx, wy, ww, wh ); + ps->vr = QRect( vx, vy, vw, vh ); + ps->wm = wxmat; + ps->vxf = testf(VxF); + ps->wxf = testf(WxF); +#else + ps->xlatex = xlatex; + ps->xlatey = xlatey; +#endif + ps->rgn = crgn; + ps->clip = testf(ClipOn); + ps->ts = tabstops; + ps->ta = tabarray; + ps->wm_stack = wm_stack; + wm_stack = 0; + pss->push( ps ); +} + +/*! + Restores the current painter state (pops a saved state off the + stack). + + \sa save() +*/ + +void QPainter::restore() +{ + if ( testf(ExtDev) ) { + pdev->cmd( QPaintDevice::PdcRestore, this, 0 ); + if ( pdev->devType() == QInternal::Picture ) + block_ext = TRUE; + } + QPStateStack *pss = (QPStateStack *)ps_stack; + if ( pss == 0 || pss->isEmpty() ) { +#if defined(QT_CHECK_STATE) + qWarning( "QPainter::restore: Empty stack error" ); +#endif + return; + } + QPState *ps = pss->pop(); + bool hardRestore = testf(VolatileDC); + + if ( ps->font != cfont || hardRestore ) + setFont( ps->font ); + if ( ps->pen != cpen || hardRestore ) + setPen( ps->pen ); + if ( ps->brush != cbrush || hardRestore ) + setBrush( ps->brush ); + if ( ps->bgc != bg_col || hardRestore ) + setBackgroundColor( ps->bgc ); + if ( ps->bgm != bg_mode || hardRestore ) + setBackgroundMode( (BGMode)ps->bgm ); + if ( ps->rop != rop || hardRestore ) + setRasterOp( (RasterOp)ps->rop ); + if ( ps->bro != bro || hardRestore ) + setBrushOrigin( ps->bro ); +#ifndef QT_NO_TRANSFORMATIONS + QRect wr( wx, wy, ww, wh ); + QRect vr( vx, vy, vw, vh ); + if ( ps->wr != wr || hardRestore ) + setWindow( ps->wr ); + if ( ps->vr != vr || hardRestore ) + setViewport( ps->vr ); + if ( ps->wm != wxmat || hardRestore ) + setWorldMatrix( ps->wm ); + if ( ps->vxf != testf(VxF) || hardRestore ) + setViewXForm( ps->vxf ); + if ( ps->wxf != testf(WxF) || hardRestore ) + setWorldXForm( ps->wxf ); +#else + xlatex = ps->xlatex; + xlatey = ps->xlatey; + setf( VxF, xlatex || xlatey ); +#endif + if ( ps->curPt != pos() || hardRestore ) + moveTo( ps->curPt ); + if ( ps->rgn != crgn || hardRestore ) + setClipRegion( ps->rgn ); + if ( ps->clip != testf(ClipOn) || hardRestore ) + setClipping( ps->clip ); + tabstops = ps->ts; + tabarray = ps->ta; + +#ifndef QT_NO_TRANSFORMATIONS + if ( wm_stack ) + delete (QWMatrixStack *)wm_stack; + wm_stack = ps->wm_stack; +#endif + delete ps; + block_ext = FALSE; +} + +typedef QPtrDict<QPaintDevice> QPaintDeviceDict; +static QPaintDeviceDict *pdev_dict = 0; + +/*! + Redirects all paint commands for a paint device, \a pdev, to + another paint device, \a replacement, unless \a replacement is 0. + If \a replacement is 0, the redirection for \a pdev is removed. + + In general, you'll probably find calling QPixmap::grabWidget() or + QPixmap::grabWindow() is an easier solution. +*/ + +void QPainter::redirect( QPaintDevice *pdev, QPaintDevice *replacement ) +{ + if ( pdev_dict == 0 ) { + if ( replacement == 0 ) + return; + pdev_dict = new QPaintDeviceDict; + Q_CHECK_PTR( pdev_dict ); + } +#if defined(QT_CHECK_NULL) + if ( pdev == 0 ) + qWarning( "QPainter::redirect: The pdev argument cannot be 0" ); +#endif + if ( replacement ) { + pdev_dict->insert( pdev, replacement ); + } else { + pdev_dict->remove( pdev ); + if ( pdev_dict->count() == 0 ) { + delete pdev_dict; + pdev_dict = 0; + } + } +} + +/*! + \internal + Returns the replacement for \a pdev, or 0 if there is no replacement. +*/ +QPaintDevice *QPainter::redirect( QPaintDevice *pdev ) +{ + return pdev_dict ? pdev_dict->find( pdev ) : 0; +} + +/*! + Returns the font metrics for the painter, if the painter is + active. It is not possible to obtain metrics for an inactive + painter, so the return value is undefined if the painter is not + active. + + \sa fontInfo(), isActive() +*/ + +QFontMetrics QPainter::fontMetrics() const +{ + if ( pdev && pdev->devType() == QInternal::Picture ) + return QFontMetrics( cfont ); + + return QFontMetrics(this); +} + +/*! + Returns the font info for the painter, if the painter is active. + It is not possible to obtain font information for an inactive + painter, so the return value is undefined if the painter is not + active. + + \sa fontMetrics(), isActive() +*/ + +QFontInfo QPainter::fontInfo() const +{ + if ( pdev && pdev->devType() == QInternal::Picture ) + return QFontInfo( cfont ); + + return QFontInfo(this); +} + + +/*! + \fn const QPen &QPainter::pen() const + + Returns the painter's current pen. + + \sa setPen() +*/ + +/*! + Sets a new painter pen. + + The \a pen defines how to draw lines and outlines, and it also + defines the text color. + + \sa pen() +*/ + +void QPainter::setPen( const QPen &pen ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setPen: Will be reset by begin()" ); +#endif + if ( cpen == pen ) + return; + cpen = pen; + updatePen(); +} + +/*! + \overload + + Sets the painter's pen to have style \a style, width 0 and black + color. + + \sa pen(), QPen +*/ + +void QPainter::setPen( PenStyle style ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setPen: Will be reset by begin()" ); +#endif + QPen::QPenData *d = cpen.data; // low level access + if ( d->style == style && d->linest == style && !d->width && d->color == Qt::black ) + return; + if ( d->count != 1 ) { + cpen.detach(); + d = cpen.data; + } + d->style = style; + d->width = 0; + d->color = Qt::black; + d->linest = style; + updatePen(); +} + +/*! + \overload + + Sets the painter's pen to have style \c SolidLine, width 0 and the + specified \a color. + + \sa pen(), QPen +*/ + +void QPainter::setPen( const QColor &color ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setPen: Will be reset by begin()" ); +#endif + QPen::QPenData *d = cpen.data; // low level access + if ( d->color == color && !d->width && d->style == SolidLine && d->linest == SolidLine ) + return; + if ( d->count != 1 ) { + cpen.detach(); + d = cpen.data; + } + d->style = SolidLine; + d->width = 0; + d->color = color; + d->linest = SolidLine; + updatePen(); +} + +/*! + \fn const QBrush &QPainter::brush() const + + Returns the painter's current brush. + + \sa QPainter::setBrush() +*/ + +/*! + \overload + + Sets the painter's brush to \a brush. + + The \a brush defines how shapes are filled. + + \sa brush() +*/ + +void QPainter::setBrush( const QBrush &brush ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setBrush: Will be reset by begin()" ); +#endif + if ( cbrush == brush ) + return; + cbrush = brush; + updateBrush(); +} + +/*! + Sets the painter's brush to black color and the specified \a + style. + + \sa brush(), QBrush +*/ + +void QPainter::setBrush( BrushStyle style ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setBrush: Will be reset by begin()" ); +#endif + QBrush::QBrushData *d = cbrush.data; // low level access + if ( d->style == style && d->color == Qt::black && !d->pixmap ) + return; + if ( d->count != 1 ) { + cbrush.detach(); + d = cbrush.data; + } + d->style = style; + d->color = Qt::black; + if ( d->pixmap ) { + delete d->pixmap; + d->pixmap = 0; + } + updateBrush(); +} + +/*! + \overload + + Sets the painter's brush to have style \c SolidPattern and the + specified \a color. + + \sa brush(), QBrush +*/ + +void QPainter::setBrush( const QColor &color ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setBrush: Will be reset by begin()" ); +#endif + QBrush::QBrushData *d = cbrush.data; // low level access + if ( d->color == color && d->style == SolidPattern && !d->pixmap ) + return; + if ( d->count != 1 ) { + cbrush.detach(); + d = cbrush.data; + } + d->style = SolidPattern; + d->color = color; + if ( d->pixmap ) { + delete d->pixmap; + d->pixmap = 0; + } + updateBrush(); +} + + +/*! + \fn const QColor &QPainter::backgroundColor() const + + Returns the current background color. + + \sa setBackgroundColor() QColor +*/ + +/*! + \fn BGMode QPainter::backgroundMode() const + + Returns the current background mode. + + \sa setBackgroundMode() BGMode +*/ + +/*! + \fn RasterOp QPainter::rasterOp() const + + Returns the current \link Qt::RasterOp raster operation \endlink. + + \sa setRasterOp() RasterOp +*/ + +/*! + \fn const QPoint &QPainter::brushOrigin() const + + Returns the brush origin currently set. + + \sa setBrushOrigin() +*/ + + +/*! + \fn int QPainter::tabStops() const + + Returns the tab stop setting. + + \sa setTabStops() +*/ + +/*! + Set the tab stop width to \a ts, i.e. locates tab stops at \a ts, + 2*\a ts, 3*\a ts and so on. + + Tab stops are used when drawing formatted text with \c ExpandTabs + set. This fixed tab stop value is used only if no tab array is set + (which is the default case). + + A value of 0 (the default) implies a tabstop setting of 8 times the width of the + character 'x' in the font currently set on the painter. + + \sa tabStops(), setTabArray(), drawText(), fontMetrics() +*/ + +void QPainter::setTabStops( int ts ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setTabStops: Will be reset by begin()" ); +#endif + tabstops = ts; + if ( isActive() && testf(ExtDev) ) { // tell extended device + QPDevCmdParam param[1]; + param[0].ival = ts; + pdev->cmd( QPaintDevice::PdcSetTabStops, this, param ); + } +} + +/*! + \fn int *QPainter::tabArray() const + + Returns the currently set tab stop array. + + \sa setTabArray() +*/ + +/*! + Sets the tab stop array to \a ta. This puts tab stops at \a ta[0], + \a ta[1] and so on. The array is null-terminated. + + If both a tab array and a tab top size is set, the tab array wins. + + \sa tabArray(), setTabStops(), drawText(), fontMetrics() +*/ + +void QPainter::setTabArray( int *ta ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setTabArray: Will be reset by begin()" ); +#endif + if ( ta != tabarray ) { + tabarraylen = 0; + if ( tabarray ) // Avoid purify complaint + delete [] tabarray; // delete old array + if ( ta ) { // tabarray = copy of 'ta' + while ( ta[tabarraylen] ) + tabarraylen++; + tabarraylen++; // and 0 terminator + tabarray = new int[tabarraylen]; // duplicate ta + memcpy( tabarray, ta, sizeof(int)*tabarraylen ); + } else { + tabarray = 0; + } + } + if ( isActive() && testf(ExtDev) ) { // tell extended device + QPDevCmdParam param[2]; + param[0].ival = tabarraylen; + param[1].ivec = tabarray; + pdev->cmd( QPaintDevice::PdcSetTabArray, this, param ); + } +} + + +/*! + \fn HANDLE QPainter::handle() const + + Returns the platform-dependent handle used for drawing. Using this + function is not portable. +*/ + + +/***************************************************************************** + QPainter xform settings + *****************************************************************************/ + +#ifndef QT_NO_TRANSFORMATIONS + +/*! + Enables view transformations if \a enable is TRUE, or disables + view transformations if \a enable is FALSE. + + \sa hasViewXForm(), setWindow(), setViewport(), setWorldMatrix(), + setWorldXForm(), xForm() +*/ + +void QPainter::setViewXForm( bool enable ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setViewXForm: Will be reset by begin()" ); +#endif + if ( !isActive() || enable == testf(VxF) ) + return; + setf( VxF, enable ); + if ( testf(ExtDev) ) { + QPDevCmdParam param[1]; + param[0].ival = enable; + pdev->cmd( QPaintDevice::PdcSetVXform, this, param ); + } + updateXForm(); +} + +/*! + \fn bool QPainter::hasViewXForm() const + + Returns TRUE if view transformation is enabled; otherwise returns + FALSE. + + \sa setViewXForm(), xForm() +*/ + +/*! + Returns the window rectangle. + + \sa setWindow(), setViewXForm() +*/ + +QRect QPainter::window() const +{ + return QRect( wx, wy, ww, wh ); +} + +/*! + Sets the window rectangle view transformation for the painter and + enables view transformation. + + The window rectangle is part of the view transformation. The + window specifies the logical coordinate system and is specified by + the \a x, \a y, \a w width and \a h height parameters. Its sister, + the viewport(), specifies the device coordinate system. + + The default window rectangle is the same as the device's + rectangle. See the \link coordsys.html Coordinate System Overview + \endlink for an overview of coordinate transformation. + + \sa window(), setViewport(), setViewXForm(), setWorldMatrix(), + setWorldXForm() +*/ + +void QPainter::setWindow( int x, int y, int w, int h ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setWindow: Will be reset by begin()" ); +#endif + wx = x; + wy = y; + ww = w; + wh = h; + if ( testf(ExtDev) ) { + QRect r( x, y, w, h ); + QPDevCmdParam param[1]; + param[0].rect = (QRect*)&r; + pdev->cmd( QPaintDevice::PdcSetWindow, this, param ); + } + if ( testf(VxF) ) + updateXForm(); + else + setViewXForm( TRUE ); +} + +/*! + Returns the viewport rectangle. + + \sa setViewport(), setViewXForm() +*/ + +QRect QPainter::viewport() const // get viewport +{ + return QRect( vx, vy, vw, vh ); +} + +/*! + Sets the viewport rectangle view transformation for the painter + and enables view transformation. + + The viewport rectangle is part of the view transformation. The + viewport specifies the device coordinate system and is specified + by the \a x, \a y, \a w width and \a h height parameters. Its + sister, the window(), specifies the logical coordinate system. + + The default viewport rectangle is the same as the device's + rectangle. See the \link coordsys.html Coordinate System Overview + \endlink for an overview of coordinate transformation. + + \sa viewport(), setWindow(), setViewXForm(), setWorldMatrix(), + setWorldXForm(), xForm() +*/ + +void QPainter::setViewport( int x, int y, int w, int h ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setViewport: Will be reset by begin()" ); +#endif + vx = x; + vy = y; + vw = w; + vh = h; + if ( testf(ExtDev) ) { + QRect r( x, y, w, h ); + QPDevCmdParam param[1]; + param[0].rect = (QRect*)&r; + pdev->cmd( QPaintDevice::PdcSetViewport, this, param ); + } + if ( testf(VxF) ) + updateXForm(); + else + setViewXForm( TRUE ); +} + + +/*! + Enables world transformations if \a enable is TRUE, or disables + world transformations if \a enable is FALSE. The world + transformation matrix is not changed. + + \sa setWorldMatrix(), setWindow(), setViewport(), setViewXForm(), + xForm() +*/ + +void QPainter::setWorldXForm( bool enable ) +{ +#if defined(QT_CHECK_STATE) + if ( !isActive() ) + qWarning( "QPainter::setWorldXForm: Will be reset by begin()" ); +#endif + if ( !isActive() || enable == testf(WxF) ) + return; + setf( WxF, enable ); + if ( testf(ExtDev) && !block_ext ) { + QPDevCmdParam param[1]; + param[0].ival = enable; + pdev->cmd( QPaintDevice::PdcSetWXform, this, param ); + } + updateXForm(); +} + +/*! + \fn bool QPainter::hasWorldXForm() const + + Returns TRUE if world transformation is enabled; otherwise returns + FALSE. + + \sa setWorldXForm() +*/ + +/*! + Returns the world transformation matrix. + + \sa setWorldMatrix() +*/ + +const QWMatrix &QPainter::worldMatrix() const +{ + return wxmat; +} + +/*! + Sets the world transformation matrix to \a m and enables world + transformation. + + If \a combine is TRUE, then \a m is combined with the current + transformation matrix, otherwise \a m replaces the current + transformation matrix. + + If \a m is the identity matrix and \a combine is FALSE, this + function calls setWorldXForm(FALSE). (The identity matrix is the + matrix where QWMatrix::m11() and QWMatrix::m22() are 1.0 and the + rest are 0.0.) + + World transformations are applied after the view transformations + (i.e. \link setWindow() window\endlink and \link setViewport() + viewport\endlink). + + The following functions can transform the coordinate system without using + a QWMatrix: + \list + \i translate() + \i scale() + \i shear() + \i rotate() + \endlist + + They operate on the painter's worldMatrix() and are implemented like this: + + \code + void QPainter::rotate( double a ) + { + QWMatrix m; + m.rotate( a ); + setWorldMatrix( m, TRUE ); + } + \endcode + + Note that you should always use \a combine when you are drawing + into a QPicture. Otherwise it may not be possible to replay the + picture with additional transformations. Using translate(), + scale(), etc., is safe. + + For a brief overview of coordinate transformation, see the \link + coordsys.html Coordinate System Overview. \endlink + + \sa worldMatrix() setWorldXForm() setWindow() setViewport() + setViewXForm() xForm() QWMatrix +*/ + +void QPainter::setWorldMatrix( const QWMatrix &m, bool combine ) +{ + if ( !isActive() ) { +#if defined(QT_CHECK_STATE) + qWarning( "QPainter::setWorldMatrix: Will be reset by begin()" ); +#endif + return; + } + if ( combine ) + wxmat = m * wxmat; // combines + else + wxmat = m; // set new matrix + bool identity = wxmat.m11() == 1.0F && wxmat.m22() == 1.0F && + wxmat.m12() == 0.0F && wxmat.m21() == 0.0F && + wxmat.dx() == 0.0F && wxmat.dy() == 0.0F; + if ( testf(ExtDev) && !block_ext ) { + QPDevCmdParam param[2]; + param[0].matrix = &m; + param[1].ival = combine; + pdev->cmd( QPaintDevice::PdcSetWMatrix, this, param ); + } + if ( identity && pdev->devType() != QInternal::Picture ) + setWorldXForm( FALSE ); + else if ( !testf(WxF) ) + setWorldXForm( TRUE ); + else + updateXForm(); +} + +/*! \obsolete + + We recommend using save() instead. +*/ + +void QPainter::saveWorldMatrix() +{ + QWMatrixStack *stack = (QWMatrixStack *)wm_stack; + if ( stack == 0 ) { + stack = new QPtrStack<QWMatrix>; + Q_CHECK_PTR( stack ); + stack->setAutoDelete( TRUE ); + wm_stack = stack; + } + + stack->push( new QWMatrix( wxmat ) ); + +} + +/*! \obsolete + We recommend using restore() instead. +*/ + +void QPainter::restoreWorldMatrix() +{ + QWMatrixStack *stack = (QWMatrixStack *)wm_stack; + if ( stack == 0 || stack->isEmpty() ) { +#if defined(QT_CHECK_STATE) + qWarning( "QPainter::restoreWorldMatrix: Empty stack error" ); +#endif + return; + } + QWMatrix* m = stack->pop(); + setWorldMatrix( *m ); + delete m; +} + +#endif // QT_NO_TRANSFORMATIONS + +/*! + Translates the coordinate system by \a (dx, dy). After this call, + \a (dx, dy) is added to points. + + For example, the following code draws the same point twice: + \code + void MyWidget::paintEvent() + { + QPainter paint( this ); + + paint.drawPoint( 0, 0 ); + + paint.translate( 100.0, 40.0 ); + paint.drawPoint( -100, -40 ); + } + \endcode + + \sa scale(), shear(), rotate(), resetXForm(), setWorldMatrix(), xForm() +*/ + +void QPainter::translate( double dx, double dy ) +{ +#ifndef QT_NO_TRANSFORMATIONS + QWMatrix m; + m.translate( dx, dy ); + setWorldMatrix( m, TRUE ); +#else + xlatex += (int)dx; + xlatey += (int)dy; + setf( VxF, xlatex || xlatey ); +#endif +} + + +#ifndef QT_NO_TRANSFORMATIONS +/*! + Scales the coordinate system by \a (sx, sy). + + \sa translate(), shear(), rotate(), resetXForm(), setWorldMatrix(), + xForm() +*/ + +void QPainter::scale( double sx, double sy ) +{ + QWMatrix m; + m.scale( sx, sy ); + setWorldMatrix( m, TRUE ); +} + +/*! + Shears the coordinate system by \a (sh, sv). + + \sa translate(), scale(), rotate(), resetXForm(), setWorldMatrix(), + xForm() +*/ + +void QPainter::shear( double sh, double sv ) +{ + QWMatrix m; + m.shear( sv, sh ); + setWorldMatrix( m, TRUE ); +} + +/*! + Rotates the coordinate system \a a degrees counterclockwise. + + \sa translate(), scale(), shear(), resetXForm(), setWorldMatrix(), + xForm() +*/ + +void QPainter::rotate( double a ) +{ + QWMatrix m; + m.rotate( a ); + setWorldMatrix( m, TRUE ); +} + + +/*! + Resets any transformations that were made using translate(), scale(), + shear(), rotate(), setWorldMatrix(), setViewport() and + setWindow(). + + \sa worldMatrix(), viewport(), window() +*/ + +void QPainter::resetXForm() +{ + if ( !isActive() ) + return; + wx = wy = vx = vy = 0; // default view origins + ww = vw = pdev->metric( QPaintDeviceMetrics::PdmWidth ); + wh = vh = pdev->metric( QPaintDeviceMetrics::PdmHeight ); + wxmat = QWMatrix(); + setWorldXForm( FALSE ); + setViewXForm( FALSE ); +} + +/*! + \internal + Updates an internal integer transformation matrix. +*/ + +void QPainter::updateXForm() +{ + QWMatrix m; + if ( testf(VxF) ) { + double scaleW = (double)vw/(double)ww; + double scaleH = (double)vh/(double)wh; + m.setMatrix( scaleW, 0, 0, scaleH, vx - wx*scaleW, vy - wy*scaleH ); + } + if ( testf(WxF) ) { + if ( testf(VxF) ) + m = wxmat * m; + else + m = wxmat; + } + xmat = m; + + txinv = FALSE; // no inverted matrix + txop = TxNone; + if ( m12()==0.0 && m21()==0.0 && m11() >= 0.0 && m22() >= 0.0 ) { + if ( m11()==1.0 && m22()==1.0 ) { + if ( dx()!=0.0 || dy()!=0.0 ) + txop = TxTranslate; + } else { + txop = TxScale; +#if defined(Q_WS_WIN) + setf(DirtyFont); +#endif + } + } else { + txop = TxRotShear; +#if defined(Q_WS_WIN) + setf(DirtyFont); +#endif + } +} + + +/*! + \internal + Updates an internal integer inverse transformation matrix. +*/ + +void QPainter::updateInvXForm() +{ +#if defined(QT_CHECK_STATE) + Q_ASSERT( txinv == FALSE ); +#endif + txinv = TRUE; // creating inverted matrix + bool invertible; + QWMatrix m; + if ( testf(VxF) ) { + m.translate( vx, vy ); + m.scale( 1.0*vw/ww, 1.0*vh/wh ); + m.translate( -wx, -wy ); + } + if ( testf(WxF) ) { + if ( testf(VxF) ) + m = wxmat * m; + else + m = wxmat; + } + ixmat = m.invert( &invertible ); // invert matrix +} + +#else +void QPainter::resetXForm() +{ + xlatex = 0; + xlatey = 0; + clearf( VxF ); +} +#endif // QT_NO_TRANSFORMATIONS + + +extern bool qt_old_transformations; + +/*! + \internal + Maps a point from logical coordinates to device coordinates. +*/ + +void QPainter::map( int x, int y, int *rx, int *ry ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( qt_old_transformations ) { + switch ( txop ) { + case TxNone: + *rx = x; *ry = y; + break; + case TxTranslate: + // #### "Why no rounding here?", Warwick asked of Haavard. + *rx = int(x + dx()); + *ry = int(y + dy()); + break; + case TxScale: { + double tx = m11()*x + dx(); + double ty = m22()*y + dy(); + *rx = tx >= 0 ? int(tx + 0.5) : int(tx - 0.5); + *ry = ty >= 0 ? int(ty + 0.5) : int(ty - 0.5); + } break; + default: { + double tx = m11()*x + m21()*y+dx(); + double ty = m12()*x + m22()*y+dy(); + *rx = tx >= 0 ? int(tx + 0.5) : int(tx - 0.5); + *ry = ty >= 0 ? int(ty + 0.5) : int(ty - 0.5); + } break; + } + } else { + switch ( txop ) { + case TxNone: + *rx = x; + *ry = y; + break; + case TxTranslate: + *rx = qRound( x + dx() ); + *ry = qRound( y + dy() ); + break; + case TxScale: + *rx = qRound( m11()*x + dx() ); + *ry = qRound( m22()*y + dy() ); + break; + default: + *rx = qRound( m11()*x + m21()*y+dx() ); + *ry = qRound( m12()*x + m22()*y+dy() ); + break; + } + } +#else + *rx = x + xlatex; + *ry = y + xlatey; +#endif +} + +/*! + \internal + Maps a rectangle from logical coordinates to device coordinates. + This internal function does not handle rotation and/or shear. +*/ + +void QPainter::map( int x, int y, int w, int h, + int *rx, int *ry, int *rw, int *rh ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( qt_old_transformations ) { + switch ( txop ) { + case TxNone: + *rx = x; *ry = y; + *rw = w; *rh = h; + break; + case TxTranslate: + // #### "Why no rounding here?", Warwick asked of Haavard. + *rx = int(x + dx()); + *ry = int(y + dy()); + *rw = w; *rh = h; + break; + case TxScale: { + double tx1 = m11()*x + dx(); + double ty1 = m22()*y + dy(); + double tx2 = m11()*(x + w - 1) + dx(); + double ty2 = m22()*(y + h - 1) + dy(); + *rx = qRound( tx1 ); + *ry = qRound( ty1 ); + *rw = qRound( tx2 ) - *rx + 1; + *rh = qRound( ty2 ) - *ry + 1; + } break; + default: +#if defined(QT_CHECK_STATE) + qWarning( "QPainter::map: Internal error" ); +#endif + break; + } + } else { + switch ( txop ) { + case TxNone: + *rx = x; *ry = y; + *rw = w; *rh = h; + break; + case TxTranslate: + *rx = qRound(x + dx() ); + *ry = qRound(y + dy() ); + *rw = w; *rh = h; + break; + case TxScale: + *rx = qRound( m11()*x + dx() ); + *ry = qRound( m22()*y + dy() ); + *rw = qRound( m11()*w ); + *rh = qRound( m22()*h ); + break; + default: +#if defined(QT_CHECK_STATE) + qWarning( "QPainter::map: Internal error" ); +#endif + break; + } + } +#else + *rx = x + xlatex; + *ry = y + xlatey; + *rw = w; *rh = h; +#endif +} + +/*! + \internal + Maps a point from device coordinates to logical coordinates. +*/ + +void QPainter::mapInv( int x, int y, int *rx, int *ry ) const +{ +#ifndef QT_NO_TRANSFORMATIONS +#if defined(QT_CHECK_STATE) + if ( !txinv ) + qWarning( "QPainter::mapInv: Internal error" ); +#endif + if ( qt_old_transformations ) { + double tx = im11()*x + im21()*y+idx(); + double ty = im12()*x + im22()*y+idy(); + *rx = tx >= 0 ? int(tx + 0.5) : int(tx - 0.5); + *ry = ty >= 0 ? int(ty + 0.5) : int(ty - 0.5); + } else { + *rx = qRound( im11()*x + im21()*y + idx() ); + *ry = qRound( im12()*x + im22()*y + idy() ); + } +#else + *rx = x - xlatex; + *ry = y - xlatey; +#endif +} + +/*! + \internal + Maps a rectangle from device coordinates to logical coordinates. + Cannot handle rotation and/or shear. +*/ + +void QPainter::mapInv( int x, int y, int w, int h, + int *rx, int *ry, int *rw, int *rh ) const +{ +#ifndef QT_NO_TRANSFORMATIONS +#if defined(QT_CHECK_STATE) + if ( !txinv || txop == TxRotShear ) + qWarning( "QPainter::mapInv: Internal error" ); +#endif + if ( qt_old_transformations ) { + double tx = im11()*x + idx(); + double ty = im22()*y + idy(); + double tw = im11()*w; + double th = im22()*h; + *rx = tx >= 0 ? int(tx + 0.5) : int(tx - 0.5); + *ry = ty >= 0 ? int(ty + 0.5) : int(ty - 0.5); + *rw = tw >= 0 ? int(tw + 0.5) : int(tw - 0.5); + *rh = th >= 0 ? int(th + 0.5) : int(th - 0.5); + } else { + *rx = qRound( im11()*x + idx() ); + *ry = qRound( im22()*y + idy() ); + *rw = qRound( im11()*w ); + *rh = qRound( im22()*h ); + } +#else + *rx = x - xlatex; + *ry = y - xlatey; + *rw = w; + *rh = h; +#endif +} + + +/*! + Returns the point \a pv transformed from model coordinates to + device coordinates. + + \sa xFormDev(), QWMatrix::map() +*/ + +QPoint QPainter::xForm( const QPoint &pv ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return pv; + int x=pv.x(), y=pv.y(); + map( x, y, &x, &y ); + return QPoint( x, y ); +#else + return QPoint( pv.x()+xlatex, pv.y()+xlatey ); +#endif +} + +/*! + \overload + + Returns the rectangle \a rv transformed from model coordinates to + device coordinates. + + If world transformation is enabled and rotation or shearing has + been specified, then the bounding rectangle is returned. + + \sa xFormDev(), QWMatrix::map() +*/ + +QRect QPainter::xForm( const QRect &rv ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return rv; + if ( txop == TxRotShear ) { // rotation/shear + return xmat.mapRect( rv ); + } + // Just translation/scale + int x, y, w, h; + rv.rect( &x, &y, &w, &h ); + map( x, y, w, h, &x, &y, &w, &h ); + return QRect( x, y, w, h ); +#else + return QRect( rv.x()+xlatex, rv.y()+xlatey, rv.width(), rv.height() ); +#endif +} + +/*! + \overload + + Returns the point array \a av transformed from model coordinates + to device coordinates. + + \sa xFormDev(), QWMatrix::map() +*/ + +QPointArray QPainter::xForm( const QPointArray &av ) const +{ + QPointArray a = av; +#ifndef QT_NO_TRANSFORMATIONS + if ( txop != TxNone ) + { + return xmat * av; + } +#else + a.translate( xlatex, xlatey ); +#endif + return a; +} + +/*! + \overload + + Returns the point array \a av transformed from model coordinates + to device coordinates. The \a index is the first point in the + array and \a npoints denotes the number of points to be + transformed. If \a npoints is negative, all points from \a + av[index] until the last point in the array are transformed. + + The returned point array consists of the number of points that + were transformed. + + Example: + \code + QPointArray a(10); + QPointArray b; + b = painter.xForm(a, 2, 4); // b.size() == 4 + b = painter.xForm(a, 2, -1); // b.size() == 8 + \endcode + + \sa xFormDev(), QWMatrix::map() +*/ + +QPointArray QPainter::xForm( const QPointArray &av, int index, + int npoints ) const +{ + int lastPoint = npoints < 0 ? av.size() : index+npoints; + QPointArray a( lastPoint-index ); + memcpy( a.data(), av.data()+index, (lastPoint-index)*sizeof( QPoint ) ); +#ifndef QT_NO_TRANSFORMATIONS + return xmat*a; +#else + a.translate( xlatex, xlatey ); + return a; +#endif +} + +/*! + \overload + + Returns the point \a pd transformed from device coordinates to + model coordinates. + + \sa xForm(), QWMatrix::map() +*/ + +QPoint QPainter::xFormDev( const QPoint &pd ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return pd; + if ( !txinv ) { + QPainter *that = (QPainter*)this; // mutable + that->updateInvXForm(); + } +#endif + int x=pd.x(), y=pd.y(); + mapInv( x, y, &x, &y ); + return QPoint( x, y ); +} + +/*! + Returns the rectangle \a rd transformed from device coordinates to + model coordinates. + + If world transformation is enabled and rotation or shearing is + used, then the bounding rectangle is returned. + + \sa xForm(), QWMatrix::map() +*/ + +QRect QPainter::xFormDev( const QRect &rd ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return rd; + if ( !txinv ) { + QPainter *that = (QPainter*)this; // mutable + that->updateInvXForm(); + } + if ( txop == TxRotShear ) { // rotation/shear + return ixmat.mapRect( rd ); + } +#endif + // Just translation/scale + int x, y, w, h; + rd.rect( &x, &y, &w, &h ); + mapInv( x, y, w, h, &x, &y, &w, &h ); + return QRect( x, y, w, h ); +} + +/*! + \overload + + Returns the point array \a ad transformed from device coordinates + to model coordinates. + + \sa xForm(), QWMatrix::map() +*/ + +QPointArray QPainter::xFormDev( const QPointArray &ad ) const +{ +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return ad; + if ( !txinv ) { + QPainter *that = (QPainter*)this; // mutable + that->updateInvXForm(); + } + return ixmat * ad; +#else + // ### + return ad; +#endif +} + +/*! + \overload + + Returns the point array \a ad transformed from device coordinates + to model coordinates. The \a index is the first point in the array + and \a npoints denotes the number of points to be transformed. If + \a npoints is negative, all points from \a ad[index] until the + last point in the array are transformed. + + The returned point array consists of the number of points that + were transformed. + + Example: + \code + QPointArray a(10); + QPointArray b; + b = painter.xFormDev(a, 1, 3); // b.size() == 3 + b = painter.xFormDev(a, 1, -1); // b.size() == 9 + \endcode + + \sa xForm(), QWMatrix::map() +*/ + +QPointArray QPainter::xFormDev( const QPointArray &ad, int index, + int npoints ) const +{ + int lastPoint = npoints < 0 ? ad.size() : index+npoints; + QPointArray a( lastPoint-index ); + memcpy( a.data(), ad.data()+index, (lastPoint-index)*sizeof( QPoint ) ); +#ifndef QT_NO_TRANSFORMATIONS + if ( txop == TxNone ) + return a; + if ( !txinv ) { + QPainter *that = (QPainter*)this; // mutable + that->updateInvXForm(); + } + return ixmat * a; +#else + // ### + return a; +#endif +} + + +/*! + Fills the rectangle \a (x, y, w, h) with the \a brush. + + You can specify a QColor as \a brush, since there is a QBrush + constructor that takes a QColor argument and creates a solid + pattern brush. + + \sa drawRect() +*/ + +void QPainter::fillRect( int x, int y, int w, int h, const QBrush &brush ) +{ + QPen oldPen = pen(); // save pen + QBrush oldBrush = this->brush(); // save brush + setPen( NoPen ); + setBrush( brush ); + drawRect( x, y, w, h ); // draw filled rect + setBrush( oldBrush ); // restore brush + setPen( oldPen ); // restore pen +} + + +/*! + \overload void QPainter::setBrushOrigin( const QPoint &p ) + + Sets the brush origin to point \a p. +*/ + +/*! + \overload void QPainter::setWindow( const QRect &r ) + + Sets the painter's window to rectangle \a r. +*/ + + +/*! + \overload void QPainter::setViewport( const QRect &r ) + + Sets the painter's viewport to rectangle \a r. +*/ + + +/*! + \fn bool QPainter::hasClipping() const + + Returns TRUE if clipping has been set; otherwise returns FALSE. + + \sa setClipping() +*/ + +/*! + Returns the currently set clip region. Note that the clip region + is given in physical device coordinates and \e not subject to any + \link coordsys.html coordinate transformation \endlink if \a m is + equal to \c CoordDevice (the default). If \a m equals \c + CoordPainter the returned region is in model coordinates. + + \sa setClipRegion(), setClipRect(), setClipping() QPainter::CoordinateMode +*/ +QRegion QPainter::clipRegion( CoordinateMode m ) const +{ + // ### FIXME in 4.0: + // If the transformation mode is CoordPainter, we should transform the + // clip region with painter transformations. + +#ifndef QT_NO_TRANSFORMATIONS + QRegion r; + if ( m == CoordDevice ) { + r = crgn; + } else { + if ( !txinv ) { + QPainter *that = (QPainter*)this; // mutable + that->updateInvXForm(); + } + + r = ixmat * crgn; + } + return r; +#else + return crgn; +#endif +} + +/*! + \fn void QPainter::setClipRect( int x, int y, int w, int h, CoordinateMode m) + + Sets the clip region to the rectangle \a x, \a y, \a w, \a h and + enables clipping. The clip mode is set to \a m. + + If \a m is \c CoordDevice (the default), the coordinates given for + the clip region are taken to be physical device coordinates and + are \e not subject to any \link coordsys.html coordinate + transformations\endlink. If \a m is \c CoordPainter, the + coordinates given for the clip region are taken to be model + coordinates. + + \sa setClipRegion(), clipRegion(), setClipping() QPainter::CoordinateMode +*/ + +/*! + \overload void QPainter::drawPoint( const QPoint &p ) + + Draws the point \a p. +*/ + + +/*! + \overload void QPainter::moveTo( const QPoint &p ) + + Moves to the point \a p. +*/ + +/*! + \overload void QPainter::lineTo( const QPoint &p ) + + Draws a line to the point \a p. +*/ + +/*! + \overload void QPainter::drawLine( const QPoint &p1, const QPoint &p2 ) + + Draws a line from point \a p1 to point \a p2. +*/ + +/*! + \overload void QPainter::drawRect( const QRect &r ) + + Draws the rectangle \a r. +*/ + +/*! + \overload void QPainter::drawWinFocusRect( const QRect &r ) + + Draws rectangle \a r as a window focus rectangle. +*/ + +/*! + \overload void QPainter::drawWinFocusRect( const QRect &r, const QColor &bgColor ) + + Draws rectangle \a r as a window focus rectangle using background + color \a bgColor. +*/ + + +#if !defined(Q_WS_X11) && !defined(Q_WS_QWS) && !defined(Q_WS_MAC) +// The doc and X implementation of this functions is in qpainter_x11.cpp +void QPainter::drawWinFocusRect( int, int, int, int, + bool, const QColor & ) +{ + // do nothing, only called from X11 specific functions +} +#endif + + +/*! + \overload void QPainter::drawRoundRect( const QRect &r, int xRnd, int yRnd ) + + Draws a rounded rectangle \a r, rounding to the x position \a xRnd + and the y position \a yRnd on each corner. +*/ + +/*! + \overload void QPainter::drawEllipse( const QRect &r ) + + Draws the ellipse that fits inside rectangle \a r. +*/ + +/*! + \overload void QPainter::drawArc( const QRect &r, int a, int alen ) + + Draws the arc that fits inside the rectangle \a r with start angle + \a a and arc length \a alen. +*/ + +/*! + \overload void QPainter::drawPie( const QRect &r, int a, int alen ) + + Draws a pie segment that fits inside the rectangle \a r with start + angle \a a and arc length \a alen. +*/ + +/*! + \overload void QPainter::drawChord( const QRect &r, int a, int alen ) + + Draws a chord that fits inside the rectangle \a r with start angle + \a a and arc length \a alen. +*/ + +/*! + \overload void QPainter::drawPixmap( const QPoint &p, const QPixmap &pm, const QRect &sr ) + + Draws the rectangle \a sr of pixmap \a pm with its origin at point + \a p. +*/ + +/*! + \overload void QPainter::drawPixmap( const QPoint &p, const QPixmap &pm ) + + Draws the pixmap \a pm with its origin at point \a p. +*/ + +void QPainter::drawPixmap( const QPoint &p, const QPixmap &pm ) +{ + drawPixmap( p.x(), p.y(), pm, 0, 0, pm.width(), pm.height() ); +} + +#if !defined(QT_NO_IMAGE_SMOOTHSCALE) || !defined(QT_NO_PIXMAP_TRANSFORMATION) + +/*! + \overload + + Draws the pixmap \a pm into the rectangle \a r. The pixmap is + scaled to fit the rectangle, if image and rectangle size disagree. +*/ +void QPainter::drawPixmap( const QRect &r, const QPixmap &pm ) +{ + int rw = r.width(); + int rh = r.height(); + int iw= pm.width(); + int ih = pm.height(); + if ( rw <= 0 || rh <= 0 || iw <= 0 || ih <= 0 ) + return; + bool scale = ( rw != iw || rh != ih ); + float scaleX = (float)rw/(float)iw; + float scaleY = (float)rh/(float)ih; + bool smooth = ( scaleX < 1.5 || scaleY < 1.5 ); + + if ( testf(ExtDev) ) { + QPDevCmdParam param[2]; + param[0].rect = &r; + param[1].pixmap = ± +#if defined(Q_WS_WIN) + if ( !pdev->cmd( QPaintDevice::PdcDrawPixmap, this, param ) || !hdc ) + return; +#elif defined(Q_WS_QWS) + pdev->cmd( QPaintDevice::PdcDrawPixmap, this, param ); + return; +#elif defined(Q_WS_MAC) + if ( !pdev->cmd( QPaintDevice::PdcDrawPixmap, this, param ) || !pdev->handle()) + return; +#else + if ( !pdev->cmd( QPaintDevice::PdcDrawPixmap, this, param ) || !hd ) + return; +#endif + } + + QPixmap pixmap = pm; + + if ( scale ) { +#ifndef QT_NO_IMAGE_SMOOTHSCALE +# ifndef QT_NO_PIXMAP_TRANSFORMATION + if ( smooth ) +# endif + { + QImage i = pm.convertToImage(); + pixmap = QPixmap( i.smoothScale( rw, rh ) ); + } +# ifndef QT_NO_PIXMAP_TRANSFORMATION + else +# endif +#endif +#ifndef QT_NO_PIXMAP_TRANSFORMATION + { + pixmap = pm.xForm( QWMatrix( scaleX, 0, 0, scaleY, 0, 0 ) ); + } +#endif + } + drawPixmap( r.x(), r.y(), pixmap ); +} + +#endif + +/*! + \overload void QPainter::drawImage( const QPoint &, const QImage &, const QRect &sr, int conversionFlags = 0 ); + + Draws the rectangle \a sr from the image at the given point. +*/ + +/* + Draws at point \a p the \sr rect from image \a pm, using \a + conversionFlags if the image needs to be converted to a pixmap. + The default value for \a conversionFlags is 0; see + convertFromImage() for information about what other values do. + + This function may convert \a image to a pixmap and then draw it, if + device() is a QPixmap or a QWidget, or else draw it directly, if + device() is a QPrinter or QPicture. +*/ + +/*! + Draws at (\a x, \a y) the \a sw by \a sh area of pixels from (\a + sx, \a sy) in \a image, using \a conversionFlags if the image + needs to be converted to a pixmap. The default value for \a + conversionFlags is 0; see convertFromImage() for information about + what other values do. + + This function may convert \a image to a pixmap and then draw it, + if device() is a QPixmap or a QWidget, or else draw it directly, + if device() is a QPrinter or QPicture. + + Currently alpha masks of the image are ignored when painting on a QPrinter. + + \sa drawPixmap() QPixmap::convertFromImage() +*/ +void QPainter::drawImage( int x, int y, const QImage & image, + int sx, int sy, int sw, int sh, + int conversionFlags ) +{ +#ifdef Q_WS_QWS + //### Hackish +# ifndef QT_NO_TRANSFORMATIONS + if ( !image.isNull() && gfx && + (txop==TxNone||txop==TxTranslate) && !testf(ExtDev) ) +# else + if ( !image.isNull() && gfx && !testf(ExtDev) ) +# endif + { + if(sw<0) + sw=image.width(); + if(sh<0) + sh=image.height(); + + QImage image2 = qt_screen->mapToDevice( image ); + + // This is a bit dubious + if(image2.depth()==1) { + image2.setNumColors( 2 ); + image2.setColor( 0, qRgb(255,255,255) ); + image2.setColor( 1, qRgb(0,0,0) ); + } + if ( image2.hasAlphaBuffer() ) + gfx->setAlphaType(QGfx::InlineAlpha); + else + gfx->setAlphaType(QGfx::IgnoreAlpha); + gfx->setSource(&image2); + if ( testf(VxF|WxF) ) { + map( x, y, &x, &y ); + } + gfx->blt(x,y,sw,sh,sx,sy); + return; + } +#endif + + if ( !isActive() || image.isNull() ) + return; + + // right/bottom + if ( sw < 0 ) + sw = image.width() - sx; + if ( sh < 0 ) + sh = image.height() - sy; + + // Sanity-check clipping + if ( sx < 0 ) { + x -= sx; + sw += sx; + sx = 0; + } + if ( sw + sx > image.width() ) + sw = image.width() - sx; + if ( sy < 0 ) { + y -= sy; + sh += sy; + sy = 0; + } + if ( sh + sy > image.height() ) + sh = image.height() - sy; + + if ( sw <= 0 || sh <= 0 ) + return; + + bool all = image.rect().intersect(QRect(sx,sy,sw,sh)) == image.rect(); + QImage subimage = all ? image : image.copy(sx,sy,sw,sh); + + if ( testf(ExtDev) ) { + QPDevCmdParam param[2]; + QRect r( x, y, subimage.width(), subimage.height() ); + param[0].rect = &r; + param[1].image = &subimage; +#if defined(Q_WS_WIN) + if ( !pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !hdc ) + return; +#elif defined (Q_WS_QWS) + pdev->cmd( QPaintDevice::PdcDrawImage, this, param ); + return; +#elif defined(Q_WS_MAC) + if(!pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !pdev->handle() ) + return; +#else + if ( !pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !hd ) + return; +#endif + } + + QPixmap pm; + pm.convertFromImage( subimage, conversionFlags ); + drawPixmap( x, y, pm ); +} + +/*! + \overload void QPainter::drawImage( const QPoint &p, const QImage &i, int conversion_flags ) + + Draws the image \a i at point \a p. + + If the image needs to be modified to fit in a lower-resolution + result (e.g. converting from 32-bit to 8-bit), use the \a + conversion_flags to specify how you'd prefer this to happen. + + \sa Qt::ImageConversionFlags +*/ +void QPainter::drawImage( const QPoint & p, const QImage & i, + int conversion_flags ) +{ + drawImage(p, i, i.rect(), conversion_flags); +} + +#if !defined(QT_NO_IMAGE_TRANSFORMATION) || !defined(QT_NO_IMAGE_SMOOTHSCALE) + +/*! + \overload + + Draws the image \a i into the rectangle \a r. The image will be + scaled to fit the rectangle if image and rectangle dimensions + differ. +*/ +void QPainter::drawImage( const QRect &r, const QImage &i ) +{ + int rw = r.width(); + int rh = r.height(); + int iw= i.width(); + int ih = i.height(); + if ( rw <= 0 || rh <= 0 || iw <= 0 || ih <= 0 ) + return; + + if ( testf(ExtDev) ) { + QPDevCmdParam param[2]; + param[0].rect = &r; + param[1].image = &i; +#if defined(Q_WS_WIN) + if ( !pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !hdc ) + return; +#elif defined(Q_WS_QWS) + pdev->cmd( QPaintDevice::PdcDrawImage, this, param ); + return; +#elif defined(Q_WS_MAC) + if ( !pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !pdev->handle() ) + return; +#else + if ( !pdev->cmd( QPaintDevice::PdcDrawImage, this, param ) || !hd ) + return; +#endif + } + + + bool scale = ( rw != iw || rh != ih ); + float scaleX = (float)rw/(float)iw; + float scaleY = (float)rh/(float)ih; + bool smooth = ( scaleX < 1.5 || scaleY < 1.5 ); + + QImage img = scale + ? ( +#if defined(QT_NO_IMAGE_TRANSFORMATION) + i.smoothScale( rw, rh ) +#elif defined(QT_NO_IMAGE_SMOOTHSCALE) + i.scale( rw, rh ) +#else + smooth ? i.smoothScale( rw, rh ) : i.scale( rw, rh ) +#endif + ) + : i; + + drawImage( r.x(), r.y(), img ); +} + +#endif + + +void bitBlt( QPaintDevice *dst, int dx, int dy, + const QImage *src, int sx, int sy, int sw, int sh, + int conversion_flags ) +{ + QPixmap tmp; + if ( sx == 0 && sy == 0 + && (sw<0 || sw==src->width()) && (sh<0 || sh==src->height()) ) + { + tmp.convertFromImage( *src, conversion_flags ); + } else { + tmp.convertFromImage( src->copy( sx, sy, sw, sh, conversion_flags), + conversion_flags ); + } + bitBlt( dst, dx, dy, &tmp ); +} + + +/*! + \overload void QPainter::drawTiledPixmap( const QRect &r, const QPixmap &pm, const QPoint &sp ) + + Draws a tiled pixmap, \a pm, inside rectangle \a r with its origin + at point \a sp. +*/ + +/*! + \overload void QPainter::drawTiledPixmap( const QRect &r, const QPixmap &pm ) + + Draws a tiled pixmap, \a pm, inside rectangle \a r. +*/ + +/*! + \overload void QPainter::fillRect( const QRect &r, const QBrush &brush ) + + Fills the rectangle \a r using brush \a brush. +*/ + +/*! + \fn void QPainter::eraseRect( int x, int y, int w, int h ) + + Erases the area inside \a x, \a y, \a w, \a h. Equivalent to + \c{fillRect( x, y, w, h, backgroundColor() )}. +*/ + +/*! + \overload void QPainter::eraseRect( const QRect &r ) + + Erases the area inside the rectangle \a r. +*/ + +/*! + \fn QPainter::drawText( int x, int y, const QString &, int len = -1, TextDirection dir = Auto ) + + \overload + + Draws the given text at position \a x, \a y. If \a len is -1 (the + default) all the text is drawn, otherwise the first \a len + characters are drawn. The text's direction is given by \a dir. + + \sa QPainter::TextDirection +*/ + +/*! + \fn void QPainter::drawText( int x, int y, int w, int h, int flags, + const QString&, int len = -1, QRect *br=0, + QTextParag **internal=0 ) + + \overload + + Draws the given text within the rectangle starting at \a x, \a y, + with width \a w and height \a h. If \a len is -1 (the default) all + the text is drawn, otherwise the first \a len characters are + drawn. The text's flags that are given in the \a flags parameter + are \l{Qt::AlignmentFlags} and \l{Qt::TextFlags} OR'd together. \a + br (if not null) is set to the actual bounding rectangle of the + output. The \a internal parameter is for internal use only. +*/ + +/*! + \fn void QPainter::drawText( const QPoint &, const QString &, int len = -1, TextDirection dir = Auto ); + + \overload + + Draws the text at the given point. + + \sa QPainter::TextDirection +*/ + +/* + Draws the text in \a s at point \a p. If \a len is -1 the entire + string is drawn, otherwise just the first \a len characters. The + text's direction is specified by \a dir. +*/ + + +/*! + \fn void QPainter::drawText( int x, int y, const QString &, int pos, int len, TextDirection dir = Auto ); + + \overload + + Draws the text from position \a pos, at point \a (x, y). If \a len is + -1 the entire string is drawn, otherwise just the first \a len + characters. The text's direction is specified by \a dir. +*/ + +/*! + \fn void QPainter::drawText( const QPoint &p, const QString &, int pos, int len, TextDirection dir = Auto ); + + Draws the text from position \a pos, at point \a p. If \a len is + -1 the entire string is drawn, otherwise just the first \a len + characters. The text's direction is specified by \a dir. + + Note that the meaning of \e y is not the same for the two + drawText() varieties. For overloads that take a simple \e x, \e y + pair (or a point), the \e y value is the text's baseline; for + overloads that take a rectangle, \e rect.y() is the top of the + rectangle and the text is aligned within that rectangle in + accordance with the alignment flags. + + \sa QPainter::TextDirection +*/ + +/*! + \fn void QPainter::drawTextItem(const QPoint &, const QTextItem &, int) + \internal +*/ + +static inline void fix_neg_rect( int *x, int *y, int *w, int *h ) +{ + if ( *w < 0 ) { + *w = -*w + 2; + *x -= *w - 1; + } + if ( *h < 0 ) { + *h = -*h + 2; + *y -= *h - 1; + } +} +void QPainter::fix_neg_rect( int *x, int *y, int *w, int *h ) +{ + ::fix_neg_rect(x,y,w,h); +} + +// +// The drawText function takes two special parameters; 'internal' and 'brect'. +// +// The 'internal' parameter contains a pointer to an array of encoded +// information that keeps internal geometry data. +// If the drawText function is called repeatedly to display the same text, +// it makes sense to calculate text width and linebreaks the first time, +// and use these parameters later to print the text because we save a lot of +// CPU time. +// The 'internal' parameter will not be used if it is a null pointer. +// The 'internal' parameter will be generated if it is not null, but points +// to a null pointer, i.e. internal != 0 && *internal == 0. +// The 'internal' parameter will be used if it contains a non-null pointer. +// +// If the 'brect parameter is a non-null pointer, then the bounding rectangle +// of the text will be returned in 'brect'. +// + +/*! + \overload + + Draws at most \a len characters from \a str in the rectangle \a r. + + This function draws formatted text. The \a tf text format is + really of type \l Qt::AlignmentFlags and \l Qt::TextFlags OR'd + together. + + Horizontal alignment defaults to AlignAuto and vertical alignment + defaults to AlignTop. + + \a brect (if not null) is set to the actual bounding rectangle of + the output. \a internal is, yes, internal. + + \sa boundingRect() +*/ + +void QPainter::drawText( const QRect &r, int tf, + const QString& str, int len, QRect *brect, + QTextParag **internal ) +{ + if ( !isActive() ) + return; + if ( len < 0 ) + len = str.length(); + if ( len == 0 ) // empty string + return; + + if ( testf(DirtyFont|ExtDev) ) { + if ( testf(DirtyFont) ) + updateFont(); + if ( testf(ExtDev) && (tf & DontPrint) == 0 ) { + QPDevCmdParam param[3]; + QString newstr = str; + newstr.truncate( len ); + param[0].rect = &r; + param[1].ival = tf; + param[2].str = &newstr; + if ( pdev->devType() != QInternal::Printer ) { +#if defined(Q_WS_WIN) + if ( !pdev->cmd( QPaintDevice::PdcDrawText2Formatted, + this, param) || + !hdc ) + return; // QPrinter wants PdcDrawText2 +#elif defined(Q_WS_QWS) + pdev->cmd( QPaintDevice::PdcDrawText2Formatted, this, param); + return; +#elif defined(Q_WS_MAC) + if ( !pdev->cmd( QPaintDevice::PdcDrawText2Formatted, this, param) || + !pdev->handle()) + return; // QPrinter wants PdcDrawText2 +#else + if ( !pdev->cmd( QPaintDevice::PdcDrawText2Formatted, + this, param) || + !hd ) + return; // QPrinter wants PdcDrawText2 +#endif + } + } + } + + qt_format_text(font(), r, tf, str, len, brect, + tabstops, tabarray, tabarraylen, internal, this); +} + +//#define QT_FORMAT_TEXT_DEBUG + +#define QChar_linesep QChar(0x2028U) + +void qt_format_text( const QFont& font, const QRect &_r, + int tf, const QString& str, int len, QRect *brect, + int tabstops, int* tabarray, int tabarraylen, + QTextParag **, QPainter* painter ) +{ + // we need to copy r here to protect against the case (&r == brect). + QRect r( _r ); + + bool dontclip = (tf & Qt::DontClip) == Qt::DontClip; + bool wordbreak = (tf & Qt::WordBreak) == Qt::WordBreak; + bool singleline = (tf & Qt::SingleLine) == Qt::SingleLine; + bool showprefix = (tf & Qt::ShowPrefix) == Qt::ShowPrefix; + bool noaccel = ( tf & Qt::NoAccel ) == Qt::NoAccel; + + bool isRightToLeft = str.isRightToLeft(); + if ( ( tf & Qt::AlignHorizontal_Mask ) == Qt::AlignAuto ) + tf |= isRightToLeft ? Qt::AlignRight : Qt::AlignLeft; + + bool expandtabs = ( (tf & Qt::ExpandTabs) && + ( ( (tf & Qt::AlignLeft) && !isRightToLeft ) || + ( (tf & Qt::AlignRight) && isRightToLeft ) ) ); + + if ( !painter ) + tf |= Qt::DontPrint; + + int maxUnderlines = 0; + int numUnderlines = 0; + int underlinePositionStack[32]; + int *underlinePositions = underlinePositionStack; + + QFont fnt(painter ? (painter->pfont ? *painter->pfont : painter->cfont) : font); + QFontMetrics fm( fnt ); + + QString text = str; + // str.setLength() always does a deep copy, so the replacement + // code below is safe. + text.setLength( len ); + // compatible behaviour to the old implementation. Replace + // tabs by spaces + QChar *chr = (QChar*)text.unicode(); + const QChar *end = chr + len; + bool haveLineSep = FALSE; + while ( chr != end ) { + if ( *chr == '\r' || ( singleline && *chr == '\n' ) ) { + *chr = ' '; + } else if ( *chr == '\n' ) { + *chr = QChar_linesep; + haveLineSep = TRUE; + } else if ( *chr == '&' ) { + ++maxUnderlines; + } + ++chr; + } + if ( !expandtabs ) { + chr = (QChar*)text.unicode(); + while ( chr != end ) { + if ( *chr == '\t' ) + *chr = ' '; + ++chr; + } + } else if (!tabarraylen && !tabstops) { + tabstops = fm.width('x')*8; + } + + if ( noaccel || showprefix ) { + if ( maxUnderlines > 32 ) + underlinePositions = new int[maxUnderlines]; + QChar *cout = (QChar*)text.unicode(); + QChar *cin = cout; + int l = len; + while ( l ) { + if ( *cin == '&' ) { + ++cin; + --l; + if ( !l ) + break; + if ( *cin != '&' ) + underlinePositions[numUnderlines++] = cout - text.unicode(); + } + *cout = *cin; + ++cout; + ++cin; + --l; + } + uint newlen = cout - text.unicode(); + if ( newlen != text.length()) + text.setLength( newlen ); + } + + // no need to do extra work for underlines if we don't paint + if ( tf & Qt::DontPrint ) + numUnderlines = 0; + + int height = 0; + int left = r.width(); + int right = 0; + + QTextLayout textLayout( text, fnt ); + int rb = QMAX( 0, -fm.minRightBearing() ); + int lb = QMAX( 0, -fm.minLeftBearing() ); + + if ( text.isEmpty() ) { + height = fm.height(); + left = right = 0; + tf |= QPainter::DontPrint; + } else { + textLayout.beginLayout((haveLineSep || expandtabs || wordbreak) ? + QTextLayout::MultiLine : + (tf & Qt::DontPrint) ? QTextLayout::NoBidi : QTextLayout::SingleLine ); + + // break underline chars into items of their own + for( int i = 0; i < numUnderlines; i++ ) { + textLayout.setBoundary( underlinePositions[i] ); + textLayout.setBoundary( underlinePositions[i]+1 ); + } + + int lineWidth = wordbreak ? QMAX(0, r.width()-rb-lb) : INT_MAX; + if(!wordbreak) + tf |= Qt::IncludeTrailingSpaces; + + int leading = fm.leading(); + int asc = fm.ascent(); + int desc = fm.descent(); + height = -leading; + + //qDebug("\n\nbeginLayout: lw = %d, rectwidth=%d", lineWidth , r.width()); + while ( !textLayout.atEnd() ) { + height += leading; + textLayout.beginLine( lineWidth == INT_MAX ? lineWidth : lineWidth ); + //qDebug("-----beginLine( %d )-----", lineWidth ); + bool linesep = FALSE; + while ( 1 ) { + QTextItem ti = textLayout.currentItem(); + //qDebug("item: from=%d, ch=%x", ti.from(), text.unicode()[ti.from()].unicode() ); + if ( expandtabs && ti.isTab() ) { + int tw = 0; + int x = textLayout.widthUsed(); + if ( tabarraylen ) { +// qDebug("tabarraylen=%d", tabarraylen ); + int tab = 0; + while ( tab < tabarraylen ) { + if ( tabarray[tab] > x ) { + tw = tabarray[tab] - x; + break; + } + ++tab; + } + } else { + tw = tabstops - (x % tabstops); + } + //qDebug("tw = %d", tw ); + if ( tw ) + ti.setWidth( tw ); + } + if ( ti.isObject() && text.unicode()[ti.from()] == QChar_linesep ) + linesep = TRUE; + + if ( linesep || textLayout.addCurrentItem() != QTextLayout::Ok || textLayout.atEnd() ) + break; + } + + int ascent = asc, descent = desc, lineLeft, lineRight; + textLayout.setLineWidth( r.width()-rb-lb ); + textLayout.endLine( 0, height, tf, &ascent, &descent, + &lineLeft, &lineRight ); + //qDebug("finalizing line: lw=%d ascent = %d, descent=%d lineleft=%d lineright=%d", lineWidth, ascent, descent,lineLeft, lineRight ); + left = QMIN( left, lineLeft ); + right = QMAX( right, lineRight ); + height += ascent + descent + 1; + if ( linesep ) + textLayout.nextItem(); + } + } + + int yoff = 0; + if ( tf & Qt::AlignBottom ) + yoff = r.height() - height; + else if ( tf & Qt::AlignVCenter ) + yoff = (r.height() - height)/2; + + if ( brect ) { + *brect = QRect( r.x() + left, r.y() + yoff, right-left + lb+rb, height ); + //qDebug("br = %d %d %d/%d, left=%d, right=%d", brect->x(), brect->y(), brect->width(), brect->height(), left, right); + } + + if (!(tf & QPainter::DontPrint)) { + bool restoreClipping = FALSE; + bool painterHasClip = FALSE; + QRegion painterClipRegion; + if ( !dontclip ) { +#ifndef QT_NO_TRANSFORMATIONS + QRegion reg = painter->xmat * r; +#else + QRegion reg = r; + reg.translate( painter->xlatex, painter->xlatey ); +#endif + if ( painter->hasClipping() ) + reg &= painter->clipRegion(); + + painterHasClip = painter->hasClipping(); + painterClipRegion = painter->clipRegion(); + restoreClipping = TRUE; + painter->setClipRegion( reg ); + } else { + if ( painter->hasClipping() ){ + painterHasClip = painter->hasClipping(); + painterClipRegion = painter->clipRegion(); + restoreClipping = TRUE; + painter->setClipping( FALSE ); + } + } + + int cUlChar = 0; + int _tf = 0; + if (fnt.underline()) _tf |= Qt::Underline; + if (fnt.overline()) _tf |= Qt::Overline; + if (fnt.strikeOut()) _tf |= Qt::StrikeOut; + + //qDebug("have %d items",textLayout.numItems()); + for ( int i = 0; i < textLayout.numItems(); i++ ) { + QTextItem ti = textLayout.itemAt( i ); + //qDebug("Item %d: from=%d, length=%d, space=%d x=%d", i, ti.from(), ti.length(), ti.isSpace(), ti.x() ); + if ( ti.isTab() || ti.isObject() ) + continue; + int textFlags = _tf; + if ( !noaccel && numUnderlines > cUlChar && ti.from() == underlinePositions[cUlChar] ) { + textFlags |= Qt::Underline; + cUlChar++; + } +#if defined(Q_WS_X11) || defined(Q_WS_QWS) + if ( painter->bg_mode == Qt::OpaqueMode ) { + int h = ti.ascent() + ti.descent() + 1; + if (ti.y() + h < height) + // don't add leading to last line + h += fm.leading(); + qt_draw_background( painter, r.x()+lb + ti.x(), r.y() + yoff + ti.y() - ti.ascent(), + ti.width(), h); + } +#endif + painter->drawTextItem( r.x()+lb, r.y() + yoff, ti, textFlags ); + } + + if ( restoreClipping ) { + painter->setClipRegion( painterClipRegion ); + painter->setClipping( painterHasClip ); + } + } + + if ( underlinePositions != underlinePositionStack ) + delete [] underlinePositions; +} + +/*! + \overload + + Returns the bounding rectangle of the aligned text that would be + printed with the corresponding drawText() function using the first + \a len characters from \a str if \a len is > -1, or the whole of + \a str if \a len is -1. The drawing, and hence the bounding + rectangle, is constrained to the rectangle \a r, or to the + rectangle required to draw the text, whichever is the larger. + + The \a internal parameter should not be used. + + \sa drawText(), fontMetrics(), QFontMetrics::boundingRect(), Qt::TextFlags +*/ + +QRect QPainter::boundingRect( const QRect &r, int flags, + const QString& str, int len, QTextParag **internal ) +{ + QRect brect; + if ( str.isEmpty() ) + brect.setRect( r.x(),r.y(), 0,0 ); + else + drawText( r, flags | DontPrint, str, len, &brect, internal ); + return brect; +} + +/*! + \fn QRect QPainter::boundingRect( int x, int y, int w, int h, int flags, const QString&, int len = -1, QTextParag **intern=0 ); + + Returns the bounding rectangle of the aligned text that would be + printed with the corresponding drawText() function using the first + \a len characters of the string if \a len is > -1, or the whole of + the string if \a len is -1. The drawing, and hence the bounding + rectangle, is constrained to the rectangle that begins at point \a + (x, y) with width \a w and hight \a h, or to the + rectangle required to draw the text, whichever is the larger. + + The \a flags argument is + the bitwise OR of the following flags: + \table + \header \i Flag \i Meaning + \row \i \c AlignAuto \i aligns according to the language, usually left. + \row \i \c AlignLeft \i aligns to the left border. + \row \i \c AlignRight \i aligns to the right border. + \row \i \c AlignHCenter \i aligns horizontally centered. + \row \i \c AlignTop \i aligns to the top border. + \row \i \c AlignBottom \i aligns to the bottom border. + \row \i \c AlignVCenter \i aligns vertically centered. + \row \i \c AlignCenter \i (== \c AlignHCenter | \c AlignVCenter). + \row \i \c SingleLine \i ignores newline characters in the text. + \row \i \c ExpandTabs \i expands tabs. + \row \i \c ShowPrefix \i interprets "&x" as "<u>x</u>". + \row \i \c WordBreak \i breaks the text to fit the rectangle. + \endtable + + Horizontal alignment defaults to \c AlignLeft and vertical + alignment defaults to \c AlignTop. + + If several of the horizontal or several of the vertical alignment flags + are set, the resulting alignment is undefined. + + The \a intern parameter should not be used. + + \sa Qt::TextFlags +*/ + + + +/***************************************************************************** + QPen member functions + *****************************************************************************/ + +/*! + \class QPen qpen.h + \brief The QPen class defines how a QPainter should draw lines and outlines + of shapes. + + \ingroup graphics + \ingroup images + \ingroup shared + \mainclass + + A pen has a style, width, color, cap style and join style. + + The pen style defines the line type. The default pen style is \c + Qt::SolidLine. Setting the style to \c NoPen tells the painter to + not draw lines or outlines. + + When drawing 1 pixel wide diagonal lines you can either use a very + fast algorithm (specified by a line width of 0, which is the + default), or a slower but more accurate algorithm (specified by a + line width of 1). For horizontal and vertical lines a line width + of 0 is the same as a line width of 1. The cap and join style have + no effect on 0-width lines. + + The pen color defines the color of lines and text. The default + line color is black. The QColor documentation lists predefined + colors. + + The cap style defines how the end points of lines are drawn. The + join style defines how the joins between two lines are drawn when + multiple connected lines are drawn (QPainter::drawPolyline() + etc.). The cap and join styles only apply to wide lines, i.e. when + the width is 1 or greater. + + Use the QBrush class to specify fill styles. + + Example: + \code + QPainter painter; + QPen pen( red, 2 ); // red solid line, 2 pixels wide + painter.begin( &anyPaintDevice ); // paint something + painter.setPen( pen ); // set the red, wide pen + painter.drawRect( 40,30, 200,100 ); // draw a rectangle + painter.setPen( blue ); // set blue pen, 0 pixel width + painter.drawLine( 40,30, 240,130 ); // draw a diagonal in rectangle + painter.end(); // painting done + \endcode + + See the \l Qt::PenStyle enum type for a complete list of pen + styles. + + With reference to the end points of lines, for wide (non-0-width) + pens it depends on the cap style whether the end point is drawn or + not. QPainter will try to make sure that the end point is drawn + for 0-width pens, but this cannot be absolutely guaranteed because + the underlying drawing engine is free to use any (typically + accelerated) algorithm for drawing 0-width lines. On all tested + systems, however, the end point of at least all non-diagonal lines + are drawn. + + A pen's color(), width(), style(), capStyle() and joinStyle() can + be set in the constructor or later with setColor(), setWidth(), + setStyle(), setCapStyle() and setJoinStyle(). Pens may also be + compared and streamed. + + \img pen-styles.png Pen styles + + \sa QPainter, QPainter::setPen() +*/ + + +/*! + \internal + Initializes the pen. +*/ + +void QPen::init( const QColor &color, uint width, uint linestyle ) +{ + data = new QPenData; + Q_CHECK_PTR( data ); + data->style = (PenStyle)(linestyle & MPenStyle); + data->width = width; + data->color = color; + data->linest = linestyle; +} + +/*! + Constructs a default black solid line pen with 0 width, which + renders lines 1 pixel wide (fast diagonals). +*/ + +QPen::QPen() +{ + init( Qt::black, 0, SolidLine ); // default pen +} + +/*! + Constructs a black pen with 0 width (fast diagonals) and style \a + style. + + \sa setStyle() +*/ + +QPen::QPen( PenStyle style ) +{ + init( Qt::black, 0, style ); +} + +/*! + Constructs a pen with the specified \a color, \a width and \a + style. + + \sa setWidth(), setStyle(), setColor() +*/ + +QPen::QPen( const QColor &color, uint width, PenStyle style ) +{ + init( color, width, style ); +} + +/*! + Constructs a pen with the specified color \a cl and width \a w. + The pen style is set to \a s, the pen cap style to \a c and the + pen join style to \a j. + + A line width of 0 will produce a 1 pixel wide line using a fast + algorithm for diagonals. A line width of 1 will also produce a 1 + pixel wide line, but uses a slower more accurate algorithm for + diagonals. For horizontal and vertical lines a line width of 0 is + the same as a line width of 1. The cap and join style have no + effect on 0-width lines. + + \sa setWidth(), setStyle(), setColor() +*/ + +QPen::QPen( const QColor &cl, uint w, PenStyle s, PenCapStyle c, + PenJoinStyle j ) +{ + init( cl, w, s | c | j ); +} + +/*! + Constructs a pen that is a copy of \a p. +*/ + +QPen::QPen( const QPen &p ) +{ + data = p.data; + data->ref(); +} + +/*! + Destroys the pen. +*/ + +QPen::~QPen() +{ + if ( data->deref() ) + delete data; +} + + +/*! + Detaches from shared pen data to make sure that this pen is the + only one referring the data. + + If multiple pens share common data, this pen dereferences the data + and gets a copy of the data. Nothing is done if there is just a + single reference. +*/ + +void QPen::detach() +{ + if ( data->count != 1 ) + *this = copy(); +} + + +/*! + Assigns \a p to this pen and returns a reference to this pen. +*/ + +QPen &QPen::operator=( const QPen &p ) +{ + p.data->ref(); + if ( data->deref() ) + delete data; + data = p.data; + return *this; +} + + +/*! + Returns a \link shclass.html deep copy\endlink of the pen. +*/ + +QPen QPen::copy() const +{ + QPen p( data->color, data->width, data->style, capStyle(), joinStyle() ); + return p; +} + + +/*! + \fn PenStyle QPen::style() const + + Returns the pen style. + + \sa setStyle() +*/ + +/*! + Sets the pen style to \a s. + + See the \l Qt::PenStyle documentation for a list of all the + styles. + + \warning On Mac OS X the style setting (other than \c NoPen and \c + SolidLine) have no effect as they are not implemented by the + underlying system. + + \warning On Windows 95/98, the style setting (other than \c NoPen + and \c SolidLine) has no effect for lines with width greater than + 1. + + \sa style() +*/ + +void QPen::setStyle( PenStyle s ) +{ + if ( data->style == s ) + return; + detach(); + data->style = s; + data->linest = (data->linest & ~MPenStyle) | s; +} + + +/*! + \fn uint QPen::width() const + + Returns the pen width. + + \sa setWidth() +*/ + +/*! + Sets the pen width to \a w. + + A line width of 0 will produce a 1 pixel wide line using a fast + algorithm for diagonals. A line width of 1 will also produce a 1 + pixel wide line, but uses a slower more accurate algorithm for + diagonals. For horizontal and vertical lines a line width of 0 is + the same as a line width of 1. The cap and join style have no + effect on 0-width lines. + + \sa width() +*/ + +void QPen::setWidth( uint w ) +{ + if ( data->width == w ) + return; + detach(); + data->width = w; +} + + +/*! + Returns the pen's cap style. + + \sa setCapStyle() +*/ +Qt::PenCapStyle QPen::capStyle() const +{ + return (PenCapStyle)(data->linest & MPenCapStyle); +} + +/*! + Sets the pen's cap style to \a c. + + The default value is \c FlatCap. The cap style has no effect on + 0-width pens. + + \img pen-cap-styles.png Pen Cap Styles + + \warning On Windows 95/98 and Macintosh, the cap style setting has + no effect. Wide lines are rendered as if the cap style was \c + SquareCap. + + \sa capStyle() +*/ + +void QPen::setCapStyle( PenCapStyle c ) +{ + if ( (data->linest & MPenCapStyle) == c ) + return; + detach(); + data->linest = (data->linest & ~MPenCapStyle) | c; +} + +/*! + Returns the pen's join style. + + \sa setJoinStyle() +*/ +Qt::PenJoinStyle QPen::joinStyle() const +{ + return (PenJoinStyle)(data->linest & MPenJoinStyle); +} + +/*! + Sets the pen's join style to \a j. + + The default value is \c MiterJoin. The join style has no effect on + 0-width pens. + + \img pen-join-styles.png Pen Join Styles + + \warning On Windows 95/98 and Macintosh, the join style setting + has no effect. Wide lines are rendered as if the join style was \c + BevelJoin. + + \sa joinStyle() +*/ + +void QPen::setJoinStyle( PenJoinStyle j ) +{ + if ( (data->linest & MPenJoinStyle) == j ) + return; + detach(); + data->linest = (data->linest & ~MPenJoinStyle) | j; +} + +/*! + \fn const QColor &QPen::color() const + + Returns the pen color. + + \sa setColor() +*/ + +/*! + Sets the pen color to \a c. + + \sa color() +*/ + +void QPen::setColor( const QColor &c ) +{ + detach(); + data->color = c; +} + + +/*! + \fn bool QPen::operator!=( const QPen &p ) const + + Returns TRUE if the pen is different from \a p; otherwise returns + FALSE. + + Two pens are different if they have different styles, widths or + colors. + + \sa operator==() +*/ + +/*! + Returns TRUE if the pen is equal to \a p; otherwise returns FALSE. + + Two pens are equal if they have equal styles, widths and colors. + + \sa operator!=() +*/ + +bool QPen::operator==( const QPen &p ) const +{ + return (p.data == data) || (p.data->linest == data->linest && + p.data->width == data->width && p.data->color == data->color); +} + + +/***************************************************************************** + QPen stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +/*! + \relates QPen + + Writes the pen \a p to the stream \a s and returns a reference to + the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QPen &p ) +{ + // ### width() should not be restricted to 8-bit values + if ( s.version() < 3 ) + return s << (Q_UINT8)p.style() << (Q_UINT8)p.width() << p.color(); + else + return s << (Q_UINT8)( p.style() | p.capStyle() | p.joinStyle() ) + << (Q_UINT8)p.width() << p.color(); +} + +/*! + \relates QPen + + Reads a pen from the stream \a s into \a p and returns a reference + to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QPen &p ) +{ + Q_UINT8 style, width; + QColor color; + s >> style; + s >> width; + s >> color; + p = QPen( color, (uint)width, (Qt::PenStyle)style ); // owl + return s; +} +#endif //QT_NO_DATASTREAM + +/***************************************************************************** + QBrush member functions + *****************************************************************************/ + +/*! + \class QBrush qbrush.h + + \brief The QBrush class defines the fill pattern of shapes drawn by a QPainter. + + \ingroup graphics + \ingroup images + \ingroup shared + + A brush has a style and a color. One of the brush styles is a + custom pattern, which is defined by a QPixmap. + + The brush style defines the fill pattern. The default brush style + is \c NoBrush (depending on how you construct a brush). This style + tells the painter to not fill shapes. The standard style for + filling is \c SolidPattern. + + The brush color defines the color of the fill pattern. The QColor + documentation lists the predefined colors. + + Use the QPen class for specifying line/outline styles. + + Example: + \code + QPainter painter; + QBrush brush( yellow ); // yellow solid pattern + painter.begin( &anyPaintDevice ); // paint something + painter.setBrush( brush ); // set the yellow brush + painter.setPen( NoPen ); // do not draw outline + painter.drawRect( 40,30, 200,100 ); // draw filled rectangle + painter.setBrush( NoBrush ); // do not fill + painter.setPen( black ); // set black pen, 0 pixel width + painter.drawRect( 10,10, 30,20 ); // draw rectangle outline + painter.end(); // painting done + \endcode + + See the setStyle() function for a complete list of brush styles. + + \img brush-styles.png Brush Styles + + \sa QPainter, QPainter::setBrush(), QPainter::setBrushOrigin() +*/ + + +/*! + \internal + Initializes the brush. +*/ + +void QBrush::init( const QColor &color, BrushStyle style ) +{ + data = new QBrushData; + Q_CHECK_PTR( data ); + data->style = style; + data->color = color; + data->pixmap = 0; +} + +/*! + Constructs a default black brush with the style \c NoBrush (will + not fill shapes). +*/ + +QBrush::QBrush() +{ + static QBrushData* defBrushData = 0; + if ( !defBrushData ) { + static QSharedCleanupHandler<QBrushData> defBrushCleanup; + defBrushData = new QBrushData; + defBrushData->style = NoBrush; + defBrushData->color = Qt::black; + defBrushData->pixmap = 0; + defBrushCleanup.set( &defBrushData ); + } + data = defBrushData; + data->ref(); +} + +/*! + Constructs a black brush with the style \a style. + + \sa setStyle() +*/ + +QBrush::QBrush( BrushStyle style ) +{ + init( Qt::black, style ); +} + +/*! + Constructs a brush with the color \a color and the style \a style. + + \sa setColor(), setStyle() +*/ + +QBrush::QBrush( const QColor &color, BrushStyle style ) +{ + init( color, style ); +} + +/*! + Constructs a brush with the color \a color and a custom pattern + stored in \a pixmap. + + The color will only have an effect for monochrome pixmaps, i.e. + for QPixmap::depth() == 1. + + Pixmap brushes are currently not supported when printing on X11. + + \sa setColor(), setPixmap() +*/ + +QBrush::QBrush( const QColor &color, const QPixmap &pixmap ) +{ + init( color, CustomPattern ); + setPixmap( pixmap ); +} + +/*! + Constructs a brush that is a \link shclass.html shallow + copy\endlink of \a b. +*/ + +QBrush::QBrush( const QBrush &b ) +{ + data = b.data; + data->ref(); +} + +/*! + Destroys the brush. +*/ + +QBrush::~QBrush() +{ + if ( data->deref() ) { + delete data->pixmap; + delete data; + } +} + + +/*! + Detaches from shared brush data to make sure that this brush is + the only one referring the data. + + If multiple brushes share common data, this brush dereferences the + data and gets a copy of the data. Nothing is done if there is just + a single reference. +*/ + +void QBrush::detach() +{ + if ( data->count != 1 ) + *this = copy(); +} + + +/*! + Assigns \a b to this brush and returns a reference to this brush. +*/ + +QBrush &QBrush::operator=( const QBrush &b ) +{ + b.data->ref(); // beware of b = b + if ( data->deref() ) { + delete data->pixmap; + delete data; + } + data = b.data; + return *this; +} + + +/*! + Returns a \link shclass.html deep copy\endlink of the brush. +*/ + +QBrush QBrush::copy() const +{ + if ( data->style == CustomPattern ) { // brush has pixmap + QBrush b( data->color, *data->pixmap ); + return b; + } else { // brush has std pattern + QBrush b( data->color, data->style ); + return b; + } +} + + +/*! + \fn BrushStyle QBrush::style() const + + Returns the brush style. + + \sa setStyle() +*/ + +/*! + Sets the brush style to \a s. + + The brush styles are: + \table + \header \i Pattern \i Meaning + \row \i NoBrush \i will not fill shapes (default). + \row \i SolidPattern \i solid (100%) fill pattern. + \row \i Dense1Pattern \i11 94% fill pattern. + \row \i Dense2Pattern \i11 88% fill pattern. + \row \i Dense3Pattern \i11 63% fill pattern. + \row \i Dense4Pattern \i11 50% fill pattern. + \row \i Dense5Pattern \i11 37% fill pattern. + \row \i Dense6Pattern \i11 12% fill pattern. + \row \i Dense7Pattern \i11 6% fill pattern. + \row \i HorPattern \i horizontal lines pattern. + \row \i VerPattern \i vertical lines pattern. + \row \i CrossPattern \i crossing lines pattern. + \row \i BDiagPattern \i diagonal lines (directed /) pattern. + \row \i FDiagPattern \i diagonal lines (directed \) pattern. + \row \i DiagCrossPattern \i diagonal crossing lines pattern. + \row \i CustomPattern \i set when a pixmap pattern is being used. + \endtable + + On Windows, dense and custom patterns cannot be transparent. + + See the \link #details Detailed Description\endlink for a picture + of all the styles. + + \sa style() +*/ + +void QBrush::setStyle( BrushStyle s ) // set brush style +{ + if ( data->style == s ) + return; +#if defined(QT_CHECK_RANGE) + if ( s == CustomPattern ) + qWarning( "QBrush::setStyle: CustomPattern is for internal use" ); +#endif + detach(); + data->style = s; +} + + +/*! + \fn const QColor &QBrush::color() const + + Returns the brush color. + + \sa setColor() +*/ + +/*! + Sets the brush color to \a c. + + \sa color(), setStyle() +*/ + +void QBrush::setColor( const QColor &c ) +{ + detach(); + data->color = c; +} + + +/*! + \fn QPixmap *QBrush::pixmap() const + + Returns a pointer to the custom brush pattern, or 0 if no custom + brush pattern has been set. + + \sa setPixmap() +*/ + +/*! + Sets the brush pixmap to \a pixmap. The style is set to \c + CustomPattern. + + The current brush color will only have an effect for monochrome + pixmaps, i.e. for QPixmap::depth() == 1. + + Pixmap brushes are currently not supported when printing on X11. + + \sa pixmap(), color() +*/ + +void QBrush::setPixmap( const QPixmap &pixmap ) +{ + detach(); + if ( data->pixmap ) + delete data->pixmap; + if ( pixmap.isNull() ) { + data->style = NoBrush; + data->pixmap = 0; + } else { + data->style = CustomPattern; + data->pixmap = new QPixmap( pixmap ); + if ( data->pixmap->optimization() == QPixmap::MemoryOptim ) + data->pixmap->setOptimization( QPixmap::NormalOptim ); + } +} + + +/*! + \fn bool QBrush::operator!=( const QBrush &b ) const + + Returns TRUE if the brush is different from \a b; otherwise + returns FALSE. + + Two brushes are different if they have different styles, colors or + pixmaps. + + \sa operator==() +*/ + +/*! + Returns TRUE if the brush is equal to \a b; otherwise returns + FALSE. + + Two brushes are equal if they have equal styles, colors and + pixmaps. + + \sa operator!=() +*/ + +bool QBrush::operator==( const QBrush &b ) const +{ + return (b.data == data) || (b.data->style == data->style && + b.data->color == data->color && + b.data->pixmap == data->pixmap); +} + + +/*! + \fn inline double QPainter::translationX() const + \internal +*/ + +/*! + \fn inline double QPainter::translationY() const + \internal +*/ + + +/***************************************************************************** + QBrush stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +/*! + \relates QBrush + + Writes the brush \a b to the stream \a s and returns a reference + to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QBrush &b ) +{ + s << (Q_UINT8)b.style() << b.color(); + if ( b.style() == Qt::CustomPattern ) +#ifndef QT_NO_IMAGEIO + s << *b.pixmap(); +#else + qWarning("No Image Brush I/O"); +#endif + return s; +} + +/*! + \relates QBrush + + Reads the brush \a b from the stream \a s and returns a reference + to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QBrush &b ) +{ + Q_UINT8 style; + QColor color; + s >> style; + s >> color; + if ( style == Qt::CustomPattern ) { +#ifndef QT_NO_IMAGEIO + QPixmap pm; + s >> pm; + b = QBrush( color, pm ); +#else + qWarning("No Image Brush I/O"); +#endif + } + else + b = QBrush( color, (Qt::BrushStyle)style ); + return s; +} +#endif // QT_NO_DATASTREAM |