From dadc34655c3ab961b0b0b94a10eaaba710f0b5e8 Mon Sep 17 00:00:00 2001 From: tpearson Date: Mon, 4 Jul 2011 22:38:03 +0000 Subject: Added kmymoney git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kmymoney@1239792 283d02a7-25f6-0310-bc7c-ecb5cbfe19da --- libkdchart/KDDrawText.cpp | 483 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 libkdchart/KDDrawText.cpp (limited to 'libkdchart/KDDrawText.cpp') diff --git a/libkdchart/KDDrawText.cpp b/libkdchart/KDDrawText.cpp new file mode 100644 index 0000000..4b9467f --- /dev/null +++ b/libkdchart/KDDrawText.cpp @@ -0,0 +1,483 @@ +/* -*- Mode: C++ -*- + KDChart - a multi-platform charting engine + */ + +/**************************************************************************** + ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB. All rights reserved. + ** + ** This file is part of the KDChart library. + ** + ** This file may be distributed and/or modified under the terms of the + ** GNU General Public License version 2 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. + ** + ** Licensees holding valid commercial KDChart licenses may use this file in + ** accordance with the KDChart Commercial License Agreement provided with + ** the Software. + ** + ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ** + ** See http://www.klaralvdalens-datakonsult.se/?page=products for + ** information about KDChart Commercial License Agreements. + ** + ** Contact info@klaralvdalens-datakonsult.se if any conditions of this + ** licensing are not clear to you. + ** + **********************************************************************/ +#include +#include +#include +#include +#include + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +void KDDrawText::drawRotatedText( QPainter* painter, + float degrees, + QPoint anchor, + const QString& text, + const QFont* font, + int align, + bool showAnchor, + const QFontMetrics* fontMet, + bool noFirstrotate, + bool noBackrotate, + KDDrawTextRegionAndTrueRect* infos, + bool optimizeOutputForScreen ) +{ + drawRotatedTxt( painter, + optimizeOutputForScreen, + degrees, + anchor, + text, + font, + align, + showAnchor, + INT_MAX, + INT_MAX, + fontMet, + false, + 0 != infos, + noFirstrotate, + noBackrotate, + infos ); +} + + +KDDrawTextRegionAndTrueRect KDDrawText::measureRotatedText( + QPainter* painter, + float degrees, + QPoint anchor, + const QString& text, + const QFont* font, + int align, + const QFontMetrics* fontMet, + bool noFirstrotate, + bool noBackrotate, + int addPercentOfHeightToRegion ) +{ + KDDrawTextRegionAndTrueRect infos; + drawRotatedTxt( painter, + false, + degrees, + anchor, + text, + font, + align, + false, + INT_MAX, + INT_MAX, + fontMet, + true, + false, + noFirstrotate, + noBackrotate, + &infos, + addPercentOfHeightToRegion ); + return infos; +} + + +void KDDrawText::drawRotatedTxt( QPainter* painter, + bool optimizeOutputForScreen, + float degrees, + QPoint anchor, + const QString& text, + const QFont* font, + int align, + bool showAnchor, + int txtWidth, + int txtHeight, + const QFontMetrics* fontMet, + bool calculateOnly, + bool doNotCalculate, + bool noFirstrotate, + bool noBackrotate, + KDDrawTextRegionAndTrueRect* infos, + int addPercentOfHeightToRegion ) +{ + +// showAnchor=true; + //qDebug("\nanchor: "+ text + " / "+QString::number(anchor.x()) + // +" / "+QString::number(anchor.y())); + bool useInfos = doNotCalculate && infos; + bool fontChanged = ( 0 != font ); + QFont oldFont; + if( fontChanged ) { + oldFont = painter->font(); + painter->setFont( *font ); + } + else + font = &painter->font(); + + bool mustBackrotate = false; + if( !optimizeOutputForScreen && !noFirstrotate ){ + painter->rotate( degrees ); + if( !noBackrotate ) + mustBackrotate = true; + } + + QPoint pos = useInfos ? infos->pos : painter->xFormDev( anchor ); + + if( useInfos ) + { + txtWidth = infos->width; + txtHeight = infos->height; + } + else + { + int newHeight=0; + + // a bug in the AIX 5.2 compiler means using (?:) syntax doesn't work here + // therefor we do it the following way: + QFontMetrics* pFM=0; + if( ! pFM ) { + pFM = new QFontMetrics( painter->fontMetrics() ); + } else { + pFM = const_cast(fontMet); + } + + int nLF = text.contains('\n'); + if( INT_MAX == txtWidth ) { + if( nLF ){ + int tw; + txtWidth = 0; + int i0 = 0; + int iLF = text.find('\n'); + while( -1 != iLF ){ + const QRect r(pFM->boundingRect( text.mid(i0, iLF-i0) )); + tw = r.width()+ 2; + newHeight = r.height(); + if( tw > txtWidth ) + txtWidth = tw; + i0 = iLF+1; + iLF = text.find('\n', i0); + } + if( iLF < (int)text.length() ){ + const QRect r(pFM->boundingRect( text.mid( i0 ) )); + tw = r.width()+2; + newHeight = r.height(); + if( tw > txtWidth ) + txtWidth = tw; + i0 = iLF+1; + } + }else{ + const QRect r(painter->boundingRect( 0,0,1,1, Qt::AlignAuto, text )); + // correct width and height before painting with 2 unit to avoid truncating. + // PENDING Michel - improve + txtWidth = r.width()+2; + newHeight = r.height()+2; + } + } + if( INT_MAX == txtWidth || INT_MAX == txtHeight ) { + txtHeight = newHeight ? newHeight : pFM->height() * (1+nLF); + } + if( pFM != fontMet ) + delete pFM; + if( infos ) { + infos->pos = pos; + // PENDING infos + infos->width = txtWidth; + infos->height = txtHeight; + } + } + if( showAnchor ) { + int d = txtHeight/4; + QPen savePen = painter->pen(); + painter->setPen( QColor( Qt::darkRed ) ); + painter->drawLine( pos.x(), pos.y()-d, + pos.x(), pos.y()+d ); + painter->drawLine( pos.x()-d, pos.y(), + pos.x()+d, pos.y() ); + painter->setPen( savePen ); + } + int x = useInfos ? infos->x : pos.x(); + int y = useInfos ? infos->y : pos.y(); + //qDebug("1.: (x / y) :" + text + " / "+QString::number(x) + // +" / "+QString::number(y)); + //qDebug("2.: (posx / posy) :" + text ); + // qDebug ( "%d", pos.x() ); qDebug ( "%d", pos.y() ); + //qDebug("3.: (infosx / infosy) :" + text + " / "+QString::number(infos->x) + // +" / "+QString::number(infos->y)); + + if( !useInfos && !optimizeOutputForScreen ) { + switch( align & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ) ) { + case Qt::AlignLeft: + break; + case Qt::AlignRight: +//qDebug( QPaintDeviceMetrics::logicalDpiX() ); + x -= txtWidth; + break; + case Qt::AlignHCenter: + x -= txtWidth - txtWidth/2; + break; + } + switch( align & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ) ) { + case Qt::AlignTop: + break; + case Qt::AlignBottom: + y -= txtHeight; + break; + case Qt::AlignVCenter: + y -= txtHeight/2; + break; + } + } + if( infos && !useInfos ) { + painter->xForm( pos ); + infos->x = x - 4; + infos->y = y - 4; + //PENDING Michel updating info using x , y from pos + //qDebug("4.: (infosx / infosy) :" + text + " / "+QString::number(infos->x) + //+" / "+QString::number(infos->y)); + //qDebug("5.: (x / y) :" + text + " / "+QString::number(x) + // +" / "+QString::number(y)); + //qDebug("6.: (anchorx /anchory) :" + text + " / "+QString::number(x) + // +" / "+QString::number(y)); + QRect rect( painter->boundingRect( x, y, + txtWidth, txtHeight, + Qt::AlignLeft + Qt::AlignTop, + text ) ); + //painter->fillRect (rect, Qt::blue ); + + QPoint topLeft( painter->xForm( rect.topLeft() ) ); + QPoint topRight( painter->xForm( rect.topRight() ) ); + QPoint bottomRight( painter->xForm( rect.bottomRight() ) ); + QPoint bottomLeft( painter->xForm( rect.bottomLeft() ) ); + + int additor = addPercentOfHeightToRegion * txtHeight / 100; + QPointArray points; + points.setPoints( 4, topLeft.x()-additor, topLeft.y()-additor, + topRight.x()+additor, topRight.y()-additor, + bottomRight.x()+additor, bottomRight.y()+additor, + bottomLeft.x()-additor, bottomLeft.y()+additor ); + infos->region = QRegion( points ); + } + + // When the Qt initialization bug is fixed the following scope + // will be put into an "if( showAnchor )" entirely. + { + int d = txtHeight/4; + QPen savePen = painter->pen(); + if( showAnchor ) { + painter->setPen( QColor( Qt::blue ) ); + painter->drawLine( x, y-d, + x, y+d ); + painter->drawLine( x-d, y, + x+d, y ); + painter->setPen( QColor( Qt::darkGreen ) ); + painter->drawRect(x,y,txtWidth,txtHeight); + //painter->drawText( x, y-d, text); + +/* + }else{ + // Working around a strange Qt bug: Rotated painter must be + // initialized by drawing before text can be painted there. + painter->setPen( QColor( Qt::white ) ); + painter->drawLine( 30000,0,30001,0 ); +*/ + } + painter->setPen( savePen ); + } + + if( mustBackrotate && optimizeOutputForScreen ){ + painter->rotate( -degrees ); + mustBackrotate = false; + } + + if( !calculateOnly ){ + //qDebug("txtWidth: %i txtHeight: %i", txtWidth, txtHeight); + if( !optimizeOutputForScreen ){ +/* + painter->drawText( x, y, + txtWidth, txtHeight, + Qt::AlignLeft + Qt::AlignTop, + text ); +*/ + painter->drawText( x, y, + txtWidth, txtHeight, + Qt::AlignLeft + Qt::AlignTop, + text ); +/* + painter->drawText( x, y, + text, + -1, + Qt::AlignRight + Qt::AlignTop ); +*/ + }else{ + // new code (rotating the text ourselves for better quality on screens) + QPixmap pm( txtWidth+2, txtHeight+2, 1 ); + // note: When using colored axis labels it will be necessary + // to change this code and use a 256 color pixmap instead + // of a monochrome one. (khz, 2002/08/15) + pm.fill(Qt::color0); + QPainter p; + p.begin( &pm ); + if( showAnchor ){ + p.drawRect(0,0, txtWidth,txtHeight); + p.drawLine(0,0, txtWidth,txtHeight); + p.drawLine(0,txtHeight, txtWidth,0); + } + p.setFont(painter->font()); + + p.drawText( 0, 0, txtWidth, txtHeight, + Qt::AlignLeft + Qt::AlignTop, + text ); +/* + p.drawText( 0,0, + text, + -1, + Qt::AlignLeft + Qt::AlignTop ); +*/ + + QBitmap mask; + mask = pm; + pm.setMask( mask ); + QWMatrix m; + m.rotate( degrees ); + QPixmap theRotatedPixmap = pm.xForm(m); + + // where are our four corner points now: + double degreesRad = degrees; + while( degreesRad > 360 ) + degreesRad -= 360; + degreesRad *= M_PI / 180.0; + double cosA = cos( degreesRad ); + double sinA = sin( degreesRad ); + QPoint pTopLeft( 0, + 0 ); + QPoint pBotLeft( static_cast < int > ( 0 * cosA - txtHeight * sinA ), + static_cast < int > ( txtHeight * cosA + 0 * sinA ) ); + QPoint pTopRight( static_cast < int > ( txtWidth * cosA - 0 * sinA ), + static_cast < int > ( 0 * cosA + txtWidth * sinA ) ); + QPoint pBotRight( static_cast < int > ( txtWidth * cosA - txtHeight * sinA ), + static_cast < int > ( txtHeight * cosA + txtWidth * sinA ) ); + + // make our four corner points relative + // to the bounding rect of the rotated pixmap + { + QPoint pDeltaTL( QMIN(0, QMIN(pBotLeft.x(), QMIN(pTopRight.x(), pBotRight.x()))), + QMIN(0, QMIN(pBotLeft.y(), QMIN(pTopRight.y(), pBotRight.y()))) ); + pTopLeft -= pDeltaTL; + pBotLeft -= pDeltaTL; + pTopRight -= pDeltaTL; + pBotRight -= pDeltaTL; + } + + /* + painter->setPen( QColor( Qt::black ) ); + painter->drawLine( x-13, y, x+13, y ); + painter->drawLine( x, y-13, x, y+13 ); + painter->setPen( QColor( Qt::blue ) ); + painter->drawLine( x+pTopLeft.x()-3, y+pTopLeft.y(), x+pTopLeft.x()+3, y+pTopLeft.y() ); + painter->drawLine( x+pTopLeft.x(), y+pTopLeft.y()-3, x+pTopLeft.x(), y+pTopLeft.y()+3 ); + painter->setPen( QColor( Qt::red ) ); + painter->drawLine( x+pTopRight.x()-3, y+pTopRight.y(), x+pTopRight.x()+3, y+pTopRight.y() ); + painter->drawLine( x+pTopRight.x(), y+pTopRight.y()-3, x+pTopRight.x(), y+pTopRight.y()+3 ); + painter->setPen( QColor( Qt::green ) ); + painter->drawLine( x+pBotLeft.x()-3, y+pBotLeft.y(), x+pBotLeft.x()+3, y+pBotLeft.y() ); + painter->drawLine( x+pBotLeft.x(), y+pBotLeft.y()-3, x+pBotLeft.x(), y+pBotLeft.y()+3 ); + painter->setPen( QColor( Qt::yellow ) ); + painter->drawLine( x+pBotRight.x()-3, y+pBotRight.y(), x+pBotRight.x()+3, y+pBotRight.y() ); + painter->drawLine( x+pBotRight.x(), y+pBotRight.y()-3, x+pBotRight.x(), y+pBotRight.y()+3 ); + */ + + // The horizontal and vertical alignment together define one of + // NINE possible points: this point must be moved on the anchor. + int hAlign = align & ( Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter ); + int vAlign = align & ( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter ); + + QPoint pixPoint; + switch( hAlign ) { + case Qt::AlignLeft: + switch( vAlign ) { + case Qt::AlignTop: + pixPoint = pTopLeft; + break; + case Qt::AlignBottom: + pixPoint = pBotLeft; + break; + case Qt::AlignVCenter: + default: + pixPoint = QPoint( (pTopLeft.x() + pBotLeft.x()) / 2, + (pTopLeft.y() + pBotLeft.y()) / 2 ); + break; + } + break; + case Qt::AlignRight: + switch( vAlign ) { + case Qt::AlignTop: + pixPoint = pTopRight; + break; + case Qt::AlignBottom: + pixPoint = pBotRight; + break; + case Qt::AlignVCenter: + default: + pixPoint = QPoint( (pTopRight.x() + pBotRight.x()) / 2, + (pTopRight.y() + pBotRight.y()) / 2 ); + break; + } + break; + case Qt::AlignHCenter: + default: + switch( vAlign ) { + case Qt::AlignTop: + pixPoint = QPoint( (pTopLeft.x() + pTopRight.x()) / 2, + (pTopLeft.y() + pTopRight.y()) / 2 ); + break; + case Qt::AlignBottom: + pixPoint = QPoint( (pBotLeft.x() + pBotRight.x()) / 2, + (pBotLeft.y() + pBotRight.y()) / 2 ); + break; + case Qt::AlignVCenter: + default: + pixPoint = QPoint( (pTopLeft.x() + pBotRight.x()) / 2, + (pTopLeft.y() + pBotRight.y()) / 2 ); + break; + } + break; + } + //qDebug("2.: (x / y) : "+QString::number(x) + // +" / "+QString::number(y)); + painter->drawPixmap( QPoint( x - pixPoint.x(), + y - pixPoint.y() ), + theRotatedPixmap ); + p.end(); + } + } + + if( mustBackrotate ) + painter->rotate( -degrees ); + + if( fontChanged ) + painter->setFont( oldFont ); +} + + -- cgit v1.2.1