#include "tqpainter.h" #ifdef USE_QT4 /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt3Support module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "tqpainter.h" #include "tqimage.h" #include "Qt/qpaintengine.h" // #include QT_BEGIN_NAMESPACE // TAKEN FROM QT4 qbrush.cpp // THIS BLOCK MAY NEED TO BE UPDATED FROM TIME TO TIME // BEGIN BLOCK struct QTexturedBrushData : public QBrushData { QTexturedBrushData() { m_has_pixmap_texture = false; m_pixmap = 0; } ~QTexturedBrushData() { delete m_pixmap; } void setPixmap(const QPixmap &pm) { delete m_pixmap; if (pm.isNull()) { m_pixmap = 0; m_has_pixmap_texture = false; } else { m_pixmap = new QPixmap(pm); m_has_pixmap_texture = true; } m_image = QImage(); } void setImage(const QImage &image) { m_image = image; delete m_pixmap; m_pixmap = 0; m_has_pixmap_texture = false; } QPixmap &pixmap() { if (!m_pixmap) { m_pixmap = new QPixmap(QPixmap::fromImage(m_image)); } return *m_pixmap; } QImage &image() { if (m_image.isNull() && m_pixmap) m_image = m_pixmap->toImage(); return m_image; } QPixmap *m_pixmap; QImage m_image; bool m_has_pixmap_texture; }; // END BLOCK /*! \class TQPainter \brief The TQPainter class is a Qt 3 compatibility wrapper for QPainter. \compat Prior to Qt 4, QPainter specialized the pen drawing for rectangle based functions (in particular: drawRect, drawEllipse, drawRoundRect, drawArc, drawChord and drawPie). When stroking a rectangle of width 10, the pen would draw a rectangle of width 10. Drawing a polygon defined by the corner points of the same rectangle the stroke would have a width of 11. The reason for this is best explained using the picture below: \img q3painter_rationale.png As we can see, stroking the rectangle so it gets a width of 10, means the pen is drawn on a rectangle on width 9. The polygon, however follows a consistent model. In Qt 4, all rectangle based functions have changed to follow the polygon approach, which means that the rectangle defines the size of the fill, and the pen follows the edges of the shape. For pen widths of 0 and 1 this means that the stroke will be inside the shape on the left and the top and outside on the bottom and right. The reason for the change in Qt 4 is so that we provide consistency for all drawing functions even with complex transformations. */ TQPainter::TQPainter() : QPainter(), has_qwidget(FALSE), current_penpos(0,0) { } TQPainter::TQPainter( const QWidget *pdev, bool unclipped) : QPainter((QWidget*)pdev), has_qwidget(TRUE), current_penpos(0,0) { qwidget_ptr = (QWidget*)pdev; if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } } TQPainter::TQPainter( QPaintDevice *pdev, bool unclipped) : QPainter(pdev), has_qwidget(FALSE), current_penpos(0,0) { if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } } TQPainter::TQPainter( QWidget *pdev, const QWidget *w, bool unclipped) : QPainter(pdev), has_qwidget(TRUE), current_penpos(0,0) { qwidget_ptr = pdev; initFrom(w); if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } } TQPainter::TQPainter( QPaintDevice *pdev, const QWidget *w, bool unclipped ) : QPainter(pdev), has_qwidget(FALSE), current_penpos(0,0) { initFrom(w); if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } } // [FIXME] void TQPainter::flush() { printf("[WARNING] void TQPainter::flush() unimplemented\n\r"); } // [FIXME] void TQPainter::flush( const TQRegion ®ion, TQPainter::CoordinateMode cm ) { printf("[WARNING] void TQPainter::flush( const TQRegion ®ion, CoordinateMode cm = CoordDevice ) unimplemented\n\r"); } void TQPainter::setBrush(const QBrush &brush) { return QPainter::setBrush(brush); } void TQPainter::setBrush(Qt::BrushStyle style) { return QPainter::setBrush(style); } void TQPainter::setBrush(TQt::BrushStyle style) { this->QPainter::setBrush((Qt::BrushStyle)style); } TQPoint TQPainter::pos() const { return current_penpos; } bool TQPainter::tqbegin( QPaintDevice *pdev, bool unclipped ) { bool ret = begin(pdev); if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } return ret; } bool TQPainter::tqbegin( QPaintDevice *pdev, const QWidget *init, bool unclipped ) { bool ret = begin(pdev); initFrom(init); if (unclipped) { printf("[WARNING] Qt4 does not support drawing under child widgets in TQPainter via the unclipped==TRUE flag in any form! Blame Nokia and change your code...\n\r"); fflush(stdout); } return ret; } QRectF TQPainter::boundingRect(const QRectF &rect, int flags, const QString &text) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL QRectF tqbr = QPainter::boundingRect(rect, flags, text); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } QRect TQPainter::boundingRect(const QRect &rect, int flags, const QString &text) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL QRect tqbr = QPainter::boundingRect(rect, flags, text); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } QRect TQPainter::boundingRect(int x, int y, int w, int h, int flags, const QString &text) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL QRect tqbr = QPainter::boundingRect(x, y, w, h, flags, text); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } QRectF TQPainter::boundingRect(const QRectF &rect, const QString &text, const QTextOption &o) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL QRectF tqbr = QPainter::boundingRect(rect, text, o); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } TQRect TQPainter::boundingRect(const QRect &rect, int flags, const QString &text, int len) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL TQRect tqbr = QPainter::boundingRect(rect, flags, text.left(len)); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } TQRect TQPainter::boundingRect(int x, int y, int w, int h, int flags, const QString &text, int len) { TQT_INITIALIZE_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL TQRect tqbr = QPainter::boundingRect(QRect(x, y, w, h), flags, text.left(len)); TQT_DESTROY_QPAINTER_TEMPORARY_ENGINE_CONDITIONAL return tqbr; } void TQPainter::drawText(const QPointF &p, const QString &s) { QPainter::drawText(p, s); } void TQPainter::drawText(const QPoint &p, const QString &s) { QPainter::drawText(p, s); } void TQPainter::drawText(int x, int y, const QString &s) { QPainter::drawText(x, y, s); } void TQPainter::drawText(const QPointF &p, const QString &str, int tf, int justificationPadding) { QPainter::drawText(p, str, tf, justificationPadding); } void TQPainter::drawText(const QRectF &r, int flags, const QString &text, QRectF *br) { QPainter::drawText(r, flags, text, br); } void TQPainter::drawText(const QRect &r, int flags, const QString &text, QRect *br) { QPainter::drawText(r, flags, text, br); } void TQPainter::drawText(int x, int y, int w, int h, int flags, const QString &text, QRect *br) { QPainter::drawText(x, y, w, h, flags, text, br); } void TQPainter::drawText(const QRectF &r, const QString &text, const QTextOption &o) { QPainter::drawText(r, text, o); } void TQPainter::drawText( int x, int y, const TQString &s, int len, TextDirection dir ) { Qt::LayoutDirection old = layoutDirection(); if (dir == RTL) setLayoutDirection(Qt::RightToLeft); else if (dir == LTR) setLayoutDirection(Qt::LeftToRight); QPainter::drawText(x, y, s.left(len)); setLayoutDirection(old); } void TQPainter::drawText( const TQPoint &p, const TQString &s, int len, TextDirection dir ) { Qt::LayoutDirection old = layoutDirection(); if (dir == RTL) setLayoutDirection(Qt::RightToLeft); else if (dir == LTR) setLayoutDirection(Qt::LeftToRight); QPainter::drawText(p, s.left(len)); setLayoutDirection(old); } void TQPainter::drawText( int x, int y, const TQString &s, int pos, int len, TextDirection dir ) { Qt::LayoutDirection old = layoutDirection(); if (dir == RTL) setLayoutDirection(Qt::RightToLeft); else if (dir == LTR) setLayoutDirection(Qt::LeftToRight); QPainter::drawText(x, y, s.mid(pos, len)); setLayoutDirection(old); } void TQPainter::drawText( const TQPoint &p, const TQString &s, int pos, int len, TextDirection dir ) { Qt::LayoutDirection old = layoutDirection(); if (dir == RTL) setLayoutDirection(Qt::RightToLeft); else if (dir == LTR) setLayoutDirection(Qt::LeftToRight); QPainter::drawText(p, s.mid(pos, len)); setLayoutDirection(old); } void TQPainter::drawText(int x, int y, const QString &s, int pos, int len) { drawText(x, y, s.mid(pos, len)); } void TQPainter::drawText(const QPoint &p, const QString &s, int pos, int len) { drawText(p, s.mid(pos, len)); } void TQPainter::drawText(int x, int y, const QString &s, int len) { drawText(x, y, s.left(len)); } void TQPainter::drawText(const QPoint &p, const QString &s, int len) { drawText(p, s.left(len)); } void TQPainter::drawText(const QRect &r, int flags, const QString &str, int len, QRect *br) { drawText(r, flags, str.left(len), br); } void TQPainter::drawText(int x, int y, int w, int h, int flags, const QString &text, int len, QRect *br) { drawText(QRect(x, y, w, h), flags, text.left(len), br); } int *TQPainter::tabArray() const { printf("[WARNING] TQPainter::tabArray unimplemented!\n\r"); } void TQPainter::setTabArray( int *ta ) { printf("[WARNING] TQPainter::setTabArray unimplemented!\n\r"); // #if defined(TQT_CHECK_STATE) // if ( !isActive() ) // qWarning( "TQPainter::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 tqdevice // TQPDevCmdParam param[2]; // param[0].ival = tabarraylen; // param[1].ivec = tabarray; // pdev->cmd( TQPaintDevice::PdcSetTabArray, this, param ); // } } void TQPainter::drawImage( int x, int y, const TQImage image, int sx, int sy, int sw, int sh, int conversionFlags ) { QPainter::drawImage(x, y, image, sx, sy, sw, sh, (Qt::ImageConversionFlags)conversionFlags); } void TQPainter::drawImage( const TQPoint p, const TQImage image, const TQRect sr, int conversionFlags ) { QPainter::drawImage(p, image, sr, (Qt::ImageConversionFlags)conversionFlags); } void TQPainter::drawImage( const TQPoint p, const TQImage image, int conversion_flags ) { TQ_UNUSED(conversion_flags); QPainter::drawImage(p, image); } void TQPainter::drawImage( const TQRect r, const TQImage image ) { QPainter::drawImage(r, image); } void TQPainter::resetXForm() { resetTransform(); } // [FIXME] The drawWinFocusRect methods below probably need tweaking to exactly match the old Qt3 behaviour void TQPainter::drawWinFocusRect( int x, int y, int w, int h ) { drawWinFocusRect( x, y, w, h, TRUE, TQt::color0 ); } void TQPainter::drawWinFocusRect( int x, int y, int w, int h, const TQColor &bgColor ) { drawWinFocusRect( x, y, w, h, FALSE, bgColor ); } void TQPainter::drawWinFocusRect( const TQRect &tqr ) { drawWinFocusRect( tqr.x(), tqr.y(), tqr.width(), tqr.height() ); } void TQPainter::drawWinFocusRect( const TQRect &tqr, const TQColor &bgColor ) { drawWinFocusRect( tqr.x(), tqr.y(), tqr.width(), tqr.height(), bgColor ); } void TQPainter::setBackgroundColor(const QColor &color) { setBackground(color); } const QColor &TQPainter::backgroundColor() const { return background().color(); } void TQPainter::setClipRect(const QRectF &qrf, Qt::ClipOperation op) { QPainter::setClipRect(qrf, op); } void TQPainter::setClipRect(const QRect &qr, Qt::ClipOperation op) { QPainter::setClipRect(qr, op); } void TQPainter::setClipRect( int x, int y, int w, int h, TQPainter::CoordinateMode cm ) { TQRect r(x, y, w, h); setClipRect(r, cm); } void TQPainter::redirect(QPaintDevice *pdev, QPaintDevice *replacement) { if (replacement == 0) { restoreRedirected(pdev); } else { setRedirected(pdev, replacement); } } TQPaintDevice *TQPainter::redirect(QPaintDevice *pdev) { return static_cast(const_cast(redirected(pdev))); } void TQPainter::setWorldXForm(bool enabled) { setMatrixEnabled(enabled); } bool TQPainter::hasWorldXForm() const { return matrixEnabled(); } void TQPainter::setViewXForm(bool enabled) { setViewTransformEnabled(enabled); } bool TQPainter::hasViewXForm() const { return viewTransformEnabled(); } // [FIXME] void TQPainter::initialize() { printf("[WARNING] TQColor static void initialize() not implemented\n\r"); } // [FIXME] void TQPainter::cleanup() { printf("[WARNING] TQColor static void cleanup() not implemented\n\r"); } void TQPainter::moveTo( const TQPoint &p ) { moveTo( p.x(), p.y() ); } void TQPainter::lineTo( const TQPoint &p ) { lineTo( p.x(), p.y() ); } void TQPainter::drawRect(const QRect &r) { QPainter::drawRect(adjustedRectangle(r)); } void TQPainter::drawEllipse(const QRect &r) { QPainter::drawEllipse(adjustedRectangle(r)); } void TQPainter::drawRoundRect(const QRect &r, int xrnd, int yrnd) { QPainter::drawRoundRect(adjustedRectangle(r), xrnd, yrnd); } void TQPainter::drawArc(const QRect &r, int angle, int arcLength) { QPainter::drawArc(adjustedRectangle(r), angle, arcLength); } void TQPainter::drawPie(const QRect &r, int angle, int arcLength) { QPainter::drawPie(adjustedRectangle(r), angle, arcLength); } void TQPainter::drawChord(const QRect &r, int angle, int arcLength) { QPainter::drawChord(adjustedRectangle(r), angle, arcLength); } void TQPainter::tqdrawTextItem( const TQPoint& p, const TQTextItem &ti, int textflags ) { tqdrawTextItem( p.x(), p.y(), ti, textflags ); } // [FIXME] // Verify these mappings... // They will need to be kept in sync with the code inside tqpainter_x11.cpp TQt::RasterOp TQPainter::rasterOp() const { TQt::RasterOp cm; switch (rop) { case QPainter::CompositionMode_SourceOver: cm=CopyROP; break; case QPainter::RasterOp_SourceOrDestination: cm=OrROP; break; case QPainter::RasterOp_SourceXorDestination: cm=XorROP; break; case QPainter::RasterOp_NotSourceAndDestination: cm=NotAndROP; break; case QPainter::RasterOp_NotSource: cm=NotCopyROP; break; case QPainter::RasterOp_NotSourceXorDestination: cm=NotXorROP; break; case QPainter::RasterOp_SourceAndDestination: cm=AndROP; break; case QPainter::CompositionMode_Clear: cm=ClearROP; break; case QPainter::CompositionMode_Destination: cm=NopROP; break; case QPainter::RasterOp_SourceAndNotDestination: cm=AndNotROP; break; case QPainter::RasterOp_NotSourceOrNotDestination: cm=NandROP; break; case QPainter::RasterOp_NotSourceAndNotDestination: cm=NorROP; break; default: cm=CopyROP; break; } return cm; } /*! \fn TQPainter::TQPainter() Constructs a TQPainter. */ /*! \fn TQPainter::TQPainter(QPaintDevice *pdev) Constructs a TQPainter that operates on tqdevice \a pdev. */ /*! \internal */ int TQPainter::rectSubtraction() const { return pen().style() != Qt::NoPen && pen().width() == 0 ? 1 : 0; } /*! \internal */ QRect TQPainter::adjustedRectangle(const QRect &r) { QRect rect = r.normalized(); int subtract = rectSubtraction(); if (subtract != 0) rect.setSize(QSize(rect.width() - subtract, rect.height() - subtract)); return rect; } /*! \fn void TQPainter::drawRect(int x, int y, int w, int h) \overload Draws the rectangle that fits inside the bounds specified by \a x, \a y, \a w and \a h using the current pen and brush. */ /*! \fn void TQPainter::drawRect(const QRect &r) Draws a rectangle that fits inside the rectangle \a r using the current pen and brush. */ /*! \fn TQPainter::drawEllipse(const QRect &r) Draws the ellipse that fits inside the bounds \a r using the current pen and brush. */ /*! \fn TQPainter::drawEllipse(int x, int y, int width, int height) \overload Draws an ellipse that fits inside the bounds specified by \a x, \a y, \a width and \a height using the current pen and brush. */ /*! \fn void TQPainter::drawPie(int x, int y, int w, int h, int startAngle, int spanAngle) \overload Draws a pie segment that fits inside the bounds (\a{x}, \a{y}, \a{w}, \a{h}) with the given \a startAngle and \a spanAngle. */ /*! \fn void TQPainter::drawPie(const QRect &r, int a, int alen) Draws a pie defined by the rectangle \a r, the start angle \a a and the arc length \a alen. The pie is filled with the current brush(). The angles \a a and \a alen are 1/16th of a degree, i.e. a full circle equals 5760 (16*360). Positive values of \a a and \a alen mean counter-clockwise while negative values mean the clockwise direction. Zero degrees is at the 3 o'clock position. \sa drawArc(), drawChord() */ /*! \fn void TQPainter::drawArc(int x, int y, int w, int h, int startAngle, int spanAngle) \overload Draws the arc that fits inside the rectangle (\a{x}, \a{y}, \a{w}, \a{h}), with the given \a startAngle and \a spanAngle. */ /*! \fn void TQPainter::drawArc(const QRect &r, int a, int alen) Draws an arc defined by the rectangle \a r, the start angle \a a and the arc length \a alen. The angles \a a and \a alen are 1/16th of a degree, i.e. a full circle equals 5760 (16*360). Positive values of \a a and \a alen mean counter-clockwise while negative values mean the clockwise direction. Zero degrees is at the 3 o'clock position. Example: \snippet doc/src/snippets/code/src_qt3support_painting_q3painter.cpp 0 \sa drawPie(), drawChord() */ /*! \fn void TQPainter::drawChord(int x, int y, int w, int h, int startAngle, int spanAngle) \overload Draws a chord that fits inside the rectangle (\a{x}, \a{y}, \a{w}, \a{h}) with the given \a startAngle and \a spanAngle. */ /*! \fn void TQPainter::drawChord(const QRect &r, int a, int alen) Draws a chord defined by the rectangle \a r, the start angle \a a and the arc length \a alen. The chord is filled with the current brush(). The angles \a a and \a alen are 1/16th of a degree, i.e. a full circle equals 5760 (16*360). Positive values of \a a and \a alen mean counter-clockwise while negative values mean the clockwise direction. Zero degrees is at the 3 o'clock position. \sa drawArc(), drawPie() */ /*! \fn void TQPainter::drawRoundRect(const QRect &r, int xrnd, int yrnd) Draws a rounded rect that fits into the bounds \a r using the current pen and brush. The parameters \a xrnd and \a yrnd specifies the roundness in x and y direction. */ /*! \fn void TQPainter::drawRoundRect(int x, int y, int w, int h, int xrnd, int yrnd) \overload Draws a rounded rect that fits into the bounds \a x, \a y, \a w and \a h using the current pen and brush. The parameters \a xrnd and \a yrnd specifies the roundness in x and y direction. */ /*! \fn void QPainter::drawLineSegments(const QPolygon &polygon, int index, int count) Draws \a count separate lines from points defined by the \a polygon, starting at \a{polygon}\e{[index]} (\a index defaults to 0). If \a count is -1 (the default) all points until the end of the array are used. Use drawLines() combined with QPolygon::constData() instead. \oldcode QPainter painter(this); painter.drawLineSegments(polygon, index, count); \newcode int lineCount = (count == -1) ? (polygon.size() - index) / 2 : count; QPainter painter(this); painter.drawLines(polygon.constData() + index * 2, lineCount); \endcode */ void TQPainter::drawLineSegments(const QPolygon &polygon, int index, int count) { int lineCount = (count == -1) ? (polygon.size() - index) / 2 : count; drawLines(polygon.constData() + index * 2, lineCount); } /*! \obsolete Use the worldTransform() combined with QTransform::dx() instead. \oldcode QPainter painter(this); qreal x = painter.translationX(); \newcode QPainter painter(this); qreal x = painter.worldTransform().dx(); \endcode */ qreal TQPainter::translationX() const { return worldTransform().dx(); } /*! \obsolete Use the worldTransform() combined with QTransform::dy() instead. \oldcode QPainter painter(this); qreal y = painter.translationY(); \newcode QPainter painter(this); qreal y = painter.worldTransform().dy(); \endcode */ qreal TQPainter::translationY() const { return worldTransform().dy(); } /*! \fn void TQPainter::map(int x, int y, int *rx, int *ry) const \internal Sets (\a{rx}, \a{ry}) to the point that results from applying the painter's current transformation on the point (\a{x}, \a{y}). */ void TQPainter::map(int x, int y, int *rx, int *ry) const { QPoint p(x, y); p = p * combinedMatrix(); *rx = p.x(); *ry = p.y(); } /*! \internal Maps a rectangle from logical coordinates to device coordinates. This internal function does not handle rotation and/or shear. */ void TQPainter::map( int x, int y, int w, int h, int *rx, int *ry, int *rw, int *rh ) const { TQRect qr(x, y, w, h); QTransform dtrans = combinedTransform(); TQRect tqr = dtrans.mapRect(qr); *rx = tqr.x(); *ry = tqr.y(); *rw = tqr.width(); *rh = tqr.height(); } /*! \fn TQPoint TQPainter::xForm(const QPoint &point) const Use combinedTransform() instead. */ TQPoint TQPainter::xForm(const QPoint &p) const { if (combinedTransform().type() == QTransform::TxNone) return p; return p * combinedMatrix(); } /*! \fn TQRect TQPainter::xForm(const QRect &rectangle) const \overload Use combinedTransform() instead of this function and call mapRect() on the result to obtain a QRect. */ TQRect TQPainter::xForm(const QRect &r) const { if (combinedTransform().type() == QTransform::TxNone) return r; return combinedMatrix().mapRect(r); } bool TQPainter::testf( uint b ) const { // printf("[WARNING] QPainter::testf() disabled\n\r"); // return 0; // Map to Qt4 flags and functions... if ((b&IsActive)!=0) { if (QPainter::isActive()) return TRUE; } // if ((b&ExtDev)!=0) { // printf("[WARNING] Assuming ExtDev==false in QPainter::testf()\n\r"); // } // if ((b&IsStartingUp)!=0) { // } // if ((b&NoCache)!=0) { // } if ((b&VxF)!=0) { if (QPainter::viewTransformEnabled()) return TRUE; } if ((b&WxF)!=0) { if (QPainter::worldMatrixEnabled()) return TRUE; } if ((b&ClipOn)!=0) { if (QPainter::hasClipping()) return TRUE; } printf("[WARNING] Assuming test flag 0x%x == false in QPainter::testf()\n\r", b); return 0; } /*! \fn TQPolygon TQPainter::xForm(const QPolygon &polygon) const \overload Use combinedTransform() instead. */ // TQPolygon TQPainter::xForm(const QPolygon &a) const // { // Q_D(const QPainter); // if (!d->engine) { // qWarning("QPainter::xForm: Painter not active"); // return QPolygon(); // } // if (d->state->matrix.type() == QTransform::TxNone) // return a; // return a * combinedMatrix(); // } /*! \fn TQPolygon TQPainter::xForm(const QPolygon &polygon, int index, int count) const \overload Use combinedTransform() combined with QPolygon::mid() instead. \oldcode QPainter painter(this); QPolygon transformed = painter.xForm(polygon, index, count) \newcode QPainter painter(this); QPolygon transformed = polygon.mid(index, count) * painter.combinedTransform(); \endcode */ // TQPolygon TQPainter::xForm(const QPolygon &av, int index, int npoints) const // { // int lastPoint = npoints < 0 ? av.size() : index+npoints; // QPolygon a(lastPoint-index); // memcpy(a.data(), av.data()+index, (lastPoint-index)*sizeof(QPoint)); // return a * combinedMatrix(); // } /*! \fn TQPoint TQPainter::xFormDev(const QPoint &point) const \overload \obsolete Use combinedTransform() combined with QTransform::inverted() instead. \oldcode QPainter painter(this); QPoint transformed = painter.xFormDev(point); \newcode QPainter painter(this); QPoint transformed = point * painter.combinedTransform().inverted(); \endcode */ TQPoint TQPainter::xFormDev(const QPoint &p) const { if(combinedTransform().type() == QTransform::TxNone) return p; return p * combinedMatrix().inverted(); } /*! \fn TQRect TQPainter::xFormDev(const QRect &rectangle) const \overload \obsolete Use combinedTransform() combined with QTransform::inverted() instead. \oldcode QPainter painter(this); QRect transformed = painter.xFormDev(rectangle); \newcode QPainter painter(this); QRegion region = QRegion(rectangle) * painter.combinedTransform().inverted(); QRect transformed = region.boundingRect(); \endcode */ TQRect TQPainter::xFormDev(const QRect &r) const { if (combinedTransform().type() == QTransform::TxNone) return r; return combinedMatrix().inverted().mapRect(r); } /*! \overload \fn TQPoint TQPainter::xFormDev(const QPolygon &polygon) const \obsolete Use combinedTransform() combined with QTransform::inverted() instead. \oldcode QPainter painter(this); QPolygon transformed = painter.xFormDev(rectangle); \newcode QPainter painter(this); QPolygon transformed = polygon * painter.combinedTransform().inverted(); \endcode */ // TQPolygon TQPainter::xFormDev(const QPolygon &a) const // { // Q_D(const QPainter); // if (!d->engine) { // qWarning("QPainter::xFormDev: Painter not active"); // return QPolygon(); // } // if (d->state->matrix.type() == QTransform::TxNone) // return a; // return a * combinedMatrix().inverted(); // } /*! \fn TQPolygon TQPainter::xFormDev(const QPolygon &polygon, int index, int count) const \overload \obsolete Use combinedTransform() combined with QPolygon::mid() and QTransform::inverted() instead. \oldcode QPainter painter(this); QPolygon transformed = painter.xFormDev(polygon, index, count); \newcode QPainter painter(this); QPolygon transformed = polygon.mid(index, count) * painter.combinedTransform().inverted(); \endcode */ // TQPolygon TQPainter::xFormDev(const QPolygon &ad, int index, int npoints) const // { // Q_D(const QPainter); // int lastPoint = npoints < 0 ? ad.size() : index+npoints; // QPolygon a(lastPoint-index); // memcpy(a.data(), ad.data()+index, (lastPoint-index)*sizeof(QPoint)); // if (d->state->matrix.type() == QTransform::TxNone) // return a; // return a * combinedMatrix().inverted(); // } /*! \obsolete Sets the current pen position to \a (x, y) \sa lineTo(), pos() */ void TQPainter::moveTo( int x, int y ) { QPainterPath path; path.moveTo(x, y); drawPath(path); current_penpos = QPoint(x, y); } /*! \obsolete Use drawLine() instead. Draws a line from the current pen position to \a (x, y) and sets \a (x, y) to be the new current pen position. \sa TQPen moveTo(), drawLine(), pos() */ void TQPainter::lineTo( int x, int y ) { QPainterPath path; path.moveTo(current_penpos.x(), current_penpos.y()); path.lineTo(x, y); drawPath(path); current_penpos = QPoint(x, y); } static void bitBlt_helper(QPaintDevice *dst, const QPoint &dp, const QPaintDevice *src, const QRect &sr, bool) { Q_ASSERT(dst); Q_ASSERT(src); if (src->devType() == QInternal::Pixmap) { const QPixmap *pixmap = static_cast(src); QPainter pt(dst); pt.drawPixmap(dp, *pixmap, sr); } else { qWarning("QPainter: bitBlt only works when source is of type pixmap"); } } void bitBlt(QPaintDevice *dst, int dx, int dy, const QPaintDevice *src, int sx, int sy, int sw, int sh, bool ignoreMask ) { bitBlt_helper(dst, QPoint(dx, dy), src, QRect(sx, sy, sw, sh), ignoreMask); } void bitBlt(QPaintDevice *dst, const QPoint &dp, const QPaintDevice *src, const QRect &sr, bool ignoreMask) { bitBlt_helper(dst, dp, src, sr, ignoreMask); } void bitBlt(QPaintDevice *dst, int dx, int dy, const QImage *src, int sx, int sy, int sw, int sh, int fl) { Qt::ImageConversionFlags flags(fl); QPixmap srcPixmap = QPixmap::fromImage(*src, flags); bitBlt_helper(dst, QPoint(dx, dy), &srcPixmap, QRect(sx, sy, sw, sh), false); } const TQWMatrix &TQPainter::tqworldMatrix() const { return (*(static_cast(&worldMatrix()))); } /*! \fn void TQPainter::tqdrawTextItem(const TQPoint &, const TQTextItem &, 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 TQPainter::fix_neg_rect( int *x, int *y, int *w, int *h ) { ::fix_neg_rect(x,y,w,h); } TQRegion TQPainter::clipRegion( CoordinateMode cm ) const { QRegion qr = QPainter::clipRegion(); QRegion tqr = qr; if (cm == CoordDevice) { // Convert to device coordinates QTransform dtrans = combinedTransform(); tqr = dtrans.map(qr); } return tqr; } void TQPainter::setClipRegion( const QRegion &qr, CoordinateMode cm ) { QRegion tqr = qr; if (cm == CoordDevice) { // Convert from device coordinates QTransform itrans = combinedTransform().inverted(); tqr = itrans.map(qr); QPainter::setClipRegion( tqr, Qt::ReplaceClip ); } else { QPainter::setClipRegion( tqr, Qt::ReplaceClip ); } } void TQPainter::setClipRect( const TQRect &qr, CoordinateMode cm ) { QRect tqr = qr; if (cm == CoordDevice) { // Convert from device coordinates QTransform itrans = combinedTransform().inverted(); tqr = itrans.mapRect(qr); QPainter::setClipRect( tqr, Qt::ReplaceClip ); } else { QPainter::setClipRect( tqr, Qt::ReplaceClip ); } } QT_END_NAMESPACE #else // USE_QT4 /**************************************************************************** ** ** Implementation of TQPainter, TQPen and TQBrush classes ** ** Created : 940112 ** ** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. ** ** This file is part of the kernel module of the TQt 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 TQt 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 sales@trolltech.com. ** ** This file may be used under the terms of the Q Public License as ** defined by Trolltech ASA and appearing in the file LICENSE.TQPL ** included in the packaging of this file. Licensees holding valid TQt ** Commercial licenses may use this file in accordance with the TQt ** 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 "tqpainter_p.h" #include "tqbitmap.h" #include "tqptrstack.h" #include "tqptrdict.h" #include "tqdatastream.h" #include "tqwidget.h" #include "tqimage.h" #include "tqpaintdevicemetrics.h" #include "tqapplication.h" #include "tqrichtext_p.h" #include "tqregexp.h" #include "tqcleanuphandler.h" #ifdef TQ_WS_TQWS #include "tqgfx_qws.h" #endif #include #include "tqtextlayout_p.h" #include "tqfontengine_p.h" #ifndef TQT_NO_TRANSFORMATIONS typedef TQPtrStack TQWMatrixStack; #endif // POSIX Large File Support redefines truncate -> truncate64 #if defined(truncate) # undef truncate #endif /*! \class TQPainter tqpainter.h \brief The TQPainter 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. TQPainter can draw everything from simple lines to complex tqshapes 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 TQPainter use is in a reimplementation of TQWidget::paintEvent(), and the painter is heavily optimized for such use.) Here's one very simple example: \code void SimpleExampleWidget::paintEvent() { TQPainter paint( this ); paint.setPen( TQt::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, TQt tqfinds 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 Transtqparent, 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(), tqworldMatrix() 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 tqdevice 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 tqdevices, e.g. TQWidget::font(). TQPainter::begin() (or the TQPainter constructor) copies these attributes from the paint tqdevice. Calling, for example, TQWidget::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 TQPainter 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 TQPrinter and TQPicture. 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 TQPicture using this painter. drawPicture() is the only function that disregards all the painter's settings: the TQPicture has its own settings. Normally, the TQPainter operates on the tqdevice's own coordinate system (usually pixels), but TQPainter 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 tqworldMatrix(). setWorldMatrix() can tqreplace or add to the currently set tqworldMatrix(). setViewport() sets the rectangle on which TQPainter operates. The default is the entire tqdevice, 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, TQPainter can clip the drawing to an arbitrary rectangle or region. hasClipping() is TRUE if TQPainter 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 TQPainter's clipping, the paint tqdevice 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(). TQPainter 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, tqdevice() returns the paint tqdevice on which the painter paints. Sometimes it is desirable to make someone else paint on an unusual TQPaintDevice. TQPainter 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 TQPainter 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 tqdrawutil.h \sa TQPaintDevice TQWidget TQPixmap TQPrinter TQPicture \link simple-application.html Application Walkthrough \endlink \link coordsys.html Coordinate System Overview \endlink */ /*! \fn TQGfx * TQPainter::internalGfx() \internal */ /*! \enum TQPainter::CoordinateMode \value CoordDevice \value CoordPainter \sa clipRegion() */ /*! \enum TQPainter::TextDirection \value Auto \value RTL right to left \value LTR left to right \sa drawText() */ /*! \enum TQt::PaintUnit \value PixelUnit \value LoMetricUnit \e obsolete \value HiMetricUnit \e obsolete \value LoEnglishUnit \e obsolete \value HiEnglishUnit \e obsolete \value TwipsUnit \e obsolete */ /*! \enum TQt::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 TQt::RasterOp This enum type is used to describe the way things are written to the paint tqdevice. 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 TQt/Embedded, only \c CopyROP, \c XorROP, and \c NotROP are supported. */ /*! \enum TQt::AlignmentFlags This enum type is used to describe tqalignment. It tqcontains 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 TQt::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 P (see TQButton 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 TQGridLayout::addWidget()) are generally ignored. */ /*! \enum TQt::PenStyle This enum type defines the pen styles that can be drawn using TQPainter. The styles are \value NoPen no line at all. For example, TQPainter::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 tqmask of the pen styles. \img pen-styles.png Pen Styles */ /*! \enum TQt::PenCapStyle This enum type defines the pen cap styles supported by TQt, i.e. the line end caps that can be drawn using TQPainter. \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 tqmask of the pen cap styles. \img pen-cap-styles.png Pen Cap Styles */ /*! \enum TQt::PenJoinStyle This enum type defines the pen join styles supported by TQt, i.e. which joins between two connected lines can be drawn using TQPainter. \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 tqmask of the pen join styles. \img pen-join-styles.png Pen Join Styles */ /*! \enum TQt::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() */ TQPainter::TQPainter() { init(); } /*! Constructs a painter that begins painting the paint tqdevice \a pd immediately. Depending on the underlying graphic system the painter will paint over tqchildren of the painttqdevice if \a unclipped is TRUE. This constructor is convenient for short-lived painters, e.g. in a \link TQWidget::paintEvent() paint event\endlink and should be used only once. The constructor calls begin() for you and the TQPainter destructor automatically calls end(). Here's an example using begin() and end(): \code void MyWidget::paintEvent( TQPaintEvent * ) { TQPainter p; p.begin( this ); p.drawLine( ... ); // drawing code p.end(); } \endcode The same example using this constructor: \code void MyWidget::paintEvent( TQPaintEvent * ) { TQPainter 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 tqdevices, e.g. printers. \sa begin(), end() */ TQPainter::TQPainter( const TQPaintDevice *pd, bool unclipped ) { init(); if ( begin( pd, unclipped ) ) flags |= CtorBegin; } /*! Constructs a painter that begins painting the paint tqdevice \a pd immediately, with the default arguments taken from \a copyAttributes. The painter will paint over tqchildren of the paint tqdevice if \a unclipped is TRUE (although this is not supported on all platforms). \sa begin() */ TQPainter::TQPainter( const TQPaintDevice *pd, const TQWidget *copyAttributes, bool unclipped ) { init(); if ( begin( pd, copyAttributes, unclipped ) ) flags |= CtorBegin; } /*! Destroys the painter. */ TQPainter::~TQPainter() { if ( isActive() ) end(); else killPStack(); if ( tabarray ) // delete tab array delete [] tabarray; #ifndef TQT_NO_TRANSFORMATIONS if ( wm_stack ) delete (TQWMatrixStack *)wm_stack; #endif destroy(); } /*! \overload bool TQPainter::begin( const TQPaintDevice *pd, const TQWidget *copyAttributes, bool unclipped ) This version opens the painter on a paint tqdevice \a pd and sets the initial pen, background color and font from \a copyAttributes, painting over the paint tqdevice's tqchildren when \a unclipped is TRUE. This is equivalent to: \code TQPainter 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( TQPaintEvent * ) { TQPixmap pm(size()); TQPainter p; p.begin(&pm, this); // ... potentially flickering paint operation ... p.end(); bitBlt(this, 0, 0, &pm); } \endcode \sa end() */ bool TQPainter::begin( const TQPaintDevice *pd, const TQWidget *copyAttributes, bool unclipped ) { if ( copyAttributes == 0 ) { #if defined(TQT_CHECK_NULL) qWarning( "TQPainter::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 TQPainter::setf( uint b, bool v ) { if ( v ) setf( b ); else clearf( b ); } /*! \fn bool TQPainter::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 TQPaintDevice::paintingActive() */ /*! \fn TQPaintDevice *TQPainter::tqdevice() const Returns the paint tqdevice on which this painter is currently painting, or 0 if the painter is not active. \sa TQPaintDevice::paintingActive() */ struct TQPState { // painter state TQFont font; TQPen pen; TQPoint curPt; TQBrush brush; TQColor bgc; uchar bgm; uchar rop; TQPoint bro; TQRect wr, vr; #ifndef TQT_NO_TRANSFORMATIONS TQWMatrix wm; #else int xlatex; int xlatey; #endif bool vxf; bool wxf; TQRegion rgn; bool clip; int ts; int *ta; void* wm_stack; }; //TODO lose the worldmatrix stack typedef TQPtrStack TQPStateStack; void TQPainter::killPStack() { #if defined(TQT_CHECK_STATE) if ( ps_stack && !((TQPStateStack *)ps_stack)->isEmpty() ) qWarning( "TQPainter::killPStack: non-empty save/restore stack when " "end() was called" ); #endif delete (TQPStateStack *)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 TQPainter::save() { if ( testf(ExtDev) ) { if ( testf(DirtyFont) ) updateFont(); if ( testf(DirtyPen) ) updatePen(); if ( testf(DirtyBrush) ) updateBrush(); pdev->cmd( TQPaintDevice::PdcSave, this, 0 ); } TQPStateStack *pss = (TQPStateStack *)ps_stack; if ( pss == 0 ) { pss = new TQPtrStack; TQ_CHECK_PTR( pss ); pss->setAutoDelete( TRUE ); ps_stack = pss; } TQPState *ps = new TQPState; TQ_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 TQT_NO_TRANSFORMATIONS ps->wr = TQRect( wx, wy, ww, wh ); ps->vr = TQRect( 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 TQPainter::restore() { if ( testf(ExtDev) ) { pdev->cmd( TQPaintDevice::PdcRestore, this, 0 ); if ( pdev->devType() == TQInternal::Picture ) block_ext = TRUE; } TQPStateStack *pss = (TQPStateStack *)ps_stack; if ( pss == 0 || pss->isEmpty() ) { #if defined(TQT_CHECK_STATE) qWarning( "TQPainter::restore: Empty stack error" ); #endif return; } TQPState *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 TQT_NO_TRANSFORMATIONS TQRect wr( wx, wy, ww, wh ); TQRect 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 TQT_NO_TRANSFORMATIONS if ( wm_stack ) delete (TQWMatrixStack *)wm_stack; wm_stack = ps->wm_stack; #endif delete ps; block_ext = FALSE; } typedef TQPtrDict TQPaintDeviceDict; static TQPaintDeviceDict *pdev_dict = 0; /*! Redirects all paint commands for a paint tqdevice, \a pdev, to another paint tqdevice, \a tqreplacement, unless \a tqreplacement is 0. If \a tqreplacement is 0, the redirection for \a pdev is removed. In general, you'll probably tqfind calling TQPixmap::grabWidget() or TQPixmap::grabWindow() is an easier solution. */ void TQPainter::redirect( TQPaintDevice *pdev, TQPaintDevice *tqreplacement ) { if ( pdev_dict == 0 ) { if ( tqreplacement == 0 ) return; pdev_dict = new TQPaintDeviceDict; TQ_CHECK_PTR( pdev_dict ); } #if defined(TQT_CHECK_NULL) if ( pdev == 0 ) qWarning( "TQPainter::redirect: The pdev argument cannot be 0" ); #endif if ( tqreplacement ) { pdev_dict->insert( pdev, tqreplacement ); } else { pdev_dict->remove( pdev ); if ( pdev_dict->count() == 0 ) { delete pdev_dict; pdev_dict = 0; } } } /*! \internal Returns the tqreplacement for \a pdev, or 0 if there is no tqreplacement. */ TQPaintDevice *TQPainter::redirect( TQPaintDevice *pdev ) { return pdev_dict ? pdev_dict->tqfind( 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() */ TQFontMetrics TQPainter::fontMetrics() const { if ( pdev && pdev->devType() == TQInternal::Picture ) return TQFontMetrics( cfont ); return TQFontMetrics(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() */ TQFontInfo TQPainter::fontInfo() const { if ( pdev && pdev->devType() == TQInternal::Picture ) return TQFontInfo( cfont ); return TQFontInfo(this); } /*! \fn const TQPen &TQPainter::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 TQPainter::setPen( const TQPen &pen ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::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(), TQPen */ void TQPainter::setPen( PenStyle style ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setPen: Will be reset by begin()" ); #endif TQPen::TQPenData *d = cpen.data; // low level access if ( d->style == style && d->linest == style && !d->width && d->color == TQt::black ) return; if ( d->count != 1 ) { cpen.detach(); d = cpen.data; } d->style = style; d->width = 0; d->color = TQt::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(), TQPen */ void TQPainter::setPen( const TQColor &color ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setPen: Will be reset by begin()" ); #endif TQPen::TQPenData *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 TQBrush &TQPainter::brush() const Returns the painter's current brush. \sa TQPainter::setBrush() */ /*! \overload Sets the painter's brush to \a brush. The \a brush defines how tqshapes are filled. \sa brush() */ void TQPainter::setBrush( const TQBrush &brush ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::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(), TQBrush */ void TQPainter::setBrush( BrushStyle style ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setBrush: Will be reset by begin()" ); #endif TQBrush::TQBrushData *d = cbrush.data; // low level access if ( d->style == style && d->color == TQt::black && !d->pixmap ) return; if ( d->count != 1 ) { cbrush.detach(); d = cbrush.data; } d->style = style; d->color = TQt::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(), TQBrush */ void TQPainter::setBrush( const TQColor &color ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setBrush: Will be reset by begin()" ); #endif TQBrush::TQBrushData *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 TQColor &TQPainter::backgroundColor() const Returns the current background color. \sa setBackgroundColor() TQColor */ /*! \fn BGMode TQPainter::backgroundMode() const Returns the current background mode. \sa setBackgroundMode() BGMode */ /*! \fn RasterOp TQPainter::rasterOp() const Returns the current \link TQt::RasterOp raster operation \endlink. \sa setRasterOp() RasterOp */ /*! \fn const TQPoint &TQPainter::brushOrigin() const Returns the brush origin currently set. \sa setBrushOrigin() */ /*! \fn int TQPainter::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 TQPainter::setTabStops( int ts ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setTabStops: Will be reset by begin()" ); #endif tabstops = ts; if ( isActive() && testf(ExtDev) ) { // tell extended tqdevice TQPDevCmdParam param[1]; param[0].ival = ts; pdev->cmd( TQPaintDevice::PdcSetTabStops, this, param ); } } /*! \fn int *TQPainter::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 TQPainter::setTabArray( int *ta ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::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 tqdevice TQPDevCmdParam param[2]; param[0].ival = tabarraylen; param[1].ivec = tabarray; pdev->cmd( TQPaintDevice::PdcSetTabArray, this, param ); } } /*! \fn HANDLE TQPainter::handle() const Returns the platform-dependent handle used for drawing. Using this function is not portable. */ /***************************************************************************** TQPainter xform settings *****************************************************************************/ #ifndef TQT_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 TQPainter::setViewXForm( bool enable ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setViewXForm: Will be reset by begin()" ); #endif if ( !isActive() || enable == testf(VxF) ) return; setf( VxF, enable ); if ( testf(ExtDev) ) { TQPDevCmdParam param[1]; param[0].ival = enable; pdev->cmd( TQPaintDevice::PdcSetVXform, this, param ); } updateXForm(); } /*! \fn bool TQPainter::hasViewXForm() const Returns TRUE if view transformation is enabled; otherwise returns FALSE. \sa setViewXForm(), xForm() */ /*! Returns the window rectangle. \sa setWindow(), setViewXForm() */ TQRect TQPainter::window() const { return TQRect( 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 tqdevice coordinate system. The default window rectangle is the same as the tqdevice's rectangle. See the \link coordsys.html Coordinate System Overview \endlink for an overview of coordinate transformation. \sa window(), setViewport(), setViewXForm(), setWorldMatrix(), setWorldXForm() */ void TQPainter::setWindow( int x, int y, int w, int h ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setWindow: Will be reset by begin()" ); #endif wx = x; wy = y; ww = w; wh = h; if ( testf(ExtDev) ) { TQRect r( x, y, w, h ); TQPDevCmdParam param[1]; param[0].rect = (TQRect*)&r; pdev->cmd( TQPaintDevice::PdcSetWindow, this, param ); } if ( testf(VxF) ) updateXForm(); else setViewXForm( TRUE ); } /*! Returns the viewport rectangle. \sa setViewport(), setViewXForm() */ TQRect TQPainter::viewport() const // get viewport { return TQRect( 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 tqdevice 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 tqdevice'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 TQPainter::setViewport( int x, int y, int w, int h ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setViewport: Will be reset by begin()" ); #endif vx = x; vy = y; vw = w; vh = h; if ( testf(ExtDev) ) { TQRect r( x, y, w, h ); TQPDevCmdParam param[1]; param[0].rect = (TQRect*)&r; pdev->cmd( TQPaintDevice::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 TQPainter::setWorldXForm( bool enable ) { #if defined(TQT_CHECK_STATE) if ( !isActive() ) qWarning( "TQPainter::setWorldXForm: Will be reset by begin()" ); #endif if ( !isActive() || enable == testf(WxF) ) return; setf( WxF, enable ); if ( testf(ExtDev) && !block_ext ) { TQPDevCmdParam param[1]; param[0].ival = enable; pdev->cmd( TQPaintDevice::PdcSetWXform, this, param ); } updateXForm(); } /*! \fn bool TQPainter::hasWorldXForm() const Returns TRUE if world transformation is enabled; otherwise returns FALSE. \sa setWorldXForm() */ /*! Returns the world transformation matrix. \sa setWorldMatrix() */ const TQWMatrix &TQPainter::tqworldMatrix() 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 tqreplaces 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 TQWMatrix::m11() and TQWMatrix::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 TQWMatrix: \list \i translate() \i scale() \i shear() \i rotate() \endlist They operate on the painter's tqworldMatrix() and are implemented like this: \code void TQPainter::rotate( double a ) { TQWMatrix m; m.rotate( a ); setWorldMatrix( m, TRUE ); } \endcode Note that you should always use \a combine when you are drawing into a TQPicture. 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 tqworldMatrix() setWorldXForm() setWindow() setViewport() setViewXForm() xForm() TQWMatrix */ void TQPainter::setWorldMatrix( const TQWMatrix &m, bool combine ) { if ( !isActive() ) { #if defined(TQT_CHECK_STATE) qWarning( "TQPainter::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 ) { TQPDevCmdParam param[2]; param[0].matrix = &m; param[1].ival = combine; pdev->cmd( TQPaintDevice::PdcSetWMatrix, this, param ); } if ( identity && pdev->devType() != TQInternal::Picture ) setWorldXForm( FALSE ); else if ( !testf(WxF) ) setWorldXForm( TRUE ); else updateXForm(); } /*! \obsolete We recommend using save() instead. */ void TQPainter::saveWorldMatrix() { TQWMatrixStack *stack = (TQWMatrixStack *)wm_stack; if ( stack == 0 ) { stack = new TQPtrStack; TQ_CHECK_PTR( stack ); stack->setAutoDelete( TRUE ); wm_stack = stack; } stack->push( new TQWMatrix( wxmat ) ); } /*! \obsolete We recommend using restore() instead. */ void TQPainter::restoreWorldMatrix() { TQWMatrixStack *stack = (TQWMatrixStack *)wm_stack; if ( stack == 0 || stack->isEmpty() ) { #if defined(TQT_CHECK_STATE) qWarning( "TQPainter::restoreWorldMatrix: Empty stack error" ); #endif return; } TQWMatrix* m = stack->pop(); setWorldMatrix( *m ); delete m; } #endif // TQT_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() { TQPainter 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 TQPainter::translate( double dx, double dy ) { #ifndef TQT_NO_TRANSFORMATIONS TQWMatrix m; m.translate( dx, dy ); setWorldMatrix( m, TRUE ); #else xlatex += (int)dx; xlatey += (int)dy; setf( VxF, xlatex || xlatey ); #endif } #ifndef TQT_NO_TRANSFORMATIONS /*! Scales the coordinate system by \a (sx, sy). \sa translate(), shear(), rotate(), resetXForm(), setWorldMatrix(), xForm() */ void TQPainter::scale( double sx, double sy ) { TQWMatrix m; m.scale( sx, sy ); setWorldMatrix( m, TRUE ); } /*! Shears the coordinate system by \a (sh, sv). \sa translate(), scale(), rotate(), resetXForm(), setWorldMatrix(), xForm() */ void TQPainter::shear( double sh, double sv ) { TQWMatrix m; m.shear( sv, sh ); setWorldMatrix( m, TRUE ); } /*! Rotates the coordinate system \a a degrees counterclockwise. \sa translate(), scale(), shear(), resetXForm(), setWorldMatrix(), xForm() */ void TQPainter::rotate( double a ) { TQWMatrix m; m.rotate( a ); setWorldMatrix( m, TRUE ); } /*! Resets any transformations that were made using translate(), scale(), shear(), rotate(), setWorldMatrix(), setViewport() and setWindow(). \sa tqworldMatrix(), viewport(), window() */ void TQPainter::resetXForm() { if ( !isActive() ) return; wx = wy = vx = vy = 0; // default view origins ww = vw = pdev->metric( TQPaintDeviceMetrics::PdmWidth ); wh = vh = pdev->metric( TQPaintDeviceMetrics::PdmHeight ); wxmat = TQWMatrix(); setWorldXForm( FALSE ); setViewXForm( FALSE ); } /*! \internal Updates an internal integer transformation matrix. */ void TQPainter::updateXForm() { TQWMatrix 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(TQ_WS_WIN) setf(DirtyFont); #endif } } else { txop = TxRotShear; #if defined(TQ_WS_WIN) setf(DirtyFont); #endif } } /*! \internal Updates an internal integer inverse transformation matrix. */ void TQPainter::updateInvXForm() { #if defined(TQT_CHECK_STATE) TQ_ASSERT( txinv == FALSE ); #endif txinv = TRUE; // creating inverted matrix bool invertible; TQWMatrix 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 TQPainter::resetXForm() { xlatex = 0; xlatey = 0; clearf( VxF ); } #endif // TQT_NO_TRANSFORMATIONS extern bool qt_old_transformations; /*! \internal Maps a point from logical coordinates to tqdevice coordinates. */ void TQPainter::map( int x, int y, int *rx, int *ry ) const { #ifndef TQT_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 = tqRound( x + dx() ); *ry = tqRound( y + dy() ); break; case TxScale: *rx = tqRound( m11()*x + dx() ); *ry = tqRound( m22()*y + dy() ); break; default: *rx = tqRound( m11()*x + m21()*y+dx() ); *ry = tqRound( m12()*x + m22()*y+dy() ); break; } } #else *rx = x + xlatex; *ry = y + xlatey; #endif } /*! \internal Maps a rectangle from logical coordinates to tqdevice coordinates. This internal function does not handle rotation and/or shear. */ void TQPainter::map( int x, int y, int w, int h, int *rx, int *ry, int *rw, int *rh ) const { #ifndef TQT_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 = tqRound( tx1 ); *ry = tqRound( ty1 ); *rw = tqRound( tx2 ) - *rx + 1; *rh = tqRound( ty2 ) - *ry + 1; } break; default: #if defined(TQT_CHECK_STATE) qWarning( "TQPainter::map: Internal error" ); #endif break; } } else { switch ( txop ) { case TxNone: *rx = x; *ry = y; *rw = w; *rh = h; break; case TxTranslate: *rx = tqRound(x + dx() ); *ry = tqRound(y + dy() ); *rw = w; *rh = h; break; case TxScale: *rx = tqRound( m11()*x + dx() ); *ry = tqRound( m22()*y + dy() ); *rw = tqRound( m11()*w ); *rh = tqRound( m22()*h ); break; default: #if defined(TQT_CHECK_STATE) qWarning( "TQPainter::map: Internal error" ); #endif break; } } #else *rx = x + xlatex; *ry = y + xlatey; *rw = w; *rh = h; #endif } /*! \internal Maps a point from tqdevice coordinates to logical coordinates. */ void TQPainter::mapInv( int x, int y, int *rx, int *ry ) const { #ifndef TQT_NO_TRANSFORMATIONS #if defined(TQT_CHECK_STATE) if ( !txinv ) qWarning( "TQPainter::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 = tqRound( im11()*x + im21()*y + idx() ); *ry = tqRound( im12()*x + im22()*y + idy() ); } #else *rx = x - xlatex; *ry = y - xlatey; #endif } /*! \internal Maps a rectangle from tqdevice coordinates to logical coordinates. Cannot handle rotation and/or shear. */ void TQPainter::mapInv( int x, int y, int w, int h, int *rx, int *ry, int *rw, int *rh ) const { #ifndef TQT_NO_TRANSFORMATIONS #if defined(TQT_CHECK_STATE) if ( !txinv || txop == TxRotShear ) qWarning( "TQPainter::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 = tqRound( im11()*x + idx() ); *ry = tqRound( im22()*y + idy() ); *rw = tqRound( im11()*w ); *rh = tqRound( im22()*h ); } #else *rx = x - xlatex; *ry = y - xlatey; *rw = w; *rh = h; #endif } /*! Returns the point \a pv transformed from model coordinates to tqdevice coordinates. \sa xFormDev(), TQWMatrix::map() */ TQPoint TQPainter::xForm( const TQPoint &pv ) const { #ifndef TQT_NO_TRANSFORMATIONS if ( txop == TxNone ) return pv; int x=pv.x(), y=pv.y(); map( x, y, &x, &y ); return TQPoint( x, y ); #else return TQPoint( pv.x()+xlatex, pv.y()+xlatey ); #endif } /*! \overload Returns the rectangle \a rv transformed from model coordinates to tqdevice coordinates. If world transformation is enabled and rotation or shearing has been specified, then the bounding rectangle is returned. \sa xFormDev(), TQWMatrix::map() */ TQRect TQPainter::xForm( const TQRect &rv ) const { #ifndef TQT_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 TQRect( x, y, w, h ); #else return TQRect( rv.x()+xlatex, rv.y()+xlatey, rv.width(), rv.height() ); #endif } /*! \overload Returns the point array \a av transformed from model coordinates to tqdevice coordinates. \sa xFormDev(), TQWMatrix::map() */ TQPointArray TQPainter::xForm( const TQPointArray &av ) const { TQPointArray a = av; #ifndef TQT_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 tqdevice 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 TQPointArray a(10); TQPointArray b; b = painter.xForm(a, 2, 4); // b.size() == 4 b = painter.xForm(a, 2, -1); // b.size() == 8 \endcode \sa xFormDev(), TQWMatrix::map() */ TQPointArray TQPainter::xForm( const TQPointArray &av, int index, int npoints ) const { int lastPoint = npoints < 0 ? av.size() : index+npoints; TQPointArray a( lastPoint-index ); memcpy( a.data(), av.data()+index, (lastPoint-index)*sizeof( TQPoint ) ); #ifndef TQT_NO_TRANSFORMATIONS return xmat*a; #else a.translate( xlatex, xlatey ); return a; #endif } /*! \overload Returns the point \a pd transformed from tqdevice coordinates to model coordinates. \sa xForm(), TQWMatrix::map() */ TQPoint TQPainter::xFormDev( const TQPoint &pd ) const { #ifndef TQT_NO_TRANSFORMATIONS if ( txop == TxNone ) return pd; if ( !txinv ) { TQPainter *that = (TQPainter*)this; // mutable that->updateInvXForm(); } #endif int x=pd.x(), y=pd.y(); mapInv( x, y, &x, &y ); return TQPoint( x, y ); } /*! Returns the rectangle \a rd transformed from tqdevice coordinates to model coordinates. If world transformation is enabled and rotation or shearing is used, then the bounding rectangle is returned. \sa xForm(), TQWMatrix::map() */ TQRect TQPainter::xFormDev( const TQRect &rd ) const { #ifndef TQT_NO_TRANSFORMATIONS if ( txop == TxNone ) return rd; if ( !txinv ) { TQPainter *that = (TQPainter*)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 TQRect( x, y, w, h ); } /*! \overload Returns the point array \a ad transformed from tqdevice coordinates to model coordinates. \sa xForm(), TQWMatrix::map() */ TQPointArray TQPainter::xFormDev( const TQPointArray &ad ) const { #ifndef TQT_NO_TRANSFORMATIONS if ( txop == TxNone ) return ad; if ( !txinv ) { TQPainter *that = (TQPainter*)this; // mutable that->updateInvXForm(); } return ixmat * ad; #else // ### return ad; #endif } /*! \overload Returns the point array \a ad transformed from tqdevice 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 TQPointArray a(10); TQPointArray b; b = painter.xFormDev(a, 1, 3); // b.size() == 3 b = painter.xFormDev(a, 1, -1); // b.size() == 9 \endcode \sa xForm(), TQWMatrix::map() */ TQPointArray TQPainter::xFormDev( const TQPointArray &ad, int index, int npoints ) const { int lastPoint = npoints < 0 ? ad.size() : index+npoints; TQPointArray a( lastPoint-index ); memcpy( a.data(), ad.data()+index, (lastPoint-index)*sizeof( TQPoint ) ); #ifndef TQT_NO_TRANSFORMATIONS if ( txop == TxNone ) return a; if ( !txinv ) { TQPainter *that = (TQPainter*)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 TQColor as \a brush, since there is a TQBrush constructor that takes a TQColor argument and creates a solid pattern brush. \sa drawRect() */ void TQPainter::fillRect( int x, int y, int w, int h, const TQBrush &brush ) { TQPen oldPen = pen(); // save pen TQBrush 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 TQPainter::setBrushOrigin( const TQPoint &p ) Sets the brush origin to point \a p. */ /*! \overload void TQPainter::setWindow( const TQRect &r ) Sets the painter's window to rectangle \a r. */ /*! \overload void TQPainter::setViewport( const TQRect &r ) Sets the painter's viewport to rectangle \a r. */ /*! \fn bool TQPainter::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 tqdevice 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() TQPainter::CoordinateMode */ TQRegion TQPainter::clipRegion( CoordinateMode m ) const { // ### FIXME in 4.0: // If the transformation mode is CoordPainter, we should transform the // clip region with painter transformations. #ifndef TQT_NO_TRANSFORMATIONS TQRegion r; if ( m == CoordDevice ) { r = crgn; } else { if ( !txinv ) { TQPainter *that = (TQPainter*)this; // mutable that->updateInvXForm(); } r = ixmat * crgn; } return r; #else return crgn; #endif } /*! \fn void TQPainter::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 tqdevice 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() TQPainter::CoordinateMode */ /*! \overload void TQPainter::drawPoint( const TQPoint &p ) Draws the point \a p. */ /*! \overload void TQPainter::moveTo( const TQPoint &p ) Moves to the point \a p. */ /*! \overload void TQPainter::lineTo( const TQPoint &p ) Draws a line to the point \a p. */ /*! \overload void TQPainter::drawLine( const TQPoint &p1, const TQPoint &p2 ) Draws a line from point \a p1 to point \a p2. */ /*! \overload void TQPainter::drawRect( const TQRect &r ) Draws the rectangle \a r. */ /*! \overload void TQPainter::drawWinFocusRect( const TQRect &r ) Draws rectangle \a r as a window focus rectangle. */ /*! \overload void TQPainter::drawWinFocusRect( const TQRect &r, const TQColor &bgColor ) Draws rectangle \a r as a window focus rectangle using background color \a bgColor. */ #if !defined(TQ_WS_X11) && !defined(TQ_WS_TQWS) && !defined(TQ_WS_MAC) // The doc and X implementation of this functions is in qpainter_x11.cpp void TQPainter::drawWinFocusRect( int, int, int, int, bool, const TQColor & ) { // do nothing, only called from X11 specific functions } #endif /*! \overload void TQPainter::drawRoundRect( const TQRect &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 TQPainter::drawEllipse( const TQRect &r ) Draws the ellipse that fits inside rectangle \a r. */ /*! \overload void TQPainter::drawArc( const TQRect &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 TQPainter::drawPie( const TQRect &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 TQPainter::drawChord( const TQRect &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 TQPainter::drawPixmap( const TQPoint &p, const TQPixmap &pm, const TQRect &sr ) Draws the rectangle \a sr of pixmap \a pm with its origin at point \a p. */ /*! \overload void TQPainter::drawPixmap( const TQPoint &p, const TQPixmap &pm ) Draws the pixmap \a pm with its origin at point \a p. */ void TQPainter::drawPixmap( const TQPoint &p, const TQPixmap &pm ) { drawPixmap( p.x(), p.y(), pm, 0, 0, pm.width(), pm.height() ); } #if !defined(TQT_NO_IMAGE_SMOOTHSCALE) || !defined(TQT_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 TQPainter::drawPixmap( const TQRect &r, const TQPixmap &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) ) { TQPDevCmdParam param[2]; param[0].rect = &r; param[1].pixmap = ± #if defined(TQ_WS_WIN) if ( !pdev->cmd( TQPaintDevice::PdcDrawPixmap, this, param ) || !hdc ) return; #elif defined(TQ_WS_TQWS) pdev->cmd( TQPaintDevice::PdcDrawPixmap, this, param ); return; #elif defined(TQ_WS_MAC) if ( !pdev->cmd( TQPaintDevice::PdcDrawPixmap, this, param ) || !pdev->handle()) return; #else if ( !pdev->cmd( TQPaintDevice::PdcDrawPixmap, this, param ) || !hd ) return; #endif } TQPixmap pixmap = pm; if ( scale ) { #ifndef TQT_NO_IMAGE_SMOOTHSCALE # ifndef TQT_NO_PIXMAP_TRANSFORMATION if ( smooth ) # endif { TQImage i = pm.convertToImage(); pixmap = TQPixmap( i.smoothScale( rw, rh ) ); } # ifndef TQT_NO_PIXMAP_TRANSFORMATION else # endif #endif #ifndef TQT_NO_PIXMAP_TRANSFORMATION { pixmap = pm.xForm( TQWMatrix( scaleX, 0, 0, scaleY, 0, 0 ) ); } #endif } drawPixmap( r.x(), r.y(), pixmap ); } #endif /*! \overload void TQPainter::drawImage( const TQPoint &, const TQImage &, const TQRect &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 tqdevice() is a TQPixmap or a TQWidget, or else draw it directly, if tqdevice() is a TQPrinter or TQPicture. */ /*! 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 tqdevice() is a TQPixmap or a TQWidget, or else draw it directly, if tqdevice() is a TQPrinter or TQPicture. Currently alpha masks of the image are ignored when painting on a TQPrinter. \sa drawPixmap() TQPixmap::convertFromImage() */ void TQPainter::drawImage( int x, int y, const TQImage & image, int sx, int sy, int sw, int sh, int conversionFlags ) { #ifdef TQ_WS_TQWS //### Hackish # ifndef TQT_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(); TQImage image2 = qt_screen->mapToDevice( image ); // This is a bit dubious if(image2.depth()==1) { image2.setNumColors( 2 ); image2.setColor( 0, tqRgb(255,255,255) ); image2.setColor( 1, tqRgb(0,0,0) ); } if ( image2.hasAlphaBuffer() ) gfx->setAlphaType(TQGfx::InlineAlpha); else gfx->setAlphaType(TQGfx::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(TQRect(sx,sy,sw,sh)) == image.rect(); TQImage subimage = all ? image : image.copy(sx,sy,sw,sh); if ( testf(ExtDev) ) { TQPDevCmdParam param[2]; TQRect r( x, y, subimage.width(), subimage.height() ); param[0].rect = &r; param[1].image = &subimage; #if defined(TQ_WS_WIN) if ( !pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ) || !hdc ) return; #elif defined (TQ_WS_TQWS) pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ); return; #elif defined(TQ_WS_MAC) if(!pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ) || !pdev->handle() ) return; #else if ( !pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ) || !hd ) return; #endif } TQPixmap pm; pm.convertFromImage( subimage, conversionFlags ); drawPixmap( x, y, pm ); } /*! \overload void TQPainter::drawImage( const TQPoint &p, const TQImage &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 TQt::ImageConversionFlags */ void TQPainter::drawImage( const TQPoint & p, const TQImage & i, int conversion_flags ) { drawImage(p, i, i.rect(), conversion_flags); } #if !defined(TQT_NO_IMAGE_TRANSFORMATION) || !defined(TQT_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 TQPainter::drawImage( const TQRect &r, const TQImage &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) ) { TQPDevCmdParam param[2]; param[0].rect = &r; param[1].image = &i; #if defined(TQ_WS_WIN) if ( !pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ) || !hdc ) return; #elif defined(TQ_WS_TQWS) pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ); return; #elif defined(TQ_WS_MAC) if ( !pdev->cmd( TQPaintDevice::PdcDrawImage, this, param ) || !pdev->handle() ) return; #else if ( !pdev->cmd( TQPaintDevice::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 ); TQImage img = scale ? ( #if defined(TQT_NO_IMAGE_TRANSFORMATION) i.smoothScale( rw, rh ) #elif defined(TQT_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( TQPaintDevice *dst, int dx, int dy, const TQImage *src, int sx, int sy, int sw, int sh, int conversion_flags ) { TQPixmap 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 TQPainter::drawTiledPixmap( const TQRect &r, const TQPixmap &pm, const TQPoint &sp ) Draws a tiled pixmap, \a pm, inside rectangle \a r with its origin at point \a sp. */ /*! \overload void TQPainter::drawTiledPixmap( const TQRect &r, const TQPixmap &pm ) Draws a tiled pixmap, \a pm, inside rectangle \a r. */ /*! \overload void TQPainter::fillRect( const TQRect &r, const TQBrush &brush ) Fills the rectangle \a r using brush \a brush. */ /*! \fn void TQPainter::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 TQPainter::eraseRect( const TQRect &r ) Erases the area inside the rectangle \a r. */ /*! \fn TQPainter::drawText( int x, int y, const TQString &, 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 TQPainter::TextDirection */ /*! \fn void TQPainter::drawText( int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQRect *br=0, TQTextParag **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{TQt::AlignmentFlags} and \l{TQt::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 TQPainter::drawText( const TQPoint &, const TQString &, int len = -1, TextDirection dir = Auto ); \overload Draws the text at the given point. \sa TQPainter::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 TQPainter::drawText( int x, int y, const TQString &, 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 TQPainter::drawText( const TQPoint &p, const TQString &, 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 tqalignment flags. \sa TQPainter::TextDirection */ /*! \fn void TQPainter::tqdrawTextItem(const TQPoint &, const TQTextItem &, 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 TQPainter::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 tqcontains a pointer to an array of encoded // information that keeps internal tqgeometry 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 tqcontains 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 TQt::AlignmentFlags and \l TQt::TextFlags OR'd together. Horizontal tqalignment defaults to AlignAuto and vertical tqalignment 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 TQPainter::drawText( const TQRect &r, int tf, const TQString& str, int len, TQRect *brect, TQTextParag **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 ) { TQPDevCmdParam param[3]; TQString newstr = str; newstr.truncate( len ); param[0].rect = &r; param[1].ival = tf; param[2].str = &newstr; if ( pdev->devType() != TQInternal::Printer ) { #if defined(TQ_WS_WIN) if ( !pdev->cmd( TQPaintDevice::PdcDrawText2Formatted, this, param) || !hdc ) return; // TQPrinter wants PdcDrawText2 #elif defined(TQ_WS_TQWS) pdev->cmd( TQPaintDevice::PdcDrawText2Formatted, this, param); return; #elif defined(TQ_WS_MAC) if ( !pdev->cmd( TQPaintDevice::PdcDrawText2Formatted, this, param) || !pdev->handle()) return; // TQPrinter wants PdcDrawText2 #else if ( !pdev->cmd( TQPaintDevice::PdcDrawText2Formatted, this, param) || !hd ) return; // TQPrinter wants PdcDrawText2 #endif } } } qt_format_text(font(), r, tf, str, len, brect, tabstops, tabarray, tabarraylen, internal, this); } //#define TQT_FORMAT_TEXT_DEBUG #define TQChar_linesep TQChar(0x2028U) void qt_format_text( const TQFont& font, const TQRect &_r, int tf, const TQString& str, int len, TQRect *brect, int tabstops, int* tabarray, int tabarraylen, TQTextParag **, TQPainter* painter ) { // we need to copy r here to protect against the case (&r == brect). TQRect r( _r ); bool dontclip = (tf & TQt::DontClip) == TQt::DontClip; bool wordbreak = (tf & TQt::WordBreak) == TQt::WordBreak; bool singleline = (tf & TQt::SingleLine) == TQt::SingleLine; bool showprefix = (tf & TQt::ShowPrefix) == TQt::ShowPrefix; bool noaccel = ( tf & TQt::NoAccel ) == TQt::NoAccel; bool isRightToLeft = str.isRightToLeft(); if ( ( tf & TQt::AlignHorizontal_Mask ) == TQt::AlignAuto ) tf |= isRightToLeft ? TQt::AlignRight : TQt::AlignLeft; bool expandtabs = ( (tf & TQt::ExpandTabs) && ( ( (tf & TQt::AlignLeft) && !isRightToLeft ) || ( (tf & TQt::AlignRight) && isRightToLeft ) ) ); if ( !painter ) tf |= TQt::DontPrint; int maxUnderlines = 0; int numUnderlines = 0; int underlinePositionStack[32]; int *underlinePositions = underlinePositionStack; TQFont fnt(painter ? (painter->pfont ? *painter->pfont : painter->cfont) : font); TQFontMetrics fm( fnt ); TQString text = str; // str.setLength() always does a deep copy, so the tqreplacement // code below is safe. text.setLength( len ); // compatible behaviour to the old implementation. Replace // tabs by spaces TQChar *chr = (TQChar*)text.tqunicode(); const TQChar *end = chr + len; bool haveLineSep = FALSE; while ( chr != end ) { if ( *chr == '\r' || ( singleline && *chr == '\n' ) ) { *chr = ' '; } else if ( *chr == '\n' ) { *chr = TQChar_linesep; haveLineSep = TRUE; } else if ( *chr == '&' ) { ++maxUnderlines; } ++chr; } if ( !expandtabs ) { chr = (TQChar*)text.tqunicode(); 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]; TQChar *cout = (TQChar*)text.tqunicode(); TQChar *cin = cout; int l = len; while ( l ) { if ( *cin == '&' ) { ++cin; --l; if ( !l ) break; if ( *cin != '&' ) underlinePositions[numUnderlines++] = cout - text.tqunicode(); } *cout = *cin; ++cout; ++cin; --l; } uint newlen = cout - text.tqunicode(); if ( newlen != text.length()) text.setLength( newlen ); } // no need to do extra work for underlines if we don't paint if ( tf & TQt::DontPrint ) numUnderlines = 0; int height = 0; int left = r.width(); int right = 0; TQTextLayout textLayout( text, fnt ); int rb = TQMAX( 0, -fm.minRightBearing() ); int lb = TQMAX( 0, -fm.minLeftBearing() ); if ( text.isEmpty() ) { height = fm.height(); left = right = 0; tf |= TQPainter::DontPrint; } else { textLayout.beginLayout((haveLineSep || expandtabs || wordbreak) ? TQTextLayout::MultiLine : (tf & TQt::DontPrint) ? TQTextLayout::NoBidi : TQTextLayout::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 ? TQMAX(0, r.width()-rb-lb) : INT_MAX; if(!wordbreak) tf |= TQt::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 ) { TQTextItem ti = textLayout.currentItem(); //qDebug("item: from=%d, ch=%x", ti.from(), text.tqunicode()[ti.from()].tqunicode() ); 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.tqunicode()[ti.from()] == TQChar_linesep ) linesep = TRUE; if ( linesep || textLayout.addCurrentItem() != TQTextLayout::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 = TQMIN( left, lineLeft ); right = TQMAX( right, lineRight ); height += ascent + descent + 1; if ( linesep ) textLayout.nextItem(); } } int yoff = 0; if ( tf & TQt::AlignBottom ) yoff = r.height() - height; else if ( tf & TQt::AlignVCenter ) yoff = (r.height() - height)/2; if ( brect ) { *brect = TQRect( 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 & TQPainter::DontPrint)) { bool restoreClipping = FALSE; bool painterHasClip = FALSE; TQRegion painterClipRegion; if ( !dontclip ) { #ifndef TQT_NO_TRANSFORMATIONS TQRegion reg = painter->xmat * r; #else TQRegion 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 |= TQt::Underline; if (fnt.overline()) _tf |= TQt::Overline; if (fnt.strikeOut()) _tf |= TQt::StrikeOut; //qDebug("have %d items",textLayout.numItems()); for ( int i = 0; i < textLayout.numItems(); i++ ) { TQTextItem 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 |= TQt::Underline; cUlChar++; } #if defined(TQ_WS_X11) || defined(TQ_WS_TQWS) if ( painter->bg_mode == TQt::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->tqdrawTextItem( 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(), TQFontMetrics::boundingRect(), TQt::TextFlags */ TQRect TQPainter::boundingRect( const TQRect &r, int flags, const TQString& str, int len, TQTextParag **internal ) { TQRect brect; if ( str.isEmpty() ) brect.setRect( r.x(),r.y(), 0,0 ); else drawText( r, flags | DontPrint, str, len, &brect, internal ); return brect; } /*! \fn TQRect TQPainter::boundingRect( int x, int y, int w, int h, int flags, const TQString&, int len = -1, TQTextParag **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 "x". \row \i \c WordBreak \i breaks the text to fit the rectangle. \endtable Horizontal tqalignment defaults to \c AlignLeft and vertical tqalignment defaults to \c AlignTop. If several of the horizontal or several of the vertical tqalignment flags are set, the resulting tqalignment is undefined. The \a intern parameter should not be used. \sa TQt::TextFlags */ /***************************************************************************** TQPen member functions *****************************************************************************/ /*! \class TQPen tqpen.h \brief The TQPen class defines how a TQPainter should draw lines and outlines of tqshapes. \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 TQt::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 TQColor 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 (TQPainter::drawPolyline() etc.). The cap and join styles only apply to wide lines, i.e. when the width is 1 or greater. Use the TQBrush class to specify fill styles. Example: \code TQPainter painter; TQPen 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 TQt::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. TQPainter 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 TQPainter, TQPainter::setPen() */ /*! \internal Initializes the pen. */ void TQPen::init( const TQColor &color, uint width, uint linestyle ) { data = new TQPenData; TQ_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). */ TQPen::TQPen() { init( TQt::black, 0, SolidLine ); // default pen } /*! Constructs a black pen with 0 width (fast diagonals) and style \a style. \sa setStyle() */ TQPen::TQPen( PenStyle style ) { init( TQt::black, 0, style ); } /*! Constructs a pen with the specified \a color, \a width and \a style. \sa setWidth(), setStyle(), setColor() */ TQPen::TQPen( const TQColor &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() */ TQPen::TQPen( const TQColor &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. */ TQPen::TQPen( const TQPen &p ) { data = p.data; data->ref(); } /*! Destroys the pen. */ TQPen::~TQPen() { 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 TQPen::detach() { if ( data->count != 1 ) *this = copy(); } /*! Assigns \a p to this pen and returns a reference to this pen. */ TQPen &TQPen::operator=( const TQPen &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. */ TQPen TQPen::copy() const { TQPen p( data->color, data->width, data->style, capStyle(), joinStyle() ); return p; } /*! \fn PenStyle TQPen::style() const Returns the pen style. \sa setStyle() */ /*! Sets the pen style to \a s. See the \l TQt::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 TQPen::setStyle( PenStyle s ) { if ( data->style == s ) return; detach(); data->style = s; data->linest = (data->linest & ~MPenStyle) | s; } /*! \fn uint TQPen::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 TQPen::setWidth( uint w ) { if ( data->width == w ) return; detach(); data->width = w; } /*! Returns the pen's cap style. \sa setCapStyle() */ TQt::PenCapStyle TQPen::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 TQPen::setCapStyle( PenCapStyle c ) { if ( (data->linest & MPenCapStyle) == c ) return; detach(); data->linest = (data->linest & ~MPenCapStyle) | c; } /*! Returns the pen's join style. \sa setJoinStyle() */ TQt::PenJoinStyle TQPen::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 TQPen::setJoinStyle( PenJoinStyle j ) { if ( (data->linest & MPenJoinStyle) == j ) return; detach(); data->linest = (data->linest & ~MPenJoinStyle) | j; } /*! \fn const TQColor &TQPen::color() const Returns the pen color. \sa setColor() */ /*! Sets the pen color to \a c. \sa color() */ void TQPen::setColor( const TQColor &c ) { detach(); data->color = c; } /*! \fn bool TQPen::operator!=( const TQPen &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 TQPen::operator==( const TQPen &p ) const { return (p.data == data) || (p.data->linest == data->linest && p.data->width == data->width && p.data->color == data->color); } /***************************************************************************** TQPen stream functions *****************************************************************************/ #ifndef TQT_NO_DATASTREAM /*! \relates TQPen Writes the pen \a p to the stream \a s and returns a reference to the stream. \sa \link datastreamformat.html Format of the TQDataStream operators \endlink */ TQDataStream &operator<<( TQDataStream &s, const TQPen &p ) { // ### width() should not be restricted to 8-bit values if ( s.version() < 3 ) return s << (TQ_UINT8)p.style() << (TQ_UINT8)p.width() << p.color(); else return s << (TQ_UINT8)( p.style() | p.capStyle() | p.joinStyle() ) << (TQ_UINT8)p.width() << p.color(); } /*! \relates TQPen 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 TQDataStream operators \endlink */ TQDataStream &operator>>( TQDataStream &s, TQPen &p ) { TQ_UINT8 style, width; TQColor color; s >> style; s >> width; s >> color; p = TQPen( color, (uint)width, (TQt::PenStyle)style ); // owl return s; } #endif //TQT_NO_DATASTREAM /***************************************************************************** TQBrush member functions *****************************************************************************/ /*! \class TQBrush tqbrush.h \brief The TQBrush class defines the fill pattern of tqshapes drawn by a TQPainter. \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 TQPixmap. 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 tqshapes. The standard style for filling is \c SolidPattern. The brush color defines the color of the fill pattern. The TQColor documentation lists the predefined colors. Use the TQPen class for specifying line/outline styles. Example: \code TQPainter painter; TQBrush 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 TQPainter, TQPainter::setBrush(), TQPainter::setBrushOrigin() */ inline TQPixmap *TQBrush::pixmap() const { if (style() != Qt::TexturePattern) return 0; QTexturedBrushData *data = static_cast(d.data()); QPixmap &pixmap = data->pixmap(); return pixmap.isNull() ? 0 : &pixmap; } /*! \internal Initializes the brush. */ void TQBrush::init( const TQColor &color, BrushStyle style ) { data = new TQBrushData; TQ_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 tqshapes). */ TQBrush::TQBrush() { static TQBrushData* defBrushData = 0; if ( !defBrushData ) { static TQSharedCleanupHandler defBrushCleanup; defBrushData = new TQBrushData; defBrushData->style = NoBrush; defBrushData->color = TQt::black; defBrushData->pixmap = 0; defBrushCleanup.set( &defBrushData ); } data = defBrushData; data->ref(); } /*! Constructs a black brush with the style \a style. \sa setStyle() */ TQBrush::TQBrush( BrushStyle style ) { init( TQt::black, style ); } /*! Constructs a brush with the color \a color and the style \a style. \sa setColor(), setStyle() */ TQBrush::TQBrush( const TQColor &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 TQPixmap::depth() == 1. Pixmap brushes are currently not supported when printing on X11. \sa setColor(), setPixmap() */ TQBrush::TQBrush( const TQColor &color, const TQPixmap &pixmap ) { init( color, CustomPattern ); setPixmap( pixmap ); } /*! Constructs a brush that is a \link shclass.html shallow copy\endlink of \a b. */ TQBrush::TQBrush( const TQBrush &b ) { data = b.data; data->ref(); } /*! Destroys the brush. */ TQBrush::~TQBrush() { 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 TQBrush::detach() { if ( data->count != 1 ) *this = copy(); } /*! Assigns \a b to this brush and returns a reference to this brush. */ TQBrush &TQBrush::operator=( const TQBrush &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. */ TQBrush TQBrush::copy() const { if ( data->style == CustomPattern ) { // brush has pixmap TQBrush b( data->color, *data->pixmap ); return b; } else { // brush has std pattern TQBrush b( data->color, data->style ); return b; } } /*! \fn BrushStyle TQBrush::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 tqshapes (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 transtqparent. See the \link #details Detailed Description\endlink for a picture of all the styles. \sa style() */ void TQBrush::setStyle( BrushStyle s ) // set brush style { if ( data->style == s ) return; #if defined(TQT_CHECK_RANGE) if ( s == CustomPattern ) qWarning( "TQBrush::setStyle: CustomPattern is for internal use" ); #endif detach(); data->style = s; } /*! \fn const TQColor &TQBrush::color() const Returns the brush color. \sa setColor() */ /*! Sets the brush color to \a c. \sa color(), setStyle() */ void TQBrush::setColor( const TQColor &c ) { detach(); data->color = c; } /*! \fn TQPixmap *TQBrush::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 TQPixmap::depth() == 1. Pixmap brushes are currently not supported when printing on X11. \sa pixmap(), color() */ void TQBrush::setPixmap( const TQPixmap &pixmap ) { detach(); if ( data->pixmap ) delete data->pixmap; if ( pixmap.isNull() ) { data->style = NoBrush; data->pixmap = 0; } else { data->style = CustomPattern; data->pixmap = new TQPixmap( pixmap ); if ( data->pixmap->optimization() == TQPixmap::MemoryOptim ) data->pixmap->setOptimization( TQPixmap::NormalOptim ); } } /*! \fn bool TQBrush::operator!=( const TQBrush &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 TQBrush::operator==( const TQBrush &b ) const { return (b.data == data) || (b.data->style == data->style && b.data->color == data->color && b.data->pixmap == data->pixmap); } /*! \fn inline double TQPainter::translationX() const \internal */ /*! \fn inline double TQPainter::translationY() const \internal */ /***************************************************************************** TQBrush stream functions *****************************************************************************/ #ifndef TQT_NO_DATASTREAM /*! \relates TQBrush Writes the brush \a b to the stream \a s and returns a reference to the stream. \sa \link datastreamformat.html Format of the TQDataStream operators \endlink */ TQDataStream &operator<<( TQDataStream &s, const TQBrush &b ) { s << (TQ_UINT8)b.style() << b.color(); if ( b.style() == TQt::CustomPattern ) #ifndef TQT_NO_IMAGEIO s << *b.pixmap(); #else qWarning("No Image Brush I/O"); #endif return s; } /*! \relates TQBrush Reads the brush \a b from the stream \a s and returns a reference to the stream. \sa \link datastreamformat.html Format of the TQDataStream operators \endlink */ TQDataStream &operator>>( TQDataStream &s, TQBrush &b ) { TQ_UINT8 style; TQColor color; s >> style; s >> color; if ( style == TQt::CustomPattern ) { #ifndef TQT_NO_IMAGEIO TQPixmap pm; s >> pm; b = TQBrush( color, pm ); #else qWarning("No Image Brush I/O"); #endif } else b = TQBrush( color, (TQt::BrushStyle)style ); return s; } #endif // TQT_NO_DATASTREAM #endif // USE_QT4