diff options
Diffstat (limited to 'libkdchart/KDChartCustomBox.cpp')
-rw-r--r-- | libkdchart/KDChartCustomBox.cpp | 495 |
1 files changed, 495 insertions, 0 deletions
diff --git a/libkdchart/KDChartCustomBox.cpp b/libkdchart/KDChartCustomBox.cpp new file mode 100644 index 0000000..4f765f0 --- /dev/null +++ b/libkdchart/KDChartCustomBox.cpp @@ -0,0 +1,495 @@ +/* -*- 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 <qpainter.h> +#include <qregion.h> +#include <qpalette.h> +#include <qpoint.h> +#include <qsimplerichtext.h> +#include <qpaintdevicemetrics.h> + +#include <KDChartCustomBox.h> +#include <KDXMLTools.h> +#include <KDFrame.h> + + + +KDChartCustomBox::~KDChartCustomBox() +{ + // Intentionally left blank for now. +} + + +void KDChartCustomBox::deepCopy( const KDChartCustomBox* source ) +{ + if( !source || this == source ) + return; + _rotation = source->_rotation; + _content.deepCopy( &source->_content); + _fontSize = source->_fontSize; + _fontScaleGlobal = source->_fontScaleGlobal; + _deltaX = source->_deltaX; + _deltaY = source->_deltaY; + _width = source->_width; + _height = source->_height; + _color = source->_color; + _paper = source->_paper; + _anchorArea = source->_anchorArea; + _anchorPos = source->_anchorPos; + _anchorAlign = source->_anchorAlign; + _dataRow = source->_dataRow; + _dataCol = source->_dataCol; + _data3rd = source->_data3rd; + _deltaAlign = source->_deltaAlign; + _deltaScaleGlobal = source->_deltaScaleGlobal; + _anchorBeingCalculated = source->_anchorBeingCalculated; + _parentAxisArea = source->_parentAxisArea; +} + +const KDChartCustomBox* KDChartCustomBox::clone() const +{ + KDChartCustomBox* newBox = new KDChartCustomBox(); + newBox->deepCopy( this ); + return newBox; +} + + +float KDChartCustomBox::trueFontSize( double areaWidthP1000, + double areaHeightP1000, + int rectHeight ) const +{ + float size; + if( 0 > _fontSize ) { + if( _fontScaleGlobal ) { + + size = _fontSize * QMIN(areaWidthP1000, areaHeightP1000) * -1.0;//(areaWidthP1000 + areaHeightP1000) / -2.0; + + } else { + + // calculate the exact size: + float targetLineSpacing = (_fontSize * rectHeight)/ -1000; + size = targetLineSpacing; + // step #1 - try to make the right font size: + QFont font( content().font() ); + font.setPointSizeFloat( size ); + QFontMetrics fm( font ); + //qDebug(QString("\nsize : ")+QString::number(size)); + //qDebug(QString("(float)rectHeight : ")+QString::number((float)rectHeight)); + //qDebug(QString("(float)fm.lineSpacing(): ")+QString::number((float)fm.lineSpacing())); + size *= targetLineSpacing / fm.lineSpacing(); + //qDebug(QString("size : ")+QString::number(size)); + // step #2 - make sure the font size is not too big: + font.setPointSizeFloat( size ); + QFontMetrics fm2( font ); + size *= targetLineSpacing / fm2.lineSpacing(); + //qDebug(QString("(float)rectHeight : ")+QString::number((float)rectHeight)); + //qDebug(QString("(float)fm.lineSpacing(): ")+QString::number((float)fm.lineSpacing())); + //qDebug(QString("size : ")+QString::number(size)); + } + } + else { +//qDebug(QString("\n_fontsize: ")+QString::number(_fontSize)); + if( _fontSize ) + size = _fontSize; + else{ + size = content().font().pointSize(); + if( -1 == size ) + size = content().font().pixelSize(); + if( -1 == size ) + size = 10; + } + } + return size; +} + + +int KDChartCustomBox::trueFontLineSpacing( double areaWidthP1000, + double areaHeightP1000, + int rectHeight ) const +{ + QFont font( content().font() ); + font.setPointSizeFloat( trueFontSize( areaWidthP1000,areaHeightP1000, rectHeight ) ); + QFontMetrics fm( font ); + return fm.lineSpacing(); +} + + +void KDChartCustomBox::getTrueShift( double areaWidthP1000, + double areaHeightP1000, + int rectHeight, + int& dX, + int& dY ) const +{ + int x, y; + if( _deltaScaleGlobal ){ + x = (0 > _deltaX) ? static_cast < int > ( -areaWidthP1000 * _deltaX ) : _deltaX; + y = (0 > _deltaY) ? static_cast < int > ( -areaHeightP1000 * _deltaY ) : _deltaY; + }else{ + int fontHeight = trueFontLineSpacing( areaWidthP1000, areaHeightP1000, rectHeight ); + //qDebug("\nfontHeight %i",fontHeight); + x = (0 > _deltaX) ? static_cast < int > ( fontHeight * _deltaX / -100.0 ) : _deltaX; + y = (0 > _deltaY) ? static_cast < int > ( fontHeight * _deltaY / -100.0 ) : _deltaY; + //qDebug("y %i",y); + } + uint deltaAlign = (KDCHART_AlignAuto == _deltaAlign) ? _anchorAlign : _deltaAlign; + if ( Qt::AlignLeft == (Qt::AlignLeft & deltaAlign) ) + dX = x; + else if ( Qt::AlignRight == (Qt::AlignRight & deltaAlign) ) + dX = -x; + else + dX = 0; // <-- so the _deltaX value becomes ineffective! + + if ( Qt::AlignTop == (Qt::AlignTop & deltaAlign) ) + dY = y; + else if ( Qt::AlignBottom == (Qt::AlignBottom & deltaAlign) ) + dY = -y; + else + dY = 0; // <-- so the _deltaY value becomes ineffective! +} + +QRect KDChartCustomBox::trueRect( QPainter * /*painter*/, QPoint /*anchor*/, double /*areaWidthP1000*/, double /*areaHeightP1000*/ ) const +{ + //temporary allow KDC_Presentation to compile + qDebug( "Sorry, not implemented yet: KDChartCustomBox::trueRect()" ); + return QRect( 1, 1, 2, 2 ); +} + +//static QPainter* pppainter=0; +//static int pdWidth =1280; +//static int pdHeight =1024; + +QRect KDChartCustomBox::trueRect( QPoint anchor, double areaWidthP1000, double areaHeightP1000 ) const +{ + int w = (0 > _width ) ? static_cast < int > ( -areaWidthP1000 * _width ) : _width; + int h = (0 > _height) ? static_cast < int > ( -areaHeightP1000 * _height ) : _height; + + //qDebug("w: %i h: %i", w,h ); + + if( _fontScaleGlobal && 0 == w && 0 == h ){ + //Now calculate the size of the box based upon the content! + QFont font( content().font() ); + if ( _fontSize ) { + font.setPointSizeFloat( + (0 > _fontSize) + ? (_fontSize * QMIN(areaWidthP1000, areaHeightP1000) * -1.0)//(areaWidthP1000 + areaHeightP1000) / -2.0 + : _fontSize ); + //qDebug("\n_fontSize * QMIN(areaWidthP1000, areaHeightP1000) %i * QMIN(%f, %f) text: %s", _fontSize , areaWidthP1000, areaHeightP1000, content().text().latin1()); + } + QString txt( content().text() ); + QString txtTest( txt.stripWhiteSpace().lower() ); +#if QT_VERSION >= 200 && QT_VERSION < 300 +// version 2.x + if( !(txtTest.left(4) == "<qt>") ) + txt.prepend( "<qt>" ); + if( !(txtTest.right(5)== "</qt>")) + txt.append( "</qt>"); +#else + if( !txtTest.startsWith("<qt>" ) ) + txt.prepend( "<qt>" ); + if( !txtTest.endsWith( "</qt>") ) + txt.append( "</qt>"); +#endif + + //qDebug("\nw: %i h: %i", w,h ); + QSimpleRichText tmpContent( txt, font ); +// tmpContent.setWidth(pdWidth); +// tmpContent.setHeight(pdHeight); +// tmpContent.adjustSize(); +// if( pppainter ){ +// tmpContent.setWidth(pppainter, 2000); +// tmpContent.adjustSize(); +// } + w = tmpContent.widthUsed(); + h = tmpContent.height(); + //qDebug("pdWidth: %i w: %i h %i",pdWidth,w,h); + //qDebug("w: %i h: %i", w,h ); + } + + //qDebug("\nw: %i h: %i", w,h ); + int x,y; + if ( Qt::AlignLeft == (Qt::AlignLeft & _anchorAlign) ) + x = 0; + else if ( Qt::AlignRight == (Qt::AlignRight & _anchorAlign) ) + x = - w + 1; + else + x = - w / 2; + + if ( Qt::AlignTop == (Qt::AlignTop & _anchorAlign) ) + y = 0; + else if ( Qt::AlignBottom == (Qt::AlignBottom & _anchorAlign) ) + y = - h + 1; + else + y = - h / 2; + int dX,dY; + getTrueShift( areaWidthP1000, areaHeightP1000, h, + dX, dY ); + //qDebug("trueRect: x %i y %i w %i h %i text: %s", anchor.x()+x+dX, anchor.y()+y+dY, w,h, content().text().latin1()); + + return QRect( anchor.x()+x+dX, anchor.y()+y+dY, w, h ); +} + + +int KDChartCustomBox::trueRectAlignX(const QRect& rect) const +{ + int ret = rect.center().x(); + if ( Qt::AlignLeft == (Qt::AlignLeft & _anchorAlign) ) + ret -= rect.width(); + else if ( Qt::AlignRight == (Qt::AlignRight & _anchorAlign) ) + ret += rect.width(); + return ret; +} +int KDChartCustomBox::trueRectAlignY(const QRect& rect) const +{ + int ret = rect.center().y(); + if ( Qt::AlignTop == (Qt::AlignTop & _anchorAlign) ) + ret -= rect.height(); + else if ( Qt::AlignBottom == (Qt::AlignBottom & _anchorAlign) ) + ret += rect.height(); + return ret; +} + +void KDChartCustomBox::paint( QPainter* painter, + QPoint anchor, + double areaWidthP1000, + double areaHeightP1000, + const KDFrame* frame, + const QRect& frameRect, + const QColor * color, + const QBrush * paper ) const +{ + painter->save(); + int rotDX = 0; + int rotDY = 0; +/* +//pppainter=painter; +const QPaintDeviceMetrics metrics(painter->device()); +pdWidth = metrics.width(); +const int aWidthP1000 = metrics.width() /1000; +const int aHeightP1000 = metrics.height()/1000; +//pdHeight = metrics.height(); +*/ + + QRect myRect( trueRect( anchor, areaWidthP1000, areaHeightP1000 ) ); + + + /* +QPaintDeviceMetrics metrics(painter->device()); +int pdWidth = metrics.width(); +int dpiY = metrics.logicalDpiY(); +int dpiX = metrics.logicalDpiX(); +qDebug("dpiY: %i dpiX: %i",dpiY,dpiX); +qDebug("pdWidth: %i box myRect w: %i h %i",pdWidth,myRect.width(),myRect.height()); + */ +//myRect.setSize(myRect.size()*6); + + + QRect myFrameRect( frameRect ); + if ( myRect.isValid() ) { +//qDebug("box myRect center: x %i y %i",myRect.center().x(),myRect.center().y()); + if( _rotation ){ + getTrueShift( areaWidthP1000, areaHeightP1000, myRect.height(), + rotDX, rotDY ); + myRect.moveBy( -rotDX, -rotDY ); + if( frame ) + myFrameRect.moveBy( -rotDX, -rotDY ); +//qDebug("\nrotDelta: x %i y %i",rotDX,rotDY); +//qDebug("\nbox myRect center: x %i y %i",myRect.center().x(),myRect.center().y()); + myRect.moveCenter( QPoint( anchor.x() - trueRectAlignX(myRect), + anchor.y() - trueRectAlignY(myRect) ) ); + if( frame ) + myFrameRect.moveCenter( QPoint( anchor.x() - trueRectAlignX(myFrameRect), + anchor.y() - trueRectAlignY(myFrameRect) ) ); +//qDebug("box myRect center: x %i y %i",myRect.center().x(),myRect.center().y()); + painter->translate( anchor.x(), anchor.y() ); + painter->rotate( _rotation ); + painter->translate( rotDX, rotDY ); + } + if( frame ) + frame->paint( painter, KDFrame::PaintAll, myFrameRect ); + if ( _fontSize ) { + QFont font( content().font() ); + + float trueSize = trueFontSize(areaWidthP1000,areaHeightP1000, myRect.height() ); + font.setPointSizeFloat( trueSize ); + //adjust the area height related to the font size + myRect.setHeight( (int)(trueSize )+ (int)(trueSize*0.5)); + const KDChartTextPiece tmpTextPiece( painter, content().text(), font ); + + tmpTextPiece.draw( painter, myRect.x(), myRect.y(), myRect, + color ? *color : _color, + paper ? paper : &_paper ); + }else{ + + content().draw( painter, myRect.x(), myRect.y(), myRect, + color ? *color : _color, + paper ? paper : &_paper ); + } + } + painter->restore(); +} + + +void KDChartCustomBox::createCustomBoxNode( QDomDocument& document, + QDomNode& parent, + const QString& elementName, + const KDChartCustomBox* custombox ) +{ + QDomElement customBoxElement = document.createElement( elementName ); + parent.appendChild( customBoxElement ); + KDXML::createIntNode( document, customBoxElement, "Rotation", custombox->_rotation ); + KDXML::createStringNode( document, customBoxElement, "ContentText", + custombox->_content.text() ); + KDXML::createFontNode( document, customBoxElement, "ContentFont", + custombox->_content.font() ); + KDXML::createIntNode( document, customBoxElement, "FontSize", custombox->_fontSize ); + KDXML::createBoolNode( document, customBoxElement, "FontScaleGlobal", + custombox->_fontScaleGlobal ); + KDXML::createIntNode( document, customBoxElement, "DeltaX", custombox->_deltaX ); + KDXML::createIntNode( document, customBoxElement, "DeltaY", custombox->_deltaY ); + KDXML::createIntNode( document, customBoxElement, "Width", custombox->_width ); + KDXML::createIntNode( document, customBoxElement, "Height", custombox->_height ); + KDXML::createColorNode( document, customBoxElement, "Color", custombox->_color ); + KDXML::createBrushNode( document, customBoxElement, "Paper", custombox->_paper ); + KDXML::createIntNode( document, customBoxElement, "AnchorArea", + custombox->_anchorArea ); + KDXML::createStringNode( document, customBoxElement, "AnchorPos", + KDChartEnums::positionFlagToString( custombox->_anchorPos ) ); + KDXML::createIntNode( document, customBoxElement, "AnchorAlign", + custombox->_anchorAlign ); + KDXML::createIntNode( document, customBoxElement, "DataRow", + custombox->_dataRow ); + KDXML::createIntNode( document, customBoxElement, "DataCol", + custombox->_dataCol ); + KDXML::createIntNode( document, customBoxElement, "Data3rd", + custombox->_data3rd ); + KDXML::createIntNode( document, customBoxElement, "DeltaAlign", + custombox->_deltaAlign ); + KDXML::createBoolNode( document, customBoxElement, "DeltaScaleGlobal", + custombox->_deltaScaleGlobal ); + KDXML::createIntNode( document, customBoxElement, "ParentAxisArea", + custombox->_parentAxisArea ); +} + + +bool KDChartCustomBox::readCustomBoxNode( const QDomElement& element, + KDChartCustomBox& custombox ) +{ + bool ok = true; + QString tempContentText; + QFont tempContentFont; + int tempRotation = 0; // must be initialized: new parameter, not present in old versions of KDChart + int tempDeltaAlign = KDCHART_AlignAuto; // must be initialized too: new parameter + bool tempDeltaScaleGlobal = true; // must be initialized too: new parameter + int tempFontSize, tempDeltaX, tempDeltaY, + tempWidth, tempHeight, tempAnchorArea, tempParentAxisArea, tempAnchorAlign, + tempDataRow, tempDataCol, tempData3rd; + bool tempFontScaleGlobal; + QColor tempColor; + QBrush tempPaper; + KDChartEnums::PositionFlag tempAnchorPos = KDChartEnums::PosTopLeft; + QDomNode node = element.firstChild(); + while( !node.isNull() ) { + QDomElement element = node.toElement(); + if( !element.isNull() ) { // was really an element + QString tagName = element.tagName(); + if( tagName == "Rotation" ) { + ok = ok & KDXML::readIntNode( element, tempRotation ); + } else if( tagName == "ContentText" ) { + ok = ok & KDXML::readStringNode( element, tempContentText ); + } else if( tagName == "ContentFont" ) { + ok = ok & KDXML::readFontNode( element, tempContentFont ); + } else if( tagName == "FontSize" ) { + ok = ok & KDXML::readIntNode( element, tempFontSize ); + } else if( tagName == "FontScaleGlobal" ) { + ok = ok & KDXML::readBoolNode( element, tempFontScaleGlobal ); + } else if( tagName == "DeltaX" ) { + ok = ok & KDXML::readIntNode( element, tempDeltaX ); + } else if( tagName == "DeltaY" ) { + ok = ok & KDXML::readIntNode( element, tempDeltaY ); + } else if( tagName == "Width" ) { + ok = ok & KDXML::readIntNode( element, tempWidth ); + } else if( tagName == "Height" ) { + ok = ok & KDXML::readIntNode( element, tempHeight ); + } else if( tagName == "Color" ) { + ok = ok & KDXML::readColorNode( element, tempColor ); + } else if( tagName == "Paper" ) { + ok = ok & KDXML::readBrushNode( element, tempPaper ); + } else if( tagName == "AnchorArea" ) { + ok = ok & KDXML::readIntNode( element, tempAnchorArea ); + } else if( tagName == "AnchorPos" ) { + QString value; + ok = ok & KDXML::readStringNode( element, value ); + tempAnchorPos = KDChartEnums::stringToPositionFlag( value ); + } else if( tagName == "AnchorAlign" ) { + ok = ok & KDXML::readIntNode( element, tempAnchorAlign ); + } else if( tagName == "DataRow" ) { + ok = ok & KDXML::readIntNode( element, tempDataRow ); + } else if( tagName == "DataCol" ) { + ok = ok & KDXML::readIntNode( element, tempDataCol ); + } else if( tagName == "Data3rd" ) { + ok = ok & KDXML::readIntNode( element, tempData3rd ); + } else if( tagName == "DeltaAlign" ) { + ok = ok & KDXML::readIntNode( element, tempDeltaAlign ); + } else if( tagName == "DeltaScaleGlobal" ) { + ok = ok & KDXML::readBoolNode( element, tempDeltaScaleGlobal ); + } else if ( tagName == "ParentAxisArea" ) { + ok = ok & KDXML::readIntNode( element, tempParentAxisArea ); + } else { + qDebug( "Unknown tag in custom box" ); + } + } + node = node.nextSibling(); + } + + if( ok ) { + const KDChartTextPiece piece( 0, tempContentText, tempContentFont ); + custombox._content.deepCopy( &piece ); + custombox._rotation = tempRotation; + custombox._fontSize = tempFontSize; + custombox._fontScaleGlobal = tempFontScaleGlobal; + custombox._deltaX = tempDeltaX; + custombox._deltaY = tempDeltaY; + custombox._width = tempWidth; + custombox._height = tempHeight; + custombox._color = tempColor; + custombox._paper = tempPaper; + custombox._anchorArea = tempAnchorArea; + custombox._anchorPos = tempAnchorPos; + custombox._anchorAlign = tempAnchorAlign; + custombox._dataRow = tempDataRow; + custombox._dataCol = tempDataCol; + custombox._data3rd = tempData3rd; + custombox._deltaAlign = tempDeltaAlign; + custombox._deltaScaleGlobal = tempDeltaScaleGlobal; + custombox._parentAxisArea = tempParentAxisArea; + } + + return ok; +} + +#include "KDChartCustomBox.moc" |