kchart

KDChartCustomBox.cpp
1/*
2 KDChart - a multi-platform charting engine
3 */
4
5/****************************************************************************
6 ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB. All rights reserved.
7 **
8 ** This file is part of the KDChart library.
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file LICENSE.GPL included in the
13 ** packaging of this file.
14 **
15 ** Licensees holding valid commercial KDChart licenses may use this file in
16 ** accordance with the KDChart Commercial License Agreement provided with
17 ** the Software.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ** See http://www.klaralvdalens-datakonsult.se/?page=products for
23 ** information about KDChart Commercial License Agreements.
24 **
25 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
26 ** licensing are not clear to you.
27 **
28 **********************************************************************/
29#include <tqpainter.h>
30#include <tqregion.h>
31#include <tqpalette.h>
32#include <tqpoint.h>
33#include <tqsimplerichtext.h>
34#include <tqpaintdevicemetrics.h>
35
36#include <KDChartCustomBox.h>
37#include <KDXMLTools.h>
38#include <KDFrame.h>
39
40
41
43{
44 // Intentionally left blank for now.
45}
46
47
49{
50 if( !source || this == source )
51 return;
52 _rotation = source->_rotation;
53 _content.deepCopy( &source->_content);
54 _fontSize = source->_fontSize;
55 _fontScaleGlobal = source->_fontScaleGlobal;
56 _deltaX = source->_deltaX;
57 _deltaY = source->_deltaY;
58 _width = source->_width;
59 _height = source->_height;
60 _color = source->_color;
61 _paper = source->_paper;
62 _anchorArea = source->_anchorArea;
63 _anchorPos = source->_anchorPos;
64 _anchorAlign = source->_anchorAlign;
65 _dataRow = source->_dataRow;
66 _dataCol = source->_dataCol;
67 _data3rd = source->_data3rd;
68 _deltaAlign = source->_deltaAlign;
69 _deltaScaleGlobal = source->_deltaScaleGlobal;
70 _anchorBeingCalculated = source->_anchorBeingCalculated;
71 _parentAxisArea = source->_parentAxisArea;
72}
73
75{
76 KDChartCustomBox* newBox = new KDChartCustomBox();
77 newBox->deepCopy( this );
78 return newBox;
79}
80
81
82float KDChartCustomBox::trueFontSize( double areaWidthP1000,
83 double areaHeightP1000,
84 int rectHeight ) const
85{
86 float size;
87 if( 0 > _fontSize ) {
88 if( _fontScaleGlobal ) {
89
90 size = _fontSize * TQMIN(areaWidthP1000, areaHeightP1000) * -1.0;//(areaWidthP1000 + areaHeightP1000) / -2.0;
91
92 } else {
93
94 // calculate the exact size:
95 float targetLineSpacing = (_fontSize * rectHeight)/ -1000;
96 size = targetLineSpacing;
97 // step #1 - try to make the right font size:
98 TQFont font( content().font() );
99 font.setPointSizeFloat( size );
100 TQFontMetrics fm( font );
101 //tqDebug(TQString("\nsize : ")+TQString::number(size));
102 //tqDebug(TQString("(float)rectHeight : ")+TQString::number((float)rectHeight));
103 //tqDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
104 size *= targetLineSpacing / fm.lineSpacing();
105 //tqDebug(TQString("size : ")+TQString::number(size));
106 // step #2 - make sure the font size is not too big:
107 font.setPointSizeFloat( size );
108 TQFontMetrics fm2( font );
109 size *= targetLineSpacing / fm2.lineSpacing();
110 //tqDebug(TQString("(float)rectHeight : ")+TQString::number((float)rectHeight));
111 //tqDebug(TQString("(float)fm.lineSpacing(): ")+TQString::number((float)fm.lineSpacing()));
112 //tqDebug(TQString("size : ")+TQString::number(size));
113 }
114 }
115 else {
116//tqDebug(TQString("\n_fontsize: ")+TQString::number(_fontSize));
117 if( _fontSize )
118 size = _fontSize;
119 else{
120 size = content().font().pointSize();
121 if( -1 == size )
122 size = content().font().pixelSize();
123 if( -1 == size )
124 size = 10;
125 }
126 }
127 return size;
128}
129
130
131int KDChartCustomBox::trueFontLineSpacing( double areaWidthP1000,
132 double areaHeightP1000,
133 int rectHeight ) const
134{
135 TQFont font( content().font() );
136 font.setPointSizeFloat( trueFontSize( areaWidthP1000,areaHeightP1000, rectHeight ) );
137 TQFontMetrics fm( font );
138 return fm.lineSpacing();
139}
140
141
142void KDChartCustomBox::getTrueShift( double areaWidthP1000,
143 double areaHeightP1000,
144 int rectHeight,
145 int& dX,
146 int& dY ) const
147{
148 int x, y;
149 if( _deltaScaleGlobal ){
150 x = (0 > _deltaX) ? static_cast < int > ( -areaWidthP1000 * _deltaX ) : _deltaX;
151 y = (0 > _deltaY) ? static_cast < int > ( -areaHeightP1000 * _deltaY ) : _deltaY;
152 }else{
153 int fontHeight = trueFontLineSpacing( areaWidthP1000, areaHeightP1000, rectHeight );
154 //tqDebug("\nfontHeight %i",fontHeight);
155 x = (0 > _deltaX) ? static_cast < int > ( fontHeight * _deltaX / -100.0 ) : _deltaX;
156 y = (0 > _deltaY) ? static_cast < int > ( fontHeight * _deltaY / -100.0 ) : _deltaY;
157 //tqDebug("y %i",y);
158 }
159 uint deltaAlign = (KDCHART_AlignAuto == _deltaAlign) ? _anchorAlign : _deltaAlign;
160 if ( TQt::AlignLeft == (TQt::AlignLeft & deltaAlign) )
161 dX = x;
162 else if ( TQt::AlignRight == (TQt::AlignRight & deltaAlign) )
163 dX = -x;
164 else
165 dX = 0; // <-- so the _deltaX value becomes ineffective!
166
167 if ( TQt::AlignTop == (TQt::AlignTop & deltaAlign) )
168 dY = y;
169 else if ( TQt::AlignBottom == (TQt::AlignBottom & deltaAlign) )
170 dY = -y;
171 else
172 dY = 0; // <-- so the _deltaY value becomes ineffective!
173}
174
175TQRect KDChartCustomBox::trueRect( TQPainter * /*painter*/, TQPoint /*anchor*/, double /*areaWidthP1000*/, double /*areaHeightP1000*/ ) const
176{
177 //temporary allow KDC_Presentation to compile
178 tqDebug( "Sorry, not implemented yet: KDChartCustomBox::trueRect()" );
179 return TQRect( 1, 1, 2, 2 );
180}
181
182//static TQPainter* pppainter=0;
183//static int pdWidth =1280;
184//static int pdHeight =1024;
185
186TQRect KDChartCustomBox::trueRect( TQPoint anchor, double areaWidthP1000, double areaHeightP1000 ) const
187{
188 int w = (0 > _width ) ? static_cast < int > ( -areaWidthP1000 * _width ) : _width;
189 int h = (0 > _height) ? static_cast < int > ( -areaHeightP1000 * _height ) : _height;
190
191 //tqDebug("w: %i h: %i", w,h );
192
193 if( _fontScaleGlobal && 0 == w && 0 == h ){
194 //Now calculate the size of the box based upon the content!
195 TQFont font( content().font() );
196 if ( _fontSize ) {
197 font.setPointSizeFloat(
198 (0 > _fontSize)
199 ? (_fontSize * TQMIN(areaWidthP1000, areaHeightP1000) * -1.0)//(areaWidthP1000 + areaHeightP1000) / -2.0
200 : _fontSize );
201 //tqDebug("\n_fontSize * TQMIN(areaWidthP1000, areaHeightP1000) %i * TQMIN(%f, %f) text: %s", _fontSize , areaWidthP1000, areaHeightP1000, content().text().latin1());
202 }
203 TQString txt( content().text() );
204 TQString txtTest( txt.stripWhiteSpace().lower() );
205 if( !txtTest.startsWith("<qt>" ) )
206 txt.prepend( "<qt>" );
207 if( !txtTest.endsWith( "</qt>") )
208 txt.append( "</qt>");
209
210 //tqDebug("\nw: %i h: %i", w,h );
211 TQSimpleRichText tmpContent( txt, font );
212// tmpContent.setWidth(pdWidth);
213// tmpContent.setHeight(pdHeight);
214// tmpContent.adjustSize();
215// if( pppainter ){
216// tmpContent.setWidth(pppainter, 2000);
217// tmpContent.adjustSize();
218// }
219 w = tmpContent.widthUsed();
220 h = tmpContent.height();
221 //tqDebug("pdWidth: %i w: %i h %i",pdWidth,w,h);
222 //tqDebug("w: %i h: %i", w,h );
223 }
224
225 //tqDebug("\nw: %i h: %i", w,h );
226 int x,y;
227 if ( TQt::AlignLeft == (TQt::AlignLeft & _anchorAlign) )
228 x = 0;
229 else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
230 x = - w + 1;
231 else
232 x = - w / 2;
233
234 if ( TQt::AlignTop == (TQt::AlignTop & _anchorAlign) )
235 y = 0;
236 else if ( TQt::AlignBottom == (TQt::AlignBottom & _anchorAlign) )
237 y = - h + 1;
238 else
239 y = - h / 2;
240 int dX,dY;
241 getTrueShift( areaWidthP1000, areaHeightP1000, h,
242 dX, dY );
243 //tqDebug("trueRect: x %i y %i w %i h %i text: %s", anchor.x()+x+dX, anchor.y()+y+dY, w,h, content().text().latin1());
244
245 return TQRect( anchor.x()+x+dX, anchor.y()+y+dY, w, h );
246}
247
248
249int KDChartCustomBox::trueRectAlignX(const TQRect& rect) const
250{
251 int ret = rect.center().x();
252 if ( TQt::AlignLeft == (TQt::AlignLeft & _anchorAlign) )
253 ret -= rect.width();
254 else if ( TQt::AlignRight == (TQt::AlignRight & _anchorAlign) )
255 ret += rect.width();
256 return ret;
257}
258int KDChartCustomBox::trueRectAlignY(const TQRect& rect) const
259{
260 int ret = rect.center().y();
261 if ( TQt::AlignTop == (TQt::AlignTop & _anchorAlign) )
262 ret -= rect.height();
263 else if ( TQt::AlignBottom == (TQt::AlignBottom & _anchorAlign) )
264 ret += rect.height();
265 return ret;
266}
267
268void KDChartCustomBox::paint( TQPainter* painter,
269 TQPoint anchor,
270 double areaWidthP1000,
271 double areaHeightP1000,
272 const KDFrame* frame,
273 const TQRect& frameRect,
274 const TQColor * color,
275 const TQBrush * paper ) const
276{
277 painter->save();
278 int rotDX = 0;
279 int rotDY = 0;
280/*
281//pppainter=painter;
282const TQPaintDeviceMetrics metrics(painter->device());
283pdWidth = metrics.width();
284const int aWidthP1000 = metrics.width() /1000;
285const int aHeightP1000 = metrics.height()/1000;
286//pdHeight = metrics.height();
287*/
288
289 TQRect myRect( trueRect( anchor, areaWidthP1000, areaHeightP1000 ) );
290
291
292 /*
293TQPaintDeviceMetrics metrics(painter->device());
294int pdWidth = metrics.width();
295int dpiY = metrics.logicalDpiY();
296int dpiX = metrics.logicalDpiX();
297tqDebug("dpiY: %i dpiX: %i",dpiY,dpiX);
298tqDebug("pdWidth: %i box myRect w: %i h %i",pdWidth,myRect.width(),myRect.height());
299 */
300//myRect.setSize(myRect.size()*6);
301
302
303 TQRect myFrameRect( frameRect );
304 if ( myRect.isValid() ) {
305//tqDebug("box myRect center: x %i y %i",myRect.center().x(),myRect.center().y());
306 if( _rotation ){
307 getTrueShift( areaWidthP1000, areaHeightP1000, myRect.height(),
308 rotDX, rotDY );
309 myRect.moveBy( -rotDX, -rotDY );
310 if( frame )
311 myFrameRect.moveBy( -rotDX, -rotDY );
312//tqDebug("\nrotDelta: x %i y %i",rotDX,rotDY);
313//tqDebug("\nbox myRect center: x %i y %i",myRect.center().x(),myRect.center().y());
314 myRect.moveCenter( TQPoint( anchor.x() - trueRectAlignX(myRect),
315 anchor.y() - trueRectAlignY(myRect) ) );
316 if( frame )
317 myFrameRect.moveCenter( TQPoint( anchor.x() - trueRectAlignX(myFrameRect),
318 anchor.y() - trueRectAlignY(myFrameRect) ) );
319//tqDebug("box myRect center: x %i y %i",myRect.center().x(),myRect.center().y());
320 painter->translate( anchor.x(), anchor.y() );
321 painter->rotate( _rotation );
322 painter->translate( rotDX, rotDY );
323 }
324 if( frame )
325 frame->paint( painter, KDFrame::PaintAll, myFrameRect );
326 if ( _fontSize ) {
327 TQFont font( content().font() );
328
329 float trueSize = trueFontSize(areaWidthP1000,areaHeightP1000, myRect.height() );
330 font.setPointSizeFloat( trueSize );
331 //adjust the area height related to the font size
332 myRect.setHeight( (int)(trueSize )+ (int)(trueSize*0.5));
333 const KDChartTextPiece tmpTextPiece( painter, content().text(), font );
334
335 tmpTextPiece.draw( painter, myRect.x(), myRect.y(), myRect,
336 color ? *color : _color,
337 paper ? paper : &_paper );
338 }else{
339
340 content().draw( painter, myRect.x(), myRect.y(), myRect,
341 color ? *color : _color,
342 paper ? paper : &_paper );
343 }
344 }
345 painter->restore();
346}
347
348
349void KDChartCustomBox::createCustomBoxNode( TQDomDocument& document,
350 TQDomNode& parent,
351 const TQString& elementName,
352 const KDChartCustomBox* custombox )
353{
354 TQDomElement customBoxElement = document.createElement( elementName );
355 parent.appendChild( customBoxElement );
356 KDXML::createIntNode( document, customBoxElement, "Rotation", custombox->_rotation );
357 KDXML::createStringNode( document, customBoxElement, "ContentText",
358 custombox->_content.text() );
359 KDXML::createFontNode( document, customBoxElement, "ContentFont",
360 custombox->_content.font() );
361 KDXML::createIntNode( document, customBoxElement, "FontSize", custombox->_fontSize );
362 KDXML::createBoolNode( document, customBoxElement, "FontScaleGlobal",
363 custombox->_fontScaleGlobal );
364 KDXML::createIntNode( document, customBoxElement, "DeltaX", custombox->_deltaX );
365 KDXML::createIntNode( document, customBoxElement, "DeltaY", custombox->_deltaY );
366 KDXML::createIntNode( document, customBoxElement, "Width", custombox->_width );
367 KDXML::createIntNode( document, customBoxElement, "Height", custombox->_height );
368 KDXML::createColorNode( document, customBoxElement, "Color", custombox->_color );
369 KDXML::createBrushNode( document, customBoxElement, "Paper", custombox->_paper );
370 KDXML::createIntNode( document, customBoxElement, "AnchorArea",
371 custombox->_anchorArea );
372 KDXML::createStringNode( document, customBoxElement, "AnchorPos",
373 KDChartEnums::positionFlagToString( custombox->_anchorPos ) );
374 KDXML::createIntNode( document, customBoxElement, "AnchorAlign",
375 custombox->_anchorAlign );
376 KDXML::createIntNode( document, customBoxElement, "DataRow",
377 custombox->_dataRow );
378 KDXML::createIntNode( document, customBoxElement, "DataCol",
379 custombox->_dataCol );
380 KDXML::createIntNode( document, customBoxElement, "Data3rd",
381 custombox->_data3rd );
382 KDXML::createIntNode( document, customBoxElement, "DeltaAlign",
383 custombox->_deltaAlign );
384 KDXML::createBoolNode( document, customBoxElement, "DeltaScaleGlobal",
385 custombox->_deltaScaleGlobal );
386 KDXML::createIntNode( document, customBoxElement, "ParentAxisArea",
387 custombox->_parentAxisArea );
388}
389
390
391bool KDChartCustomBox::readCustomBoxNode( const TQDomElement& element,
392 KDChartCustomBox& custombox )
393{
394 bool ok = true;
395 TQString tempContentText;
396 TQFont tempContentFont;
397 int tempRotation = 0; // must be initialized: new parameter, not present in old versions of KDChart
398 int tempDeltaAlign = KDCHART_AlignAuto; // must be initialized too: new parameter
399 bool tempDeltaScaleGlobal = true; // must be initialized too: new parameter
400 int tempFontSize, tempDeltaX, tempDeltaY,
401 tempWidth, tempHeight, tempAnchorArea, tempParentAxisArea, tempAnchorAlign,
402 tempDataRow, tempDataCol, tempData3rd;
403 bool tempFontScaleGlobal;
404 TQColor tempColor;
405 TQBrush tempPaper;
406 KDChartEnums::PositionFlag tempAnchorPos = KDChartEnums::PosTopLeft;
407 TQDomNode node = element.firstChild();
408 while( !node.isNull() ) {
409 TQDomElement element = node.toElement();
410 if( !element.isNull() ) { // was really an element
411 TQString tagName = element.tagName();
412 if( tagName == "Rotation" ) {
413 ok = ok & KDXML::readIntNode( element, tempRotation );
414 } else if( tagName == "ContentText" ) {
415 ok = ok & KDXML::readStringNode( element, tempContentText );
416 } else if( tagName == "ContentFont" ) {
417 ok = ok & KDXML::readFontNode( element, tempContentFont );
418 } else if( tagName == "FontSize" ) {
419 ok = ok & KDXML::readIntNode( element, tempFontSize );
420 } else if( tagName == "FontScaleGlobal" ) {
421 ok = ok & KDXML::readBoolNode( element, tempFontScaleGlobal );
422 } else if( tagName == "DeltaX" ) {
423 ok = ok & KDXML::readIntNode( element, tempDeltaX );
424 } else if( tagName == "DeltaY" ) {
425 ok = ok & KDXML::readIntNode( element, tempDeltaY );
426 } else if( tagName == "Width" ) {
427 ok = ok & KDXML::readIntNode( element, tempWidth );
428 } else if( tagName == "Height" ) {
429 ok = ok & KDXML::readIntNode( element, tempHeight );
430 } else if( tagName == "Color" ) {
431 ok = ok & KDXML::readColorNode( element, tempColor );
432 } else if( tagName == "Paper" ) {
433 ok = ok & KDXML::readBrushNode( element, tempPaper );
434 } else if( tagName == "AnchorArea" ) {
435 ok = ok & KDXML::readIntNode( element, tempAnchorArea );
436 } else if( tagName == "AnchorPos" ) {
437 TQString value;
438 ok = ok & KDXML::readStringNode( element, value );
439 tempAnchorPos = KDChartEnums::stringToPositionFlag( value );
440 } else if( tagName == "AnchorAlign" ) {
441 ok = ok & KDXML::readIntNode( element, tempAnchorAlign );
442 } else if( tagName == "DataRow" ) {
443 ok = ok & KDXML::readIntNode( element, tempDataRow );
444 } else if( tagName == "DataCol" ) {
445 ok = ok & KDXML::readIntNode( element, tempDataCol );
446 } else if( tagName == "Data3rd" ) {
447 ok = ok & KDXML::readIntNode( element, tempData3rd );
448 } else if( tagName == "DeltaAlign" ) {
449 ok = ok & KDXML::readIntNode( element, tempDeltaAlign );
450 } else if( tagName == "DeltaScaleGlobal" ) {
451 ok = ok & KDXML::readBoolNode( element, tempDeltaScaleGlobal );
452 } else if ( tagName == "ParentAxisArea" ) {
453 ok = ok & KDXML::readIntNode( element, tempParentAxisArea );
454 } else {
455 tqDebug( "Unknown tag in custom box" );
456 }
457 }
458 node = node.nextSibling();
459 }
460
461 if( ok ) {
462 const KDChartTextPiece piece( 0, tempContentText, tempContentFont );
463 custombox._content.deepCopy( &piece );
464 custombox._rotation = tempRotation;
465 custombox._fontSize = tempFontSize;
466 custombox._fontScaleGlobal = tempFontScaleGlobal;
467 custombox._deltaX = tempDeltaX;
468 custombox._deltaY = tempDeltaY;
469 custombox._width = tempWidth;
470 custombox._height = tempHeight;
471 custombox._color = tempColor;
472 custombox._paper = tempPaper;
473 custombox._anchorArea = tempAnchorArea;
474 custombox._anchorPos = tempAnchorPos;
475 custombox._anchorAlign = tempAnchorAlign;
476 custombox._dataRow = tempDataRow;
477 custombox._dataCol = tempDataCol;
478 custombox._data3rd = tempData3rd;
479 custombox._deltaAlign = tempDeltaAlign;
480 custombox._deltaScaleGlobal = tempDeltaScaleGlobal;
481 custombox._parentAxisArea = tempParentAxisArea;
482 }
483
484 return ok;
485}
486
487#include "KDChartCustomBox.moc"
Definition of a class for specifying and drawing custom boxes.
Header of the KDFrame class providing highly configurable rectangular frame drawing.
Class for specifying and drawing custom boxes.
const TQBrush & paper() const
Returns the background brush.
uint deltaAlign() const
Returns the way how the values specified for deltaX and/or deltaY affect the position of the box.
const KDChartTextPiece & content() const
Returns the text piece content that is to be drawn.
virtual void paint(TQPainter *painter, TQPoint anchor, double areaWidthP1000, double areaHeightP1000, const KDFrame *frame=0, const TQRect &frameRect=TQRect(), const TQColor *color=0, const TQBrush *paper=0) const
Paints the box.
void deepCopy(const KDChartCustomBox *source)
Copy the settings of box source into this box.
const KDChartCustomBox * clone() const
Create a new box on the heap, copy the settings stored by this box into the newly created box and ret...
TQColor color() const
Returns the text color.
TQRect trueRect(TQPainter *painter, TQPoint anchor, double areaWidthP1000, double areaHeightP1000) const
Return the actual rectangle which to draw box into.
static bool readCustomBoxNode(const TQDomElement &element, KDChartCustomBox &custombox)
Reads data from a DOM element node that represents a custom box object and fills a KDChartCustomBox o...
KDChartCustomBox()
Constructor.
static void createCustomBoxNode(TQDomDocument &document, TQDomNode &parent, const TQString &elementName, const KDChartCustomBox *custombox)
Creates a DOM element node that represents a custom box for use in a DOM document.
virtual ~KDChartCustomBox()
Destructor.
static PositionFlag stringToPositionFlag(const TQString &string)
Converts the specified string to a content position enum value.
PositionFlag
The general position flag to specify a point of an area, for example this could be the anchor point w...
static TQString positionFlagToString(PositionFlag type)
Converts the specified content position enum to a string representation.
The main class of KDFrame.
Definition KDFrame.h:88
virtual void paint(TQPainter *painter, KDFramePaintSteps steps=PaintAll, TQRect innerRect=TQRect(0, 0, 0, 0)) const
Paint methode actually drawing the frame.
Definition KDFrame.cpp:156