You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmymoney/libkdchart/KDChartCustomBox.cpp

488 lines
20 KiB

/* -*- 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 <tqpainter.h>
#include <tqregion.h>
#include <palette.h>
#include <tqpoint.h>
#include <tqsimplerichtext.h>
#include <tqpaintdevicemetrics.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 * TQMIN(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:
TQFont font( content().font() );
font.setPointSizeFloat( size );
TQFontMetrics fm( font );
//qDebug(TQString("\nsize : ")+TQString::number(size));
//qDebug(TQString("(float)rectHeight : ")+TQString::number((float)rectHeight));
//qDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
size *= targetLineSpacing / fm.lineSpacing();
//qDebug(TQString("size : ")+TQString::number(size));
// step #2 - make sure the font size is not too big:
font.setPointSizeFloat( size );
TQFontMetrics fm2( font );
size *= targetLineSpacing / fm2.lineSpacing();
//qDebug(TQString("(float)rectHeight : ")+TQString::number((float)rectHeight));
//qDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
//qDebug(TQString("size : ")+TQString::number(size));
}
}
else {
//qDebug(TQString("\n_fontsize: ")+TQString::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
{
TQFont font( content().font() );
font.setPointSizeFloat( trueFontSize( areaWidthP1000,areaHeightP1000, rectHeight ) );
TQFontMetrics 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 ( TQt::AlignLeft == (TQt::AlignLeft & deltaAlign) )
dX = x;
else if ( TQt::AlignRight == (TQt::AlignRight & deltaAlign) )
dX = -x;
else
dX = 0; // <-- so the _deltaX value becomes ineffective!
if ( TQt::AlignTop == (TQt::AlignTop & deltaAlign) )
dY = y;
else if ( TQt::AlignBottom == (TQt::AlignBottom & deltaAlign) )
dY = -y;
else
dY = 0; // <-- so the _deltaY value becomes ineffective!
}
TQRect KDChartCustomBox::trueRect( TQPainter * /*painter*/, TQPoint /*anchor*/, double /*areaWidthP1000*/, double /*areaHeightP1000*/ ) const
{
//temporary allow KDC_Presentation to compile
qDebug( "Sorry, not implemented yet: KDChartCustomBox::trueRect()" );
return TQRect( 1, 1, 2, 2 );
}
//static TQPainter* pppainter=0;
//static int pdWidth =1280;
//static int pdHeight =1024;
TQRect KDChartCustomBox::trueRect( TQPoint 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!
TQFont font( content().font() );
if ( _fontSize ) {
font.setPointSizeFloat(
(0 > _fontSize)
? (_fontSize * TQMIN(areaWidthP1000, areaHeightP1000) * -1.0)//(areaWidthP1000 + areaHeightP1000) / -2.0
: _fontSize );
//qDebug("\n_fontSize * TQMIN(areaWidthP1000, areaHeightP1000) %i * TQMIN(%f, %f) text: %s", _fontSize , areaWidthP1000, areaHeightP1000, content().text().latin1());
}
TQString txt( content().text() );
TQString txtTest( txt.stripWhiteSpace().lower() );
if( !txtTest.startsWith("<qt>" ) )
txt.prepend( "<qt>" );
if( !txtTest.endsWith( "</qt>") )
txt.append( "</qt>");
//qDebug("\nw: %i h: %i", w,h );
TQSimpleRichText 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 ( TQt::AlignLeft == (TQt::AlignLeft & _anchorAlign) )
x = 0;
else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
x = - w + 1;
else
x = - w / 2;
if ( TQt::AlignTop == (TQt::AlignTop & _anchorAlign) )
y = 0;
else if ( TQt::AlignBottom == (TQt::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 TQRect( anchor.x()+x+dX, anchor.y()+y+dY, w, h );
}
int KDChartCustomBox::trueRectAlignX(const TQRect& rect) const
{
int ret = rect.center().x();
if ( TQt::AlignLeft == (TQt::AlignLeft & _anchorAlign) )
ret -= rect.width();
else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
ret += rect.width();
return ret;
}
int KDChartCustomBox::trueRectAlignY(const TQRect& rect) const
{
int ret = rect.center().y();
if ( TQt::AlignTop == (TQt::AlignTop & _anchorAlign) )
ret -= rect.height();
else if ( TQt::AlignBottom == (TQt::AlignBottom & _anchorAlign) )
ret += rect.height();
return ret;
}
void KDChartCustomBox::paint( TQPainter* painter,
TQPoint anchor,
double areaWidthP1000,
double areaHeightP1000,
const KDFrame* frame,
const TQRect& frameRect,
const TQColor * color,
const TQBrush * paper ) const
{
painter->save();
int rotDX = 0;
int rotDY = 0;
/*
//pppainter=painter;
const TQPaintDeviceMetrics metrics(painter->device());
pdWidth = metrics.width();
const int aWidthP1000 = metrics.width() /1000;
const int aHeightP1000 = metrics.height()/1000;
//pdHeight = metrics.height();
*/
TQRect myRect( trueRect( anchor, areaWidthP1000, areaHeightP1000 ) );
/*
TQPaintDeviceMetrics 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);
TQRect 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( TQPoint( anchor.x() - trueRectAlignX(myRect),
anchor.y() - trueRectAlignY(myRect) ) );
if( frame )
myFrameRect.moveCenter( TQPoint( 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 ) {
TQFont 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( TQDomDocument& document,
TQDomNode& parent,
const TQString& elementName,
const KDChartCustomBox* custombox )
{
TQDomElement 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 TQDomElement& element,
KDChartCustomBox& custombox )
{
bool ok = true;
TQString tempContentText;
TQFont 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;
TQColor tempColor;
TQBrush tempPaper;
KDChartEnums::PositionFlag tempAnchorPos = KDChartEnums::PosTopLeft;
TQDomNode node = element.firstChild();
while( !node.isNull() ) {
TQDomElement element = node.toElement();
if( !element.isNull() ) { // was really an element
TQString 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" ) {
TQString 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"