kchart

KDChartPainter.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 <KDChartParams.h>
30#if defined ( SUN7 ) || defined (_SGIAPI) || defined ( TQ_WS_WIN)
31 #include <math.h>
32#else
33 #include <cmath>
34 #include <stdlib.h>
35#endif
36
37#include <KDDrawText.h>
38#include <KDChartPainter.h>
39#include <KDChartEnums.h>
40#include <KDChartParams.h>
41#include <KDChartCustomBox.h>
42#include <KDChartTableBase.h>
43#include <KDChartDataRegion.h>
44#include <KDChartUnknownTypeException.h>
45#include <KDChartNotEnoughSpaceException.h>
46#include <KDChartBarPainter.h>
47#include <KDChartAreaPainter.h>
48#include <KDChartLinesPainter.h>
49#include <KDChartPiePainter.h>
50#include <KDChartPolarPainter.h>
51#include <KDChartRingPainter.h>
52#include <KDChartHiLoPainter.h>
53#include <KDChartBWPainter.h>
54#include <KDChartTextPiece.h>
55
56#include <KDChart.h> // for static method KDChart::painterToDrawRect()
57
58#include <tqpainter.h>
59#include <tqpaintdevice.h>
60#include <tqpaintdevicemetrics.h>
61
62#define DEGTORAD(d) (d)*M_PI/180
63
64
97_outermostRect( TQRect(TQPoint(0,0), TQSize(0,0))),
98_legendTitle( 0 ),
99_params( params ),
100_legendNewLinesStartAtLeft( true ),
101_legendTitleHeight( 0 ),
102_legendTitleWidth( 0 ),
103_legendTitleMetricsHeight( 0 )
104{
105 // This constructor intentionally left blank so far; we cannot setup the
106 // geometry yet since we do not know the size of the painter.
107}
108
114{
115 delete _legendTitle;
116}
117
118bool KDChartPainter::calculateAllAxesLabelTextsAndCalcValues(
119 TQPainter*,
121 double,
122 double,
123 double& )
124{
125 // This function intentionally returning false; it is implemented
126 // by the KDChartAxesPainter class only.
127 return false;
128}
129
146{
147 KDChartParams::ChartType cType = make2nd
148 ? params->additionalChartType()
149 : params->chartType();
150 switch ( cType )
151 {
152 case KDChartParams::Bar:
153 return new KDChartBarPainter( params );
154 case KDChartParams::Line:
155 return new KDChartLinesPainter( params );
156 case KDChartParams::Area:
157 return new KDChartAreaPainter( params );
158 case KDChartParams::Pie:
159 return new KDChartPiePainter( params );
160 case KDChartParams::Ring:
161 return new KDChartRingPainter( params );
162 case KDChartParams::HiLo:
163 return new KDChartHiLoPainter( params );
164 case KDChartParams::BoxWhisker:
165 return new KDChartBWPainter( params );
166 case KDChartParams::Polar:
167 return new KDChartPolarPainter( params );
168 case KDChartParams::NoType:
169 default:
170 return 0;
171 }
172}
173
174
191void KDChartPainter::registerPainter( const TQString& /*painterName*/,
192 KDChartPainter* /*painter*/ )
193{
194 // PENDING(kalle) Implement this
195 tqDebug( "Sorry, not implemented: KDChartPainter::registerPainter()" );
196}
197
198
208void KDChartPainter::unregisterPainter( const TQString& /*painterName*/ )
209{
210 // PENDING(kalle) Implement this
211 tqDebug( "Sorry, not implemented: KDChartPainter::unregisterPainter()" );
212}
213
214
227void KDChartPainter::paint( TQPainter* painter,
229 bool paintFirst,
230 bool paintLast,
231 KDChartDataRegionList* regions,
232 const TQRect* rect,
233 bool mustCalculateGeometry )
234{
235
236
237 if( paintFirst && regions )
238 regions->clear();
239
240 // Protect against non-existing data
241 if( data->usedCols() == 0 && data->usedRows() == 0 )
242 return ;
243
244 TQRect drawRect;
245 //Pending Michel: at this point we have to setupGeometry
246 if( mustCalculateGeometry || _outermostRect.isNull() ){
247 if( rect )
248 drawRect = *rect;
249 else if( !KDChart::painterToDrawRect( painter, drawRect ) ){
250 tqDebug("ERROR: KDChartPainter::paint() could not calculate the drawing area.");
251 return;
252 }
253 setupGeometry( painter, data, drawRect );
254 }
255 else
256 drawRect = _outermostRect;
257
258 //tqDebug("A2: _legendRect:\n%i,%i\n%i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
259
260
261 // Note: In addition to the below paintArea calls there might be several
262 // other paintArea calls regarding to the BASE areas (AreaAxisBASE,
263 // AreaHdFtBASE, AreaCustomBoxesBASE).
264 // These additional calls result in smaller areas being drawn inside
265 // on the larger ones specifies here.
266 if ( paintFirst ) {
267 paintArea( painter, KDChartEnums::AreaOutermost );
268 paintArea( painter, KDChartEnums::AreaInnermost );
269
270 paintArea( painter, KDChartEnums::AreaDataAxesLegendHeadersFooters );
271
272 paintArea( painter, KDChartEnums::AreaHeaders );
273 paintArea( painter, KDChartEnums::AreaFooters );
274 // header areas are drawn in the following order:
275 // 1st center: main header, left main header, right main header
276 // 2nd above: header #0, left header #0, right header #0
277 // 3rd below: header #2, left header #2, right header #2
278 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader );
279 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeaderL );
280 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeaderR );
281 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0 );
282 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0L );
283 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader0R );
284 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2 );
285 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2L );
286 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosHeader2R );
287 // footer areas are drawn in the same order as the header areas:
288 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter );
289 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooterL );
290 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooterR );
291 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0 );
292 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0L );
293 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter0R );
294 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2 );
295 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2L );
296 paintArea( painter, KDChartEnums::AreaHdFtBASE + KDChartParams::HdFtPosFooter2R );
297
298 paintHeaderFooter( painter, data );
299
300 paintArea( painter, KDChartEnums::AreaDataAxesLegend );
301 paintArea( painter, KDChartEnums::AreaDataAxes );
302 paintArea( painter, KDChartEnums::AreaAxes );
303 for( int axis = KDChartAxisParams::AxisPosSTART;
304 KDChartAxisParams::AxisPosEND >= axis; ++axis )
305 paintArea( painter, KDChartEnums::AreaAxisBASE + axis );
306 paintArea( painter, KDChartEnums::AreaData );
307 paintAxes( painter, data );
308 }
309
310 painter->save();
311 paintData( painter, data, !paintFirst, regions );
312 painter->restore();
313
314 if ( paintLast ) {
315 // paint the frame lines of all little data region areas
316 // on top of all data representations
317 paintDataRegionAreas( painter, regions );
318 if( KDChartParams::Bar != params()->chartType() ||
319 KDChartParams::BarMultiRows != params()->barChartSubType() )
320 paintDataValues( painter, data, regions );
321 if (params()->legendPosition()!=KDChartParams::NoLegend)
322 paintArea( painter, KDChartEnums::AreaLegend );
323 paintLegend( painter, data );
324 paintCustomBoxes( painter, regions );
325 }
326}
327
328
332void KDChartPainter::paintArea( TQPainter* painter,
333 uint area,
334 KDChartDataRegionList* regions,
335 uint dataRow,
336 uint dataCol,
337 uint data3rd )
338{
339 if( KDChartEnums::AreaCustomBoxesBASE != (KDChartEnums::AreaBASEMask & area) ){
340 bool bFound;
342 params()->frameSettings( area, bFound );
343 if( bFound ) {
344 bool allCustomBoxes;
345 TQRect rect( calculateAreaRect( allCustomBoxes,
346 area,
347 dataRow, dataCol, data3rd, regions ) );
348
349 if( !allCustomBoxes )
350 paintAreaWithGap( painter, rect, *settings );
351 }
352 }
353}
354
355
356void KDChartPainter::paintDataRegionAreas( TQPainter* painter,
357 KDChartDataRegionList* regions )
358{
359 if( regions ){
360 int iterIdx;
361 bool bFound;
363 params()->frameSettings( KDChartEnums::AreaChartDataRegion, bFound, &iterIdx );
364 while( bFound ) {
365 bool bDummy;
366 TQRect rect( calculateAreaRect( bDummy,
367 KDChartEnums::AreaChartDataRegion,
368 settings->dataRow(),
369 settings->dataCol(),
370 settings->data3rd(),
371 regions ) );
372 // NOTE: we can *not* draw any background behind the
373 // data representations.
374 // reason: for being able to do that we would have to
375 // know the respective regions _before_ the
376 // data representations are drawn; since that
377 // is impossible, we just draw the borders only
378 // ( == the corners and the edges ) and ignore the background
379 //
380 // (actually: Since the respective interface function does not allow
381 // specifying a background there is nothing to be ignored anyway.)
382 settings->frame().paint( painter,
383 KDFrame::PaintBorder,
384 trueFrameRect( rect, settings ) );
385 settings = params()->nextFrameSettings( bFound, &iterIdx );
386 }
387 }
388}
389
390
391TQRect KDChartPainter::trueFrameRect( const TQRect& orgRect,
392 const KDChartParams::KDChartFrameSettings* settings ) const
393{
394 TQRect rect( orgRect );
395 if( settings ){
396 rect.moveBy( -settings->innerGapX(), -settings->innerGapY() );
397 rect.setWidth( rect.width() + 2*settings->innerGapX() );
398 rect.setHeight( rect.height() + 2*settings->innerGapY() );
399 }
400 return rect;
401}
402
403
410void KDChartPainter::paintAreaWithGap( TQPainter* painter,
411 TQRect rect,
413{
414 if( painter && rect.isValid() )
415 settings.frame().paint( painter,
416 KDFrame::PaintAll,
417 trueFrameRect( rect, &settings ) );
418}
419
420
424void KDChartPainter::paintDataValues( TQPainter* painter,
426 KDChartDataRegionList* regions )
427{
428 KDChartDataRegion* region;
429 if ( painter
430 && data
431 && regions
432 && regions->count()
433 && params()
434 && ( params()->printDataValues( 0 )
435 || params()->printDataValues( 1 ) ) ) {
436
437 // out of loop status saving
438 painter->save();
439
440 TQFont font0( params()->dataValuesFont( 0 ) );
441
442 if( params()->dataValuesUseFontRelSize( 0 ) ) {
443 float size = TQMIN(_areaWidthP1000, _areaHeightP1000) * abs(params()->dataValuesFontRelSize( 0 ));
444 if ( 9.0 > size )
445 size = 9.0;
446 font0.setPixelSize( static_cast < int > ( size ) );
447 }
448 painter->setFont( font0 );
449 TQFontMetrics fm0( painter->fontMetrics() );
450 double fm0HeightP100( fm0.height() / 100.0 );
451 TQFont font1( params()->dataValuesFont( 1 ) );
452
453 if( params()->dataValuesUseFontRelSize( 1 ) ) {
454 float size = TQMIN(_areaWidthP1000, _areaHeightP1000) * abs(params()->dataValuesFontRelSize( 1 ));
455 if ( 9.0 > size )
456 size = 9.0;
457 font1.setPixelSize( static_cast < int > ( size ) );
458 } else
459 font1.setPixelSize( font0.pixelSize());
460 painter->setFont( font1 );
461 TQFontMetrics fm1( painter->fontMetrics() );
462 double fm1HeightP100( fm1.height() / 100.0 );
463
464 bool lastDigitIrrelevant0 = true;
465 bool lastDigitIrrelevant1 = true;
466 // get and format the texts
467 for ( region=regions->first();
468 region != 0;
469 region = regions->next() ) {
470 TQVariant vValY;
471 if( data->cellCoord( region->row, region->col, vValY, 1 ) ){
472 if( TQVariant::String == vValY.type() ){
473 const TQString sVal( vValY.toString() );
474 if( !sVal.isEmpty() )
475 region->text = sVal;
476 }else if( TQVariant::Double == vValY.type() ){
477 double value( vValY.toDouble() );
478 region->negative = 0.0 > value;
479 double divi( pow( 10.0, params()->dataValuesDivPow10( region->chart ) ) );
480 if ( 1.0 != divi )
481 value /= divi;
482 int digits( params()->dataValuesDigitsBehindComma( region->chart ) );
483 bool autoDigits( KDCHART_DATA_VALUE_AUTO_DIGITS == digits );
484 if( autoDigits ) {
485 if( 10 < digits )
486 digits = 10;
487 } else
488 ( region->chart
489 ? lastDigitIrrelevant1
490 : lastDigitIrrelevant0 ) = false;
491 if( value == KDCHART_NEG_INFINITE )
492 region->text = "-LEMNISKATE";
493 else if( value == KDCHART_POS_INFINITE )
494 region->text = "+LEMNISKATE";
495 else {
496 region->text.setNum( value, 'f', digits );
497 if ( autoDigits && region->text.contains( '.' ) ) {
498 int len = region->text.length();
499 while ( 3 < len
500 && '0' == region->text[ len-1 ]
501 && '.' != region->text[ len-2 ] ) {
502 --len;
503 region->text.truncate( len );
504 }
505 if( '0' != region->text[ len-1 ] )
506 ( region->chart
507 ? lastDigitIrrelevant1
508 : lastDigitIrrelevant0 ) = false;
509 }
510 }
511 }
512 }
513 }
514
515 if ( lastDigitIrrelevant0 || lastDigitIrrelevant1 )
516 for ( region=regions->first();
517 region != 0;
518 region = regions->next() )
519 if ( ( ( lastDigitIrrelevant0 && !region->chart )
520 || ( lastDigitIrrelevant1 && region->chart ) )
521 && region->text.contains( '.' )
522 && ( 2 < region->text.length() ) )
523 region->text.truncate ( region->text.length() - 2 );
524
525
526 // draw the Data Value Texts and calculate the text regions
527 painter->setPen( TQt::black );
528
529 bool allowOverlapping = params()->allowOverlappingDataValueTexts();
530 bool drawThisOne;
531 TQRegion lastRegionDone;
532
533 TQFontMetrics actFM( painter->fontMetrics() );
534
535 TQFont* oldFont = 0;
536 int oldRotation = 0;
537 uint oldChart = UINT_MAX;
538 uint oldDatacolorNo = UINT_MAX;
539 for ( region=regions->first();
540 region != 0;
541 region = regions->next() ) {
542
543 // in loop status saving
544 painter->save();
545
546 if ( region->text.length() ) {
547
548 TQVariant vValY;
549 bool zero =
550 data->cellCoord( region->row, region->col, vValY, 1 ) &&
551 TQVariant::Double == vValY.type() &&
552 ( 0.0 == vValY.toDouble() || 0 == vValY.toDouble() );
553 uint align( params()->dataValuesAnchorAlign( region->chart,
554 region->negative ) );
555 KDChartParams::ChartType cType = region->chart
556 ? params()->additionalChartType()
557 : params()->chartType();
558
559
560 // these use the bounding rect of region-region:
561 bool bIsAreaChart = KDChartParams::Area == cType;
562 bool rectangular = ( KDChartParams::Bar == cType
563 || KDChartParams::Line == cType
564 || bIsAreaChart
565 || KDChartParams::HiLo == cType
566 || KDChartParams::BoxWhisker == cType );
567
568 // these use the nine anchor points stored in region->points
569 bool circular = ( KDChartParams::Pie == cType
570 || KDChartParams::Ring == cType
571 || KDChartParams::Polar == cType );
572
573
575 params()->dataValuesAnchorPosition( region->chart, region->negative ) );
576
577 TQPoint anchor(
578 rectangular
579 ? KDChartEnums::positionFlagToPoint( region->rect(), anchorPos )
580 : KDChartEnums::positionFlagToPoint( region->points, anchorPos ) );
581
582 double & fmHeightP100 = region->chart ? fm1HeightP100 : fm0HeightP100;
583
584 int angle = region->startAngle;
585 switch ( anchorPos ) {
586 case KDChartEnums::PosTopLeft:
587 case KDChartEnums::PosCenterLeft:
588 case KDChartEnums::PosBottomLeft:
589 angle += region->angleLen;
590 break;
591 case KDChartEnums::PosTopCenter:
592 case KDChartEnums::PosCenter:
593 case KDChartEnums::PosBottomCenter:
594 angle += region->angleLen / 2;
595 break;
596 /*
597 case KDChartEnums::PosTopRight:
598 case KDChartEnums::PosCenterRight:
599 case KDChartEnums::PosBottomRight:
600 angle += 0;
601 break;
602 */
603 default:
604 break;
605 }
606 double anchorDX( params()->dataValuesAnchorDeltaX( region->chart, region->negative )
607 * fmHeightP100 );
608 double anchorDY( params()->dataValuesAnchorDeltaY( region->chart, region->negative )
609 * fmHeightP100 );
610 if ( circular ) {
611 if ( 0.0 != anchorDY ) {
612 double normAngle = angle / 16;
613 double normAngleRad = DEGTORAD( normAngle );
614 double sinAngle = sin( normAngleRad );
615 TQPoint pM = TQPoint(region->points[ KDChartEnums::PosCenter ]);
616 double dX( pM.x() - anchor.x() );
617 double dY( pM.y() - anchor.y() );
618 double radialLen( sinAngle ? dY / sinAngle : dY );
619 double radialFactor( ( radialLen == 0.0 ) ? 0.0 : ( ( radialLen - anchorDY ) / radialLen ) );
620 anchor.setX( static_cast < int > ( pM.x() - dX * radialFactor ) );
621 anchor.setY( static_cast < int > ( pM.y() - dY * radialFactor ) );
622 }
623 } else {
624 anchor.setX( anchor.x() + static_cast < int > ( anchorDX ) );
625 anchor.setY( anchor.y() + static_cast < int > ( anchorDY ) );
626 }
627
628
629 if(anchor.x() < -250){
630 anchor.setX(-250);
631 //tqDebug("!! bad negative x position in KDChartPainter::paintDataValues() !!");
632 }
633 if(anchor.y() < -2500){
634 anchor.setY(-2500);
635 //tqDebug("!! bad negative y position in KDChartPainter::paintDataValues() !!");
636 }
637
638 int rotation( params()->dataValuesRotation( region->chart,
639 region->negative ) );
640 bool incRotationBy90 = false;
641 if( region->text == "-LEMNISKATE" ||
642 region->text == "+LEMNISKATE" ){
643 if( params()->dataValuesShowInfinite( region->chart ) ){
644 //bool bIsLineChart = KDChartParams::Line == cType;
645 if( region->text == "-LEMNISKATE" )
646 align = TQt::AlignRight + TQt::AlignVCenter;
647 else
648 align = TQt::AlignLeft + TQt::AlignVCenter;
649 if( !rotation )
650 rotation = 90;
651 else
652 incRotationBy90 = true;
653 region->text = " 8 ";
654 }else{
655 region->text = "";
656 }
657 }
658
659 if ( rotation ) {
660 anchor = painter->worldMatrix().map( anchor );
661
662 // Temporary solution for fixing the data labels size
663 // bug when in TQPrinter::HighResolution mode:
664 // There seem to be no backdraws by acting like this,
665 // but further investigation is required to detect the
666 // real error in the previous code/
667 if ( KDCHART_SAGGITAL_ROTATION == rotation
668 || KDCHART_TANGENTIAL_ROTATION == rotation ) {
669 rotation = ( KDCHART_TANGENTIAL_ROTATION == rotation
670 ? -1440
671 : 0 )
672 + angle;
673 rotation /= 16;
674 if( incRotationBy90 )
675 rotation += 90;
676 if ( 360 <= rotation )
677 rotation -= 360;
678 else if ( 0 > rotation )
679 rotation += 360;
680 rotation = 360 - rotation;
681 }else if( incRotationBy90 )
682 rotation = (rotation + 90) % 360;
683
684
685 if( rotation != oldRotation ) {
686 painter->rotate( rotation - oldRotation );
687 // Comment this out - zooming and scrolling
688 // oldRotation = rotation;
689 }
690
691 TQFont* actFont = region->chart ? &font1 : &font0;
692 if( oldFont != actFont ) {
693 painter->setFont( *actFont );
694 actFM = TQFontMetrics( painter->fontMetrics() );
695 // Comment this out - zooming and scrolling
696 //oldFont = actFont;
697 }
698
699 KDDrawTextRegionAndTrueRect infosKDD =
700 KDDrawText::measureRotatedText( painter,
701 rotation,
702 anchor,
703 region->text,
704 0,
705 align,
706 &actFM,
707 true,
708 true,
709 5 );
710 //anchor = painter->worldMatrix().map( anchor );
711
712 if( allowOverlapping ) {
713 drawThisOne = true;
714 }else {
715 TQRegion sectReg( infosKDD.region.intersect( lastRegionDone ) );
716 drawThisOne = sectReg.isEmpty();
717 }
718 if( drawThisOne ) {
719 lastRegionDone = lastRegionDone.unite( infosKDD.region );
720 region->pTextRegion = new TQRegion( infosKDD.region );
721
722 if( params()->dataValuesAutoColor( region->chart ) ) {
723 if( bIsAreaChart ){
724 TQColor color( params()->dataColor( region->row ) );
725 /*
726 if( ( (0.0 > anchorDY) && region->negative )
727 || ( (0.0 < anchorDY) && !region->negative ) )
728 painter->setPen(
729 TQColor( static_cast < int > ( 255- color.red() ),
730 static_cast < int > ( 255- color.green() ),
731 static_cast < int > ( 255- color.blue() ) ) );
732 else
733 */
734 painter->setPen( color.dark() );
735 }else{
736 if( zero ) {
737 if( oldDatacolorNo != UINT_MAX ) {
738 painter->setPen( TQt::black );
739 oldDatacolorNo = UINT_MAX;
740 }
741 }
742 else {
743 uint datacolorNo = ( KDChartParams::Pie == cType
744 || KDChartParams::Ring == cType )
745 ? region->col
746 : region->row;
747 if( oldDatacolorNo != datacolorNo ) {
748 oldDatacolorNo = datacolorNo;
749 TQColor color( params()->dataColor( datacolorNo ) );
750 painter->setPen( TQColor(
751 static_cast < int > (255-color.red() ),
752 static_cast < int > (255-color.green()),
753 static_cast < int > (255-color.blue() )));
754 }
755 }
756 }
757 }
758 else if( oldChart != region->chart ) {
759 oldChart = region->chart;
760 painter->setPen( params()->dataValuesColor( region->chart ) );
761 }
762
763 if( params()->optimizeOutputForScreen() ){
764 painter->rotate( -oldRotation );
765 oldRotation = 0;
766 if ( anchor.y() < 0 )
767 anchor.setY( -anchor.y() );
768
769 KDDrawText::drawRotatedText( painter,
770 rotation,
771 anchor,
772 region->text,
773 region->chart ? &font1 : &font0,
774 align,
775 false, // bool showAnchor
776 0, // const TQFontMetrics* fontMet
777 false, // bool noFirstrotate
778 false, // bool noBackrotate
779 0, // KDDrawTextRegionAndTrueRect* infos
780 true ); // bool optimizeOutputForScreen
781 }else{
782 painter->setPen( params()->dataValuesColor( region->chart ) );
783 //Pending Michel Painting data value labels rotated.
784 painter->drawText( infosKDD.x , infosKDD.y ,
785 infosKDD.width, infosKDD.height,
786 TQt::AlignHCenter | TQt::AlignVCenter | TQt::SingleLine,
787 region->text );
788
789 }
790
791
792 } // if not intersect
793
794 } else {
795
796 // no rotation:
797 painter->rotate( -oldRotation );
798 oldRotation = 0;
799 TQFontMetrics & fm = region->chart ? fm1 : fm0;
800 int boundingRectWidth = fm.boundingRect( region->text ).width();
801 int leftBearing = fm.leftBearing( region->text[ 0 ] );
802 const TQChar c = region->text.at( region->text.length() - 1 );
803 int rightBearing = fm.rightBearing( c );
804 int w = boundingRectWidth + leftBearing + rightBearing + 1;
805 int h = fm.height(); // ascent + descent + 1
806 int dx = 0;
807 int dy = 0;
808 switch( align & ( TQt::AlignLeft | TQt::AlignRight | TQt::AlignHCenter ) ) {
809 case TQt::AlignRight:
810 dx = -w+1;
811 break;
812 case TQt::AlignHCenter:
813 // Center on the middle of the bounding rect, not
814 // the painted area, because numbers appear centered then
815 dx = -( ( boundingRectWidth / 2 ) + leftBearing );
816 break;
817 }
818 switch( align & ( TQt::AlignTop | TQt::AlignBottom | TQt::AlignVCenter ) ) {
819 case TQt::AlignBottom:
820 dy = -h+1;
821 break;
822 case TQt::AlignVCenter:
823 dy = -h / 2;
824 break;
825 }
826
827 TQRegion thisRegion(
828 TQRect( anchor.x() + dx, anchor.y() + dy, w, h ) );
829 if( allowOverlapping )
830 drawThisOne = true;
831 else {
832 TQRegion sectReg( thisRegion.intersect( lastRegionDone ) );
833 drawThisOne = sectReg.isEmpty();
834 }
835 if( drawThisOne ) {
836 lastRegionDone = lastRegionDone.unite( thisRegion );
837 region->pTextRegion = new TQRegion( thisRegion );
838#ifdef DEBUG_TEXT_PAINTING
839 // for testing:
840 TQRect rect( region->pTextRegion->boundingRect() );
841 painter->drawRect( rect );
842 painter->setPen( TQt::red );
843 rect.setLeft( rect.left() + leftBearing );
844 rect.setTop( rect.top() + ( fm.height()-fm.boundingRect( region->text ).height() ) /2 );
845 rect.setWidth( fm.boundingRect( region->text ).width() );
846 rect.setHeight( fm.boundingRect( region->text ).height() );
847 painter->drawRect( rect );
848 painter->setPen( TQt::black );
849#endif
850 /*
851
852NOTE: The following will be REMOVED again once
853the layout policy feature is implemented !!!
854
855*/
856 TQRect textRect( region->pTextRegion->boundingRect() );
857 if( bIsAreaChart ){
858 TQBrush brush( params()->dataValuesBackground( region->chart ) );
859 painter->setBrush( brush );
860 painter->setPen( TQt::NoPen );
861 TQRect rect( textRect );
862 rect.moveBy( -2, 0 );
863 rect.setWidth( rect.width() + 4 );
864 painter->drawRect( rect );
865 }
866 painter->setFont( region->chart ? font1 : font0 );
867 if( params()->dataValuesAutoColor( region->chart ) ) {
868 if( bIsAreaChart ){
869 TQColor color( params()->dataColor( region->row ) );
870 /*
871 if( ( (0.0 > anchorDY) && region->negative )
872 || ( (0.0 < anchorDY) && !region->negative ) )
873 painter->setPen(
874 TQColor( static_cast < int > ( 255- color.red() ),
875 static_cast < int > ( 255- color.green() ),
876 static_cast < int > ( 255- color.blue() ) ) );
877 else
878 */
879 painter->setPen( color.dark() );
880 }else{
881 if( zero )
882 painter->setPen( TQt::black );
883 else {
884 TQColor color( params()->dataColor(
885 ( KDChartParams::Pie == params()->chartType()
886 || KDChartParams::Ring == params()->chartType() )
887 ? region->col
888 : region->row ) );
889 painter->setPen( TQColor( static_cast < int > ( 255- color.red() ),
890 static_cast < int > ( 255- color.green() ),
891 static_cast < int > ( 255- color.blue() ) ) );
892 }
893 }
894 }else{
895 painter->setPen( params()->dataValuesColor( region->chart ) );
896 }
897
898 painter->drawText( textRect.left(), textRect.top(),
899 textRect.width()+1, textRect.height()+1,
900 TQt::AlignLeft | TQt::AlignTop, region->text );
901
902 }
903
904
905 }
906 }
907 //
908 painter->restore();
909
910 }
911 painter->restore();
912 }
913
914}
915
916
920void KDChartPainter::paintCustomBoxes( TQPainter* painter,
921 KDChartDataRegionList* regions )
922{
923 // paint all of the custom boxes AND their surrounding frames+background (if any)
924 bool bGlobalFound;
925 const KDChartParams::KDChartFrameSettings* globalFrameSettings
926 = params()->frameSettings( KDChartEnums::AreasCustomBoxes, bGlobalFound );
927
928 uint idx;
929 for( idx = 0; idx <= params()->maxCustomBoxIdx(); ++idx ) {
930 const KDChartCustomBox * box = params()->customBox( idx );
931 if( box ) {
932 // paint border and background
933 paintArea( painter,
934 KDChartEnums::AreaCustomBoxesBASE + idx,
935 regions,
936 box->dataRow(),
937 box->dataCol(),
938 box->data3rd() );
939 // retrieve frame information
940 bool bIndividualFound;
941 const KDChartParams::KDChartFrameSettings * individualFrameSettings
942 = params()->frameSettings( KDChartEnums::AreaCustomBoxesBASE + idx,
943 bIndividualFound );
945 = bIndividualFound ? individualFrameSettings
946 : bGlobalFound ? globalFrameSettings : 0;
947 // paint content
948 const TQPoint anchor( calculateAnchor( *box, regions ) );
949 box->paint( painter,
950 anchor,
951 _areaWidthP1000,
952 _areaHeightP1000,
953 settings ? settings->framePtr() : 0,
954 trueFrameRect( box->trueRect( anchor, _areaWidthP1000, _areaHeightP1000 ),
955 settings ) );
956 }
957 }
958}
959
960
965 KDChartDataRegionList* regions ) const
966{
967 TQPoint pt(0,0);
968
969 // Recursion handling:
970 //
971 // * calculateAnchor() normally calls calculateAreaRect()
972 //
973 // * calculateAreaRect() will in turn calls calculateAnchor() in case of
974 // box.anchorArea() being based on KDChartEnums::AreaCustomBoxesBASE
975 //
976 // This is Ok as long as the recursive call of calculateAnchor() is NOT
977 // intend examination the same box as a previous call.
978 //
979 // Rule:
980 //
981 // A box may be aligned to another box (and the 2nd box may again be
982 // aligned to a 3rd box and so on) but NO CIRCULAR alignment is allowed.
983 //
984 if( !box.anchorBeingCalculated() ) {
985
987
988 bool allCustomBoxes;
989 TQRect rect( calculateAreaRect( allCustomBoxes,
990 box.anchorArea(),
991 box.dataRow(),
992 box.dataCol(),
993 box.data3rd(),
994 regions ) );
995 if( allCustomBoxes ) {
996 //
997 // Dear user of this library.
998 //
999 // You faced the above error during program runtime?
1000 //
1001 // The reason for this is that you may NOT use AreasCustomBoxes
1002 // as a value for the KDChartCustomBox anchor area.
1003 //
1004 // This is due to the fact that an anchor area allways must specify one AREA
1005 // or some contiguous areas that form an area when combined.
1006 // The flag AreasCustomBoxes however specifies a list of custom boxes
1007 // that normally do not form a contiguos ares, so they cannot be used as anchor area.
1008 //
1009 // In order to specify a SINGLE custom box please use AreaCustomBoxBASE+boxId.
1010 //
1011 }
1013
1015 }
1016
1017 return pt;
1018}
1019
1020
1025TQRect KDChartPainter::calculateAreaRect( bool & allCustomBoxes,
1026 uint area,
1027 uint dataRow,
1028 uint dataCol,
1029 uint /*data3rd*/,
1030 KDChartDataRegionList* regions ) const
1031{
1032 TQRect rect(0,0, 0,0);
1033 allCustomBoxes = false;
1034 uint pos;
1035 switch( area ) {
1036 case KDChartEnums::AreaData:
1037 rect = _dataRect;
1038 break;
1039 case KDChartEnums::AreaAxes:
1040 break;
1041 case KDChartEnums::AreaLegend:
1042 rect = _legendRect;
1043 break;
1044 case KDChartEnums::AreaDataAxes:
1045 rect = _axesRect;
1046 break;
1047 case KDChartEnums::AreaDataAxesLegend:
1048 rect = _axesRect;
1049 if( _legendRect.isValid() ) {
1050 if( rect.isValid() )
1051 rect = rect.unite( _legendRect );
1052 else
1053 rect = _legendRect;
1054 }
1055 break;
1056 case KDChartEnums::AreaHeaders: {
1057 bool bStart = true;
1058 for( pos = KDChartParams::HdFtPosHeadersSTART;
1059 KDChartParams::HdFtPosHeadersEND >= pos;
1060 ++pos ) {
1061 const TQRect& r = params()->headerFooterRect( pos );
1062 if( r.isValid() ) {
1063 if( bStart )
1064 rect = r;
1065 else
1066 rect = rect.unite( r );
1067 bStart = false;
1068 }
1069 }
1070 }
1071 break;
1072 case KDChartEnums::AreaFooters: {
1073 bool bStart = true;
1074 for( pos = KDChartParams::HdFtPosFootersSTART;
1075 KDChartParams::HdFtPosFootersEND >= pos;
1076 ++pos ) {
1077 const TQRect& r = params()->headerFooterRect( pos );
1078 if( r.isValid() ) {
1079 if( bStart )
1080 rect = r;
1081 else
1082 rect = rect.unite( r );
1083 bStart = false;
1084 }
1085 }
1086 }
1087 break;
1088 case KDChartEnums::AreaDataAxesLegendHeadersFooters: {
1089 rect = _axesRect;
1090 bool bStart = !rect.isValid();
1091 if( _legendRect.isValid() ) {
1092 if( bStart )
1093 rect = _legendRect;
1094 else
1095 rect = rect.unite( _legendRect );
1096 bStart = false;
1097 }
1098 for( pos = KDChartParams::HdFtPosSTART;
1099 KDChartParams::HdFtPosEND >= pos;
1100 ++pos ) {
1101 const TQRect& r = params()->headerFooterRect( pos );
1102 if( r.isValid() ) {
1103 if( bStart )
1104 rect = r;
1105 else
1106 rect = rect.unite( r );
1107 bStart = false;
1108 }
1109 }
1110 }
1111 break;
1112 case KDChartEnums::AreaOutermost:
1113 rect = _outermostRect;
1114 break;
1115 case KDChartEnums::AreaInnermost:
1116 rect = _innermostRect;
1117 break;
1118 case KDChartEnums::AreasCustomBoxes:
1119 allCustomBoxes = true;
1120 break;
1121 case KDChartEnums::AreaChartDataRegion:
1122 if( regions ) {
1123 KDChartDataRegion* current;
1124 for ( current = regions->first();
1125 current != 0;
1126 current = regions->next() ) {
1127 if ( current->row == dataRow
1128 && current->col == dataCol
1129 //
1130 // the line below prepared for true 3-dimensional data charts
1131 //
1132 /* && current->region.thirdDimension == data3rd */ ) {
1133 rect = current->rect();
1134 break;
1135 }
1136 }
1137 }
1138 break;
1139 case KDChartEnums::AreaUNKNOWN:
1140 break;
1141
1142 default: {
1143 uint maskBASE = KDChartEnums::AreaBASEMask & area;
1144 pos = area - maskBASE;
1145 if ( KDChartEnums::AreaAxisBASE == maskBASE ) {
1146 rect = params()->axisParams( pos ).axisTrueAreaRect();
1147 } else if ( KDChartEnums::AreaHdFtBASE == maskBASE ) {
1148 rect = params()->headerFooterRect( pos );
1149 } else if ( KDChartEnums::AreaCustomBoxesBASE == maskBASE ) {
1150 const KDChartCustomBox * box = params()->customBox( pos );
1151 if( box ) {
1152 rect = box->trueRect( calculateAnchor( *box, regions ),
1153 _areaWidthP1000,
1154 _areaHeightP1000 );
1155 }
1156 }
1157 }
1158 }
1159 return rect;
1160}
1161
1162
1163TQPoint KDChartPainter::pointOnCircle( const TQRect& rect, double angle )
1164{
1165 // There are two ways of computing this: The simple, but slow one
1166 // is to use TQPointArray.makeArc() and take the first point. The
1167 // more advanced, but faster one is to do the trigonometric
1168 // computionations ourselves. Since the comments in
1169 // TQPointArray::makeArc() very often say that the code there is
1170 // "poor", we'd better do it outselves...
1171
1172 double normAngle = angle / 16.0;
1173 double normAngleRad = DEGTORAD( normAngle );
1174 double cosAngle = cos( normAngleRad );
1175 double sinAngle = -sin( normAngleRad );
1176 double posX = floor( cosAngle * ( double ) rect.width() / 2.0 + 0.5 );
1177 double posY = floor( sinAngle * ( double ) rect.height() / 2.0 + 0.5 );
1178 return TQPoint( static_cast<int>(posX) + rect.center().x(),
1179 static_cast<int>(posY) + rect.center().y() );
1180
1181}
1182
1183void KDChartPainter::makeArc( TQPointArray& points,
1184 const TQRect& rect,
1185 double startAngle, double angles )
1186{
1187 double endAngle = startAngle + angles;
1188 int rCX = rect.center().x();
1189 int rCY = rect.center().y();
1190 double rWid2 = ( double ) rect.width() / 2.0;
1191 double rHig2 = ( double ) rect.height() / 2.0;
1192 int numSteps = static_cast<int>(angles);
1193 if( floor( angles ) < angles )
1194 ++numSteps;
1195 points.resize( numSteps );
1196 double angle = startAngle;
1197 if( angle < 0.0 )
1198 angle += 5760.0;
1199 else if( angle >= 5760.0 )
1200 angle -= 5760.0;
1201 for(int i = 0; i < numSteps; ++i){
1202 double normAngle = angle / 16.0;
1203 double normAngleRad = DEGTORAD( normAngle );
1204 double cosAngle = cos( normAngleRad );
1205 double sinAngle = -sin( normAngleRad );
1206 double posX = floor( cosAngle * rWid2 + 0.5 );
1207 double posY = floor( sinAngle * rHig2 + 0.5 );
1208 points[i] = TQPoint( ( int ) posX + rCX,
1209 ( int ) posY + rCY );
1210 if( i+1 >= numSteps-1 )
1211 angle = endAngle; // the very last step width may be smaller than 1.0
1212 else
1213 angle += 1.0;
1214 if( angle >= 5760.0 )
1215 angle -= 5760.0;
1216 }
1217}
1218
1228void KDChartPainter::paintAxes( TQPainter* /*painter*/, KDChartTableDataBase* /*data*/ )
1229{
1230 // This method intentionally left blank.
1231}
1232
1233
1234int KDChartPainter::legendTitleVertGap() const
1235{
1236 return _legendTitleHeight
1237 + static_cast < int > ( _legendTitleMetricsHeight * 0.20 );
1238}
1239
1240
1241TQFont KDChartPainter::trueLegendFont() const
1242{
1243 TQFont trueFont = params()->legendFont();
1244 if ( params()->legendFontUseRelSize() ) {
1245 const double averageValueP1000 = TQMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
1246 trueFont.setPixelSize(
1247 static_cast < int > ( params()->legendFontRelSize() * averageValueP1000 ) );
1248 }
1249 return trueFont;
1250}
1251
1252
1258void KDChartPainter::calculateHorizontalLegendSize( TQPainter* painter,
1259 TQSize& size,
1260 bool& legendNewLinesStartAtLeft ) const
1261{
1262
1263 legendNewLinesStartAtLeft = false;
1264 TQRect legendRect( _legendRect );
1265 /*
1266 * Pending Michel reset the left side before calculating
1267 *the new legend position calculation
1268 *otherwise we occasionally reach the edge and get a wrong
1269 *result
1270 */
1271
1272 legendRect.setLeft( _innermostRect.left() );
1273
1274 const int em2 = 2 * _legendEMSpace;
1275 const int em4 = 4 * _legendEMSpace;
1276 const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
1277
1278 const int xposHori0 = legendRect.left() + _legendEMSpace;
1279
1280 int xpos = xposHori0;
1281
1282 int ypos = legendRect.top() + emDiv2;
1283
1284 // first paint the title, if any
1285 if( _legendTitle )
1286 xpos += _legendTitleWidth + em4;
1287
1288 int maxX = _legendTitleWidth + _legendEMSpace;
1289
1290 // save the x position: here start the item texts if in horizontal mode
1291 int xposHori1 = xpos;
1292
1293 // add the space of the box plus the space between the box and the text
1294 int x2 = xpos + em2;
1295
1296 // loop over all the datasets, each one has one row in the legend
1297 // if its data are to be used in at least one of the charts drawn
1298 // *but* only if there is a legend text for it!
1299 const int rightEdge = _innermostRect.right()-_legendEMSpace;
1300 bool bFirstLFWithTitle = _legendTitle;
1301 painter->setFont( trueLegendFont() );
1302 TQFontMetrics txtMetrics( painter->fontMetrics() );
1303 int dataset;
1304 for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
1305 /*
1306 if( KDChartParams::DataEntry == params()->chartSourceMode( dataset ) ) {
1307 */
1308 if( !_legendTexts[ dataset ].isEmpty() ){
1309 int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
1310 if( x2 + txtWidth > rightEdge ){
1311 if( xposHori1 + em2 + txtWidth > rightEdge){
1312 xposHori1 = xposHori0;
1313 legendNewLinesStartAtLeft = true;
1314 }
1315 xpos = xposHori1;
1316 x2 = xpos + em2;
1317 ypos += bFirstLFWithTitle ? legendTitleVertGap() : _legendSpacing;
1318 bFirstLFWithTitle = false;
1319 }
1320 maxX = TQMAX(maxX, x2+txtWidth+_legendEMSpace);
1321
1322 xpos += txtWidth + em4;
1323 x2 += txtWidth + em4;
1324 }
1325 }
1326 if( bFirstLFWithTitle )
1327 ypos += _legendTitleHeight;
1328 else
1329 ypos += txtMetrics.height();
1330
1331 size.setWidth( maxX - legendRect.left() );
1332 size.setHeight( ypos + emDiv2 - _legendRect.top() );
1333}
1334
1335
1336bool KDChartPainter::mustDrawVerticalLegend() const
1337{
1338 return
1339 params()->legendOrientation() == TQt::Vertical ||
1340 params()->legendPosition() == KDChartParams::LegendLeft ||
1341 params()->legendPosition() == KDChartParams::LegendRight ||
1342 params()->legendPosition() == KDChartParams::LegendTopLeft ||
1343 params()->legendPosition() == KDChartParams::LegendTopLeftLeft ||
1344 params()->legendPosition() == KDChartParams::LegendTopRight ||
1345 params()->legendPosition() == KDChartParams::LegendTopRightRight ||
1346 params()->legendPosition() == KDChartParams::LegendBottomLeft ||
1347 params()->legendPosition() == KDChartParams::LegendBottomLeftLeft ||
1348 params()->legendPosition() == KDChartParams::LegendBottomRight ||
1349 params()->legendPosition() == KDChartParams::LegendBottomRightRight;
1350}
1351
1352TQFont KDChartPainter::trueLegendTitleFont() const
1353{
1354 const double averageValueP1000 = TQMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
1355 TQFont font( params()->legendTitleFont() );
1356 if ( params()->legendTitleFontUseRelSize() ) {
1357 int nTxtHeight =
1358 static_cast < int > ( params()->legendTitleFontRelSize()
1359 * averageValueP1000 );
1360 font.setPixelSize( nTxtHeight );
1361 // tqDebug("l-t-height %i",nTxtHeight);
1362 }
1363 return font;
1364}
1365
1374void KDChartPainter::paintLegend( TQPainter* painter,
1375 KDChartTableDataBase* /*data*/ )
1376{
1377 if ( params()->legendPosition() == KDChartParams::NoLegend )
1378 return ; // do not draw legend
1379
1380 const bool bVertical = mustDrawVerticalLegend();
1381 painter->save();
1382
1383
1384 bool bFrameFound;
1385 params()->frameSettings( KDChartEnums::AreaLegend, bFrameFound );
1386
1387 // start out with a rectangle around the legend
1388 //painter->setPen( TQPen( TQt::black, 1 ) );
1389 //painter->setBrush( TQBrush::NoBrush );
1390 //Pending Michel: let us paint the frame at the end of the drawmarker
1391 //and draw text process, in case we need to resize it then
1392 /*
1393 if( !bFrameFound ) {
1394 painter->drawRect( _legendRect );
1395 }
1396 */
1397 //tqDebug("B: _legendRect:\n %i,%i\n %i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
1398 //tqDebug("B: legendArea():\n %i,%i\n %i,%i\n", _params->legendArea().left(),_params->legendArea().top(),_params->legendArea().right(),_params->legendArea().bottom() );
1399
1400 const int em2 = 2 * _legendEMSpace;
1401 const int em4 = 4 * _legendEMSpace;
1402 const int emDiv2 = static_cast < int > ( _legendEMSpace / 2.0 );
1403
1404 const int xposHori0 = _legendRect.left() + _legendEMSpace;
1405
1406 int xpos = xposHori0;
1407
1408 int ypos = _legendRect.top() + emDiv2;
1409
1410
1411
1412
1413 // first paint the title, if any
1414 if( _legendTitle ) {
1415 painter->setFont( trueLegendTitleFont() );
1416 _legendTitle->draw( painter,
1417 xpos,
1418 ypos,
1419 TQRegion( xpos,
1420 ypos ,
1421 _legendTitleWidth,
1422 _legendTitleHeight ),
1423 params()->legendTitleTextColor() );
1424 if( bVertical )
1425 ypos += legendTitleVertGap();
1426
1427 else
1428 xpos += _legendTitleWidth + em4;
1429
1430 }
1431
1432 // save the x position: here start the item texts if in horizontal mode
1433 const int xposHori1 = _legendNewLinesStartAtLeft ? xposHori0 : xpos;
1434
1435 // add the space of the box plus the space between the box and the text
1436 int x2 = xpos + em2;
1437
1438 // loop over all the datasets, each one has one row in the legend
1439 // if its data are to be used in at least one of the charts drawn
1440 // *but* only if there is a legend text for it!
1441 const int rightEdge = _legendRect.right();
1442 bool bFirstLF = true;
1443 painter->setFont( trueLegendFont() );
1444 TQFontMetrics txtMetrics( painter->fontMetrics() );
1445 int dataset;
1446 for ( dataset = 0; dataset < _numLegendTexts; ++dataset ) {
1447 /*
1448 if( KDChartParams::DataEntry == params()->chartSourceMode( dataset ) ) {
1449 */
1450 if( !_legendTexts[ dataset ].isEmpty() ){
1451 int txtWidth = txtMetrics.width( _legendTexts[ dataset ] ) + 1;
1452
1453 // calculate the width and height for the marker, relative to the font height
1454 // we need the legend text to be aligned to the marker
1455 // substract a gap.
1456 int legHeight = static_cast <int>((txtMetrics.height() - (int)(txtMetrics.height() * 0.1))*0.85);
1457
1458 //int legHeight = static_cast <int> (_legendRect.height()*0.8);
1459
1460 if( !bVertical && x2 + txtWidth >= rightEdge ){
1461 _legendRect.setHeight( _legendRect.height() + _legendSpacing );
1462 xpos = xposHori1;
1463 x2 = xpos + em2;
1464 ypos += bFirstLF ? legendTitleVertGap() : _legendSpacing;
1465 bFirstLF = false;
1466 }
1467 painter->setBrush( TQBrush( params()->dataColor( dataset ),
1468 TQBrush::SolidPattern ) );
1469
1470 if( params()->legendShowLines() ){
1471 painter->setPen( TQPen( params()->dataColor( dataset ), 2,
1472 params()->lineStyle( dataset ) ) );
1473 painter->drawLine(
1474 xpos - emDiv2,
1475 ypos + emDiv2 + 1,
1476 xpos + static_cast < int > ( _legendEMSpace * 1.5 ),
1477 ypos + emDiv2 + 1);
1478 }
1479
1480 /*
1481 // draw marker if we have a marker, OR we have no marker and no line
1482 if ( params()->lineMarker() ||
1483 params()->lineStyle( dataset ) == TQt::NoPen )*/
1484 drawMarker( painter,
1485 params(),
1486 _areaWidthP1000, _areaHeightP1000,
1487 _dataRect.x(), _dataRect.y(),
1488 params()->lineMarker()
1489 ? params()->lineMarkerStyle( dataset )
1490 : KDChartParams::LineMarkerSquare,
1491 params()->dataColor(dataset),
1492 TQPoint(xpos + emDiv2,
1493 bVertical? ypos + emDiv2: !bFirstLF ?ypos + _legendSpacing:_legendRect.center().y() - (legHeight / 2 ))/*ypos + emDiv2*/ ,
1494 0, 0, 0, NULL, // these params are deadweight here. TODO
1495 &legHeight /*&_legendEMSpace*/, &legHeight /*&_legendEMSpace*/,
1496 bVertical ? TQt::AlignCenter : (TQt::AlignTop | TQt::AlignHCenter) );
1497 /*
1498 painter->drawText(_legendRect.topLeft(), "topLeft" );
1499 painter->drawText(_legendRect.topLeft().x(), _legendRect.center().y(), "center" );
1500 painter->drawText(_legendRect.bottomLeft(), "bottomLeft" );
1501 */
1502 /* old:
1503 painter->setPen( TQt::black );
1504 painter->drawRect( xpos,
1505 ypos + ( _legendHeight - _legendEMSpace ) / 2,
1506 _legendEMSpace,
1507 _legendEMSpace );
1508 */
1509 painter->setPen( params()->legendTextColor() );
1510 painter->drawText( x2,
1511 bVertical ? ypos : !bFirstLF ? ypos + _legendSpacing : _legendRect.center().y() - (legHeight / 2 ),
1512 txtWidth,
1513 legHeight,
1514 TQt::AlignLeft | TQt::AlignVCenter,
1515 _legendTexts[ dataset ] );
1516
1517 if( bVertical )
1518 ypos += _legendSpacing;
1519 else {
1520 xpos += txtWidth + em4;
1521 x2 += txtWidth + em4;
1522 }
1523 }
1524 }
1525
1526 painter->setPen( TQPen( TQt::black, 1 ) );
1527 painter->setBrush( TQBrush::NoBrush );
1528 if( !bFrameFound )
1529 painter->drawRect( _legendRect );
1530
1531
1532 painter->restore();
1533}
1534
1535
1536void adjustFromTo(int& from, int& to)
1537{
1538 if( abs(from) > abs(to) ){
1539 int n = from;
1540 from = to;
1541 to = n;
1542 }
1543}
1544
1545
1546bool KDChartPainter::axesOverlapping( int axis1, int axis2 )
1547{
1548 KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis1 );
1549 if( basicPos != KDChartAxisParams::basicAxisPos( axis2 ) )
1550 // Only axes of the same position can be compared. (e.g. 2 left axes)
1551 return false;
1552
1553 if( KDChartAxisParams::AxisPosLeft != basicPos &&
1554 KDChartAxisParams::AxisPosRight != basicPos )
1555 // Available space usage only possible for (vertical) ordinate axes.
1556 return false;
1557
1558 int f1 = params()->axisParams( axis1 ).axisUseAvailableSpaceFrom();
1559 int t1 = params()->axisParams( axis1 ).axisUseAvailableSpaceTo();
1560 int f2 = params()->axisParams( axis2 ).axisUseAvailableSpaceFrom();
1561 int t2 = params()->axisParams( axis2 ).axisUseAvailableSpaceTo();
1562 adjustFromTo(f1,t1);
1563 adjustFromTo(f2,t2);
1564 // give these values some meaning
1565 // to be able to compare mixed fixed and/or relative figures:
1566 const double guessedAxisHeightP1000 = _areaHeightP1000 * 80.0 / 100.0;
1567 if(f1 < 0) f1 = static_cast < int > ( f1 * -guessedAxisHeightP1000 );
1568 if(t1 < 0) t1 = static_cast < int > ( t1 * -guessedAxisHeightP1000 );
1569 if(f2 < 0) f2 = static_cast < int > ( f2 * -guessedAxisHeightP1000 );
1570 if(t2 < 0) t2 = static_cast < int > ( t2 * -guessedAxisHeightP1000 );
1571 const bool res = (f1 >= f2 && f1 < t2) || (f2 >= f1 && f2 < t1);
1572 return res;
1573}
1574
1575
1576void internSetAxisArea( KDChartParams* params, int axis,
1577 int x0, int y0, int w0, int h0 )
1578{
1579 // axis may never occupy more than 1000 per mille of the available space
1580 int nFrom = TQMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceFrom());
1581 int nTo = TQMAX(-1000, params->axisParams( axis ).axisUseAvailableSpaceTo());
1582 adjustFromTo(nFrom,nTo);
1583
1584 KDChartAxisParams::AxisPos basicPos = KDChartAxisParams::basicAxisPos( axis );
1585 int x, y, w, h;
1586 if( KDChartAxisParams::AxisPosBottom == basicPos ||
1587 KDChartAxisParams::AxisPosTop == basicPos ){
1588
1589 // Note: available space usage is ignored for abscissa axes!
1590 //
1591 //if( nFrom < 0 )
1592 // x = x0 + w0*nFrom/-1000;
1593 //else
1594 // x = x0 + nFrom;
1595 //y = y0;
1596 //if( nTo < 0 )
1597 // w = x0 + w0*nTo/-1000 - x;
1598 //else
1599 // w = x0 + nTo - x;
1600 //h = h0;
1601
1602 x = x0;
1603 y = y0;
1604 w = w0;
1605 h = h0;
1606
1607 }else{
1608 x = x0;
1609 if( nTo < 0 )
1610 y = y0 + h0 - h0*nTo/-1000;
1611 else
1612 y = y0 + h0 - nTo;
1613 w = w0;
1614 if( nFrom < 0 )
1615 h = y0 + h0 - h0*nFrom/-1000 - y;
1616 else
1617 h = y0 + h0 - nFrom - y;
1618 }
1619
1620 params->setAxisArea( axis,
1621 TQRect( x,
1622 y,
1623 w,
1624 h ) );
1625}
1626
1627
1636void KDChartPainter::paintHeaderFooter( TQPainter* painter,
1637 KDChartTableDataBase* /*data*/ )
1638{
1639 const double averageValueP1000 = TQMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
1640
1641 painter->save();
1642
1643 for( int iHdFt = KDChartParams::HdFtPosSTART;
1644 iHdFt <= KDChartParams::HdFtPosEND; ++iHdFt ){
1645 TQString txt( params()->headerFooterText( iHdFt ) );
1646 if ( !txt.isEmpty() ) {
1647 TQFont actFont( params()->headerFooterFont( iHdFt ) );
1648 if ( params()->headerFooterFontUseRelSize( iHdFt ) )
1649 actFont.setPixelSize( static_cast < int > (
1650 params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
1651 painter->setPen( params()->headerFooterColor( iHdFt ) );
1652 painter->setFont( actFont );
1653 // Note: The alignment flags used here match the rect calculation
1654 // done in KDChartPainter::setupGeometry().
1655 // AlignTop is done to ensure that the hd/ft texts of the same
1656 // group (e.g. Hd2L and Hd2 and Hd2R) have the same baselines.
1657
1658 TQRect rect( params()->headerFooterRect( iHdFt ) );
1659 int dXY = iHdFt < KDChartParams::HdFtPosFootersSTART
1660 ? _hdLeading/3
1661 : _ftLeading/3;
1662 rect.moveBy(dXY, dXY);
1663 rect.setWidth( rect.width() -2*dXY +1 );
1664 rect.setHeight( rect.height()-2*dXY +1 );
1665 painter->drawText( rect,
1666 TQt::AlignLeft | TQt::AlignTop | TQt::SingleLine,
1667 txt );
1668 }
1669 }
1670 painter->restore();
1671}
1672
1673
1674int KDChartPainter::calculateHdFtRects(
1675 TQPainter* painter,
1676 double averageValueP1000,
1677 int xposLeft,
1678 int xposRight,
1679 bool bHeader,
1680 int& yposTop,
1681 int& yposBottom )
1682{
1683 int& leading = (bHeader ? _hdLeading : _ftLeading);
1684 leading = 0; // pixels between the header (or footer, resp.) text
1685 // and the border of the respective Hd/Ft area
1686
1687 const int rangesCnt = 3;
1688 const int ranges[ rangesCnt ]
1689 = { bHeader ? KDChartParams::HdFtPosHeaders0START : KDChartParams::HdFtPosFooters0START,
1690 bHeader ? KDChartParams::HdFtPosHeaders1START : KDChartParams::HdFtPosFooters1START,
1691 bHeader ? KDChartParams::HdFtPosHeaders2START : KDChartParams::HdFtPosFooters2START };
1692 const int rangeSize = 3;
1693 TQFontMetrics* metrics[rangesCnt * rangeSize];
1694
1695 int i;
1696 for( i = 0; i < rangesCnt*rangeSize; ++i )
1697 metrics[ i ] = 0;
1698
1699 int iRange;
1700 int iHdFt;
1701 for( iRange = 0; iRange < rangesCnt; ++iRange ){
1702 for( i = 0; i < rangeSize; ++i ){
1703 iHdFt = ranges[iRange] + i;
1704 TQString txt( params()->headerFooterText( iHdFt ) );
1705 if ( !txt.isEmpty() ) {
1706 TQFont actFont( params()->headerFooterFont( iHdFt ) );
1707 if ( params()->headerFooterFontUseRelSize( iHdFt ) ) {
1708 actFont.setPixelSize( static_cast < int > (
1709 params()->headerFooterFontRelSize( iHdFt ) * averageValueP1000 ) );
1710 }
1711 painter->setFont( actFont );
1712 metrics[ iRange*rangeSize + i ] = new TQFontMetrics( painter->fontMetrics() );
1713 leading = TQMAX( leading, metrics[ iRange*rangeSize + i ]->lineSpacing() / 2 );
1714 }
1715 }
1716 }
1717
1718 if( bHeader )
1719 ++yposTop;//yposTop += leading/3;
1720 //else
1721 //--yposBottom;//yposBottom -= leading/3;
1722
1723 int leading23 = leading*2/3 +1;
1724
1725 for( iRange =
1726 bHeader ? 0 : rangesCnt-1;
1727 bHeader ? iRange < rangesCnt : iRange >= 0;
1728 bHeader ? ++iRange : --iRange ){
1729 // Ascents and heights must be looked at to ensure that the hd/ft texts
1730 // of the same group (e.g. Hd2L and Hd2 and Hd2R) have equal baselines.
1731 int ascents[rangeSize];
1732 int heights[rangeSize];
1733 int widths[ rangeSize];
1734 int maxAscent = 0;
1735 int maxHeight = 0;
1736 for( i = 0; i < rangeSize; ++i ){
1737 iHdFt = ranges[iRange] + i;
1738 if ( metrics[ iRange*rangeSize + i ] ) {
1739 TQFontMetrics& m = *metrics[ iRange*rangeSize + i ];
1740 ascents[i] = m.ascent();
1741 heights[i] = m.height() + leading23;
1742
1743 // the following adds two spaces to work around a bug in TQt:
1744 // bounding rect sometimes is too small, if using italicized fonts
1745 widths[ i] = m.boundingRect( params()->headerFooterText( iHdFt )+" " ).width() + leading23;
1746
1747 maxAscent = TQMAX( maxAscent, ascents[i] );
1748 maxHeight = TQMAX( maxHeight, heights[i] );
1749 }else{
1750 heights[i] = 0;
1751 }
1752 }
1753
1754 if( !bHeader )
1755 yposBottom -= maxHeight;
1756
1757 for( i = 0; i < rangeSize; ++i ){
1758 if( heights[i] ){
1759 iHdFt = ranges[iRange] + i;
1760 int x1;
1761 switch( i ){
1762 case 1: x1 = xposLeft+1;
1763 break;
1764 case 2: x1 = xposRight-widths[i]-1;
1765 break;
1766 default: x1 = xposLeft + (xposRight-xposLeft-widths[i]) / 2;
1767 }
1768 ((KDChartParams*)params())->__internalStoreHdFtRect( iHdFt,
1769 TQRect( x1,
1770 bHeader
1771 ? yposTop + maxAscent - ascents[i]
1772 : yposBottom + maxAscent - ascents[i],
1773 widths[ i],
1774 heights[i] - 1 ) );
1775 }
1776 }
1777 if( bHeader )
1778 yposTop += leading + maxHeight;
1779 else
1780 yposBottom -= leading;
1781 }
1782 for( i = 0; i < rangesCnt*rangeSize; ++i )
1783 if( metrics[ i ] )
1784 delete metrics[ i ];
1785 return leading;
1786}
1787
1788
1789
1790void KDChartPainter::findChartDatasets( KDChartTableDataBase* data,
1791 bool paint2nd,
1792 uint chart,
1793 uint& chartDatasetStart,
1794 uint& chartDatasetEnd )
1795{
1796 chartDatasetStart = 0;
1797 chartDatasetEnd = 0;
1798 if( params()->neverUsedSetChartSourceMode()
1799 || !params()->findDatasets( KDChartParams::DataEntry,
1800 KDChartParams::ExtraLinesAnchor,
1801 chartDatasetStart,
1802 chartDatasetEnd,
1803 chart ) ) {
1804 uint maxRow, maxRowMinus1;
1805 switch ( data->usedRows() ) {
1806 case 0:
1807 return ;
1808 case 1:
1809 maxRow = 0;
1810 maxRowMinus1 = 0;
1811 break;
1812 default:
1813 maxRow = data->usedRows() - 1;
1814 maxRowMinus1 = maxRow;
1815 }
1816 chartDatasetStart = paint2nd ? maxRow : 0;
1817 chartDatasetEnd = paint2nd
1818 ? maxRow
1819 : ( ( KDChartParams::NoType == params()->additionalChartType() )
1820 ? maxRow
1821 : maxRowMinus1 );
1822
1823 }
1824}
1825
1826
1827void KDChartPainter::calculateAllAxesRects(
1828 TQPainter* painter,
1829 bool finalPrecision,
1831 )
1832{
1833 const bool bIsAreaChart = KDChartParams::Area == params()->chartType();
1834 const bool bMultiRows = KDChartParams::Bar == params()->chartType() &&
1835 KDChartParams::BarMultiRows == params()->barChartSubType();
1836
1837 const int trueWidth = _outermostRect.width();
1838 const int trueHeight = _outermostRect.height();
1839 const double averageValueP1000 = TQMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
1840
1841 // store the axes' 0 offsets
1842 int nAxesLeft0 = _axesRect.left() - _outermostRect.left();
1843 int nAxesRight0 = _outermostRect.right() - _axesRect.right();
1844 int nAxesTop0 = _axesRect.top() - _outermostRect.top();
1845 int nAxesBottom0 = _outermostRect.bottom() - _axesRect.bottom();
1846 if( bMultiRows ){
1847 uint chartDatasetStart, chartDatasetEnd;
1848 findChartDatasets( data, false, 0, chartDatasetStart, chartDatasetEnd );
1849 const int datasets = chartDatasetEnd - chartDatasetStart + 1;
1850 int numValues = 0;
1851 if ( params()->numValues() != -1 )
1852 numValues = params()->numValues();
1853 else
1854 numValues = data->usedCols();
1855 if( datasets ){
1856 const int additionalGapWidth = static_cast < int > ( 1.0 * _axesRect.width() / (9.75*numValues + 4.0*datasets) * 4.0*datasets );
1857 nAxesRight0 += additionalGapWidth;
1858 nAxesTop0 += static_cast < int > ( additionalGapWidth * 0.52 );
1859 //const double widthFactor = additionalGapWidth*1.0 / _axesRect.width();
1860 //nAxesTop0 += static_cast < int > ( _axesRect.height() * widthFactor );
1861 }
1862 }
1863 // store the distances to be added to the axes' 0 offsets
1864 int nAxesLeftADD =0;
1865 int nAxesRightADD =0;
1866 int nAxesTopADD =0;
1867 int nAxesBottomADD=0;
1868
1869 // determine whether the axes widths of one side should be added
1870 // or their maximum should be used
1871 bool bAddLeft = axesOverlapping( KDChartAxisParams::AxisPosLeft,
1872 KDChartAxisParams::AxisPosLeft2 );
1873 bool bAddRight = axesOverlapping( KDChartAxisParams::AxisPosRight,
1874 KDChartAxisParams::AxisPosRight2 );
1875 bool bAddTop = axesOverlapping( KDChartAxisParams::AxisPosTop,
1876 KDChartAxisParams::AxisPosTop2 );
1877 bool bAddBottom = axesOverlapping( KDChartAxisParams::AxisPosBottom,
1878 KDChartAxisParams::AxisPosBottom2 );
1879 // iterate over all axes
1880 uint iAxis;
1881 for ( iAxis = 0; iAxis < KDCHART_MAX_AXES; ++iAxis ) {
1882 //tqDebug( "iAxis %i", iAxis );
1883 const KDChartAxisParams& para = params()->axisParams( iAxis );
1884 int areaSize = 0;
1885
1886 if ( para.axisVisible()
1887 && KDChartAxisParams::AxisTypeUnknown != para.axisType() ) {
1888
1889 const KDChartAxisParams::AxisPos
1890 basicPos( KDChartAxisParams::basicAxisPos( iAxis ) );
1891
1892 int areaMin = para.axisAreaMin();
1893 int areaMax = para.axisAreaMax();
1894 if ( 0 > areaMin )
1895 areaMin = static_cast < int > ( -1.0 * averageValueP1000 * areaMin );
1896 if ( 0 > areaMax )
1897 areaMax = static_cast < int > ( -1.0 * averageValueP1000 * areaMax );
1898
1899 // make sure areaMin will not be too small
1900 // for the label texts and check if there is an axis Title
1901 switch ( basicPos ) {
1902 case KDChartAxisParams::AxisPosBottom:
1903 case KDChartAxisParams::AxisPosTop:
1904 if ( para.axisLabelsVisible() ) {
1905 int fntHeight;
1906 if ( para.axisLabelsFontUseRelSize() )
1907 fntHeight = TQMAX(static_cast < int > ( para.axisLabelsFontRelSize() * averageValueP1000 ),
1908 para.axisLabelsFontMinSize() );
1909 else {
1910 painter->setFont( para.axisLabelsFont() );
1911 TQFontMetrics metrics( painter->fontMetrics() );
1912 fntHeight = metrics.height();
1913 }
1914 // adjust text height in case of formatted Date/Time values
1915 uint dataDataset, dataDataset2;
1916 if( !params()->findDataset( KDChartParams::DataEntry,
1917 dataDataset,
1918 dataDataset2,
1919 KDCHART_ALL_CHARTS ) ) {
1920 tqDebug( "IMPLEMENTATION ERROR: findDataset( DataEntry, ... ) should *always* return true. (a)" );
1921 dataDataset = KDCHART_ALL_DATASETS;
1922 }
1923 TQVariant::Type valType = TQVariant::Invalid;
1924 const bool dataCellsHaveSeveralCoordinates =
1925 (KDCHART_ALL_DATASETS == dataDataset)
1926 ? data->cellsHaveSeveralCoordinates( &valType )
1927 : data->cellsHaveSeveralCoordinates( dataDataset, dataDataset2, &valType );
1928 TQString format( para.axisLabelsDateTimeFormat() );
1929 if( dataCellsHaveSeveralCoordinates
1930 && TQVariant::DateTime == valType ){
1932 areaMin = TQMAX( areaMin, static_cast < int > ( fntHeight * 6.75 ) );
1933 else
1934 areaMin = TQMAX( areaMin, fntHeight * ( 3 + format.contains("\n") ) );
1935 }
1936 else
1937 areaMin = TQMAX( areaMin, fntHeight * 3 );
1938 }
1939 break;
1940 case KDChartAxisParams::AxisPosLeft:
1941 case KDChartAxisParams::AxisPosRight:
1942 default:
1943 break;
1944 }
1945
1946
1947 switch ( para.axisAreaMode() ) {
1948 case KDChartAxisParams::AxisAreaModeAutoSize:
1949 {
1950 areaSize = areaMin;
1951 switch ( basicPos ) {
1952 case KDChartAxisParams::AxisPosBottom:
1953 case KDChartAxisParams::AxisPosTop:
1954 break;
1955 case KDChartAxisParams::AxisPosLeft:
1956 case KDChartAxisParams::AxisPosRight:
1957 if( finalPrecision ){
1958 internal__KDChart__CalcValues& cv = calcVal[iAxis];
1959 const int nUsableAxisWidth = static_cast < int > (cv.pTextsW);
1960 const KDChartAxisParams & para = params()->axisParams( iAxis );
1961 TQFont axisLabelsFont( para.axisLabelsFont() );
1962 if ( para.axisLabelsFontUseRelSize() ) {
1963 axisLabelsFont.setPixelSize( static_cast < int > ( cv.nTxtHeight ) );
1964 }
1965 painter->setFont( para.axisLabelsFont() );
1966 TQFontMetrics axisLabelsFontMetrics( painter->fontMetrics() );
1967 const int lenEM( axisLabelsFontMetrics.boundingRect("M").width() );
1968 const TQStringList* labelTexts = para.axisLabelTexts();
1969 uint nLabels = ( 0 != labelTexts )
1970 ? labelTexts->count()
1971 : 0;
1972 int maxLabelsWidth = 0;
1973 for ( uint i = 0; i < nLabels; ++i )
1974 maxLabelsWidth =
1975 TQMAX( maxLabelsWidth,
1976 axisLabelsFontMetrics.boundingRect(*labelTexts->at(i)).width() );
1977 if( nUsableAxisWidth < maxLabelsWidth )
1978 areaSize = maxLabelsWidth
1979 + (para.axisTrueAreaRect().width() - nUsableAxisWidth)
1980 + lenEM;
1981 }
1982 break;
1983 default:
1984 break;
1985 }
1986 }
1987 break;
1988 case KDChartAxisParams::AxisAreaModeMinMaxSize:
1989 {
1990 tqDebug( "Sorry, not implemented: AxisAreaModeMinMaxSize" );
1991 }
1992
1993 //
1994 //
1995 // F E A T U R E P L A N N E D F O R F U T U R E . . .
1996 //
1997 //
1998
1999 // break;
2000
2001 case KDChartAxisParams::AxisAreaModeFixedSize:
2002 {
2003 areaSize = areaMax ? TQMIN( areaMin, areaMax ) : areaMin;
2004 }
2005 break;
2006 }
2007
2008 //find out if there is a title box
2009 uint idx;
2010 int boxSize = 0;
2011 for( idx = 0; idx <= params()->maxCustomBoxIdx(); ++idx ) {
2012 const KDChartCustomBox * box = params()->customBox( idx );
2013 if ( box )
2014 if ( box->parentAxisArea() == KDChartAxisParams::AxisPosBottom
2015 || box->parentAxisArea() == KDChartAxisParams::AxisPosLeft
2016 || box->parentAxisArea() == KDChartAxisParams::AxisPosTop
2017 || box->parentAxisArea() == KDChartAxisParams::AxisPosRight )
2018 boxSize = box->trueRect(TQPoint( 0,0 ), _areaWidthP1000, _areaHeightP1000 ).height();
2019 }
2020
2021 areaSize += boxSize;
2022
2023 switch ( basicPos ) {
2024 case KDChartAxisParams::AxisPosBottom:
2025 if( bAddBottom ) {
2026 //areaSize += boxSize;
2027 nAxesBottomADD += areaSize;
2028 }
2029 else{
2030 // areaSize += boxSize;
2031 nAxesBottomADD = TQMAX( nAxesBottomADD + boxSize, areaSize );
2032 }
2033 break;
2034 case KDChartAxisParams::AxisPosLeft:
2035 if( bAddLeft )
2036 nAxesLeftADD += areaSize;
2037 else
2038 nAxesLeftADD = TQMAX( nAxesLeftADD + boxSize, areaSize );
2039 break;
2040 case KDChartAxisParams::AxisPosTop:
2041 if( bAddTop )
2042 nAxesTopADD += areaSize;
2043 else
2044 nAxesTopADD = TQMAX( nAxesTopADD + boxSize, areaSize );
2045 break;
2046 case KDChartAxisParams::AxisPosRight:
2047 if( bAddRight )
2048 nAxesRightADD += areaSize;
2049 else
2050 nAxesRightADD = TQMAX( nAxesRightADD + boxSize, areaSize );
2051 break;
2052 default:
2053 break;
2054 }
2055 }
2056 // Note: to prevent users from erroneously calling this
2057 // function we do *not* provide a wrapper for it
2058 // in the KDChartParams class but rather call it
2059 // *directly* using a dirty typecast.
2060 ( ( KDChartAxisParams& ) para ).setAxisTrueAreaSize( areaSize );
2061 }
2062 int nMinDistance = static_cast < int > ( 30.0 * averageValueP1000 );
2063
2064 int nAxesBottom = TQMAX( nAxesBottom0 + nAxesBottomADD, nMinDistance );
2065
2066 // for micro alignment with the X axis, we adjust the Y axis - but not for Area Charts:
2067 // otherwise the areas drawn would overwrite the Y axis line.
2068 int nAxesLeft = TQMAX( nAxesLeft0 + nAxesLeftADD, nMinDistance )
2069 - (bIsAreaChart ? 0 : 1);
2070
2071 int nAxesTop = TQMAX( nAxesTop0 + nAxesTopADD, nMinDistance );
2072
2073 int nAxesRight = TQMAX( nAxesRight0 + nAxesRightADD, nMinDistance );
2074
2075 int nBottom = params()->axisParams( KDChartAxisParams::AxisPosBottom ).axisTrueAreaSize();
2076 int nLeft = params()->axisParams( KDChartAxisParams::AxisPosLeft ).axisTrueAreaSize();
2077 int nTop = params()->axisParams( KDChartAxisParams::AxisPosTop ).axisTrueAreaSize();
2078 int nRight = params()->axisParams( KDChartAxisParams::AxisPosRight ).axisTrueAreaSize();
2079 int nBottom2 = params()->axisParams( KDChartAxisParams::AxisPosBottom2 ).axisTrueAreaSize();
2080 int nLeft2 = params()->axisParams( KDChartAxisParams::AxisPosLeft2 ).axisTrueAreaSize();
2081 int nTop2 = params()->axisParams( KDChartAxisParams::AxisPosTop2 ).axisTrueAreaSize();
2082 int nRight2 = params()->axisParams( KDChartAxisParams::AxisPosRight2 ).axisTrueAreaSize();
2083
2084 internSetAxisArea( _params,
2085 KDChartAxisParams::AxisPosBottom,
2086 _outermostRect.left() + nAxesLeft,
2087 _outermostRect.top() + trueHeight - nAxesBottom,
2088 trueWidth - nAxesLeft - nAxesRight + 1,
2089 nBottom );
2090 internSetAxisArea( _params,
2091 KDChartAxisParams::AxisPosLeft,
2092 _outermostRect.left() + (bAddLeft ? nAxesLeft0 + nLeft2 : nAxesLeft0),
2093 _outermostRect.top() + nAxesTop,
2094 nLeft,
2095 trueHeight - nAxesTop - nAxesBottom + 1 );
2096
2097 internSetAxisArea( _params,
2098 KDChartAxisParams::AxisPosTop,
2099 _outermostRect.left() + nAxesLeft,
2100 _outermostRect.top() + (bAddTop ? nAxesTop0 + nTop2 : nAxesTop0),
2101 trueWidth - nAxesLeft - nAxesRight + 1,
2102 nTop );
2103 internSetAxisArea( _params,
2104 KDChartAxisParams::AxisPosRight,
2105 _outermostRect.left() + trueWidth - nAxesRight,
2106 _outermostRect.top() + nAxesTop,
2107 nRight,
2108 trueHeight - nAxesTop - nAxesBottom + 1 );
2109
2110 internSetAxisArea( _params,
2111 KDChartAxisParams::AxisPosBottom2,
2112 _outermostRect.left() + nAxesLeft,
2113 _outermostRect.top() + trueHeight - nAxesBottom + (bAddBottom ? nBottom : 0),
2114 trueWidth - nAxesLeft - nAxesRight + 1,
2115 nBottom2 );
2116 internSetAxisArea( _params,
2117 KDChartAxisParams::AxisPosLeft2,
2118 _outermostRect.left() + nAxesLeft0,
2119 _outermostRect.top() + nAxesTop,
2120 nLeft2,
2121 trueHeight - nAxesTop - nAxesBottom + 1 );
2122
2123 internSetAxisArea( _params,
2124 KDChartAxisParams::AxisPosTop2,
2125 _outermostRect.left() + nAxesLeft,
2126 _outermostRect.top() + nAxesTop0,
2127 trueWidth - nAxesLeft - nAxesRight + 1,
2128 nTop2 );
2129 internSetAxisArea( _params,
2130 KDChartAxisParams::AxisPosRight2,
2131 _outermostRect.left() + trueWidth - nAxesRight + (bAddRight ? nRight : 0),
2132 _outermostRect.top() + nAxesTop,
2133 nRight2,
2134 trueHeight - nAxesTop - nAxesBottom + 1 );
2135
2136 _dataRect = TQRect( _outermostRect.left() + nAxesLeft,
2137 _outermostRect.top() + nAxesTop,
2138 trueWidth - nAxesLeft - nAxesRight + 1,
2139 trueHeight - nAxesTop - nAxesBottom + 1 );
2140}
2141
2142
2143
2156void KDChartPainter::setupGeometry( TQPainter* painter,
2158 const TQRect& drawRect )
2159{
2160 //tqDebug("INVOKING: KDChartPainter::setupGeometry()");
2161 // avoid recursion from repaint() being called due to params() changed signals...
2162 const bool oldBlockSignalsState = params()->signalsBlocked();
2163 const_cast < KDChartParams* > ( params() )->blockSignals( true );
2164
2165 _outermostRect = drawRect;
2166
2167 int yposTop = _outermostRect.topLeft().y();
2168 int xposLeft = _outermostRect.topLeft().x();
2169 int yposBottom = _outermostRect.bottomRight().y();
2170 int xposRight = _outermostRect.bottomRight().x();
2171
2172 const int trueWidth = _outermostRect.width();
2173 const int trueHeight = _outermostRect.height();
2174
2175 // Temporary values used to calculate start values xposLeft, yposTop, xposRight, yposBottom.
2176 // They will be replaced immediately after these calculations.
2177 _areaWidthP1000 = trueWidth / 1000.0;
2178 _areaHeightP1000 = trueHeight / 1000.0;
2179
2180
2181 xposLeft += 0 < params()->globalLeadingLeft()
2182 ? params()->globalLeadingLeft()
2183 : static_cast < int > ( params()->globalLeadingLeft() * -_areaWidthP1000 );
2184 yposTop += 0 < params()->globalLeadingTop()
2185 ? params()->globalLeadingTop()
2186 : static_cast < int > ( params()->globalLeadingTop() * -_areaHeightP1000 );
2187 xposRight -= 0 < params()->globalLeadingRight()
2188 ? params()->globalLeadingRight()
2189 : static_cast < int > ( params()->globalLeadingRight() * -_areaWidthP1000 );
2190 yposBottom -= 0 < params()->globalLeadingBottom()
2191 ? params()->globalLeadingBottom()
2192 : static_cast < int > ( params()->globalLeadingBottom()* -_areaHeightP1000 );
2193
2194 _innermostRect = TQRect( TQPoint(xposLeft, yposTop),
2195 TQPoint(xposRight, yposBottom) );
2196
2197 _logicalWidth = xposRight - xposLeft;
2198 _logicalHeight = yposBottom - yposTop;
2199
2200 // true values (having taken the global leadings into account)
2201 // to be used by all following functions
2202 _areaWidthP1000 = _logicalWidth / 1000.0;
2203 _areaHeightP1000 = _logicalHeight / 1000.0;
2204
2205 double averageValueP1000 = TQMIN(_areaWidthP1000, _areaHeightP1000);//( _areaWidthP1000 + _areaHeightP1000 ) / 2.0;
2206
2207 // new code design:
2208 // 1. now min-header-leading is text height/2
2209 // 2. leading or legendSpacing (whichever is larger)
2210 // will be added if legend is below the header(s)
2211 // 3. leading will be added between header and data area
2212 // in case there is no top legend but grid is to be shown.
2213 int headerLineLeading = calculateHdFtRects(
2214 painter,
2215 averageValueP1000,
2216 xposLeft, xposRight,
2217 false,
2218 yposTop, yposBottom );
2219 calculateHdFtRects(
2220 painter,
2221 averageValueP1000,
2222 xposLeft, xposRight,
2223 true,
2224 yposTop, yposBottom );
2225
2226 // Calculate legend position. First check whether there is going
2227 // to be a legend at all:
2228 if ( params()->legendPosition() != KDChartParams::NoLegend ) {
2229 // Now calculate the size needed for the legend
2230 findLegendTexts( data );
2231
2232 bool hasLegendTitle = false;
2233 if ( !params()->legendTitleText().isEmpty() )
2234 hasLegendTitle = true;
2235
2236 _legendTitleWidth = 0;
2237 if( _legendTitle )
2238 delete _legendTitle;
2239 _legendTitle = 0;
2240 if ( hasLegendTitle ) {
2241 const TQFont font( trueLegendTitleFont() );
2242 painter->setFont( font );
2243 TQFontMetrics legendTitleMetrics( painter->fontMetrics() );
2244 _legendTitleMetricsHeight = legendTitleMetrics.height();
2245
2246 _legendTitle = new KDChartTextPiece( painter,
2247 params()->legendTitleText(),
2248 font );
2249 _legendTitleWidth = _legendTitle->width();
2250 _legendTitleHeight = _legendTitle->height();
2251 // tqDebug("1. _legendTitleHeight %i",_legendTitleHeight);
2252 }
2253
2254 painter->setFont( trueLegendFont() );
2255 TQFontMetrics legendMetrics( painter->fontMetrics() );
2256 _legendSpacing = legendMetrics.lineSpacing();
2257 _legendHeight = legendMetrics.height();
2258 _legendLeading = legendMetrics.leading();
2259
2260 _legendEMSpace = legendMetrics.width( 'M' );
2261
2262 int sizeX = 0;
2263 int sizeY = 0;
2264
2265 for ( int dataset = 0; dataset < _numLegendTexts; dataset++ ) {
2266 sizeX = TQMAX( sizeX, legendMetrics.width( _legendTexts[ dataset ] ) );
2267 if( !_legendTexts[ dataset ].isEmpty() )
2268 sizeY += _legendSpacing;
2269 }
2270 // add space below the legend's bottom line
2271 sizeY += _legendEMSpace - _legendLeading;
2272 // add space for the legend title if any was set
2273 if ( hasLegendTitle )
2274 sizeY += legendTitleVertGap();
2275
2276 // assume 4 em spaces: before the color box, the color box, after the
2277 // color box and after the legend text
2278 sizeX += ( _legendEMSpace * 4 );
2279
2280 // We cannot setup the title width earlier as the title does
2281 // not have a color box. The two em spaces are before the
2282 // color box (where the title does not start yet, it is
2283 // left-aligned with the color boxes) and after the title (to
2284 // have some space before the boundary line comes).
2285 sizeX = TQMAX( sizeX, _legendTitleWidth + _legendEMSpace*2 );
2286
2287 //tqDebug("setupGeometry mustDrawVerticalLegend: %s", mustDrawVerticalLegend() ? "YES":"NO ");
2288
2289 // PENDING Michel: do that after having calculated the position
2290 if( !mustDrawVerticalLegend() ){
2291 TQSize size;
2292 calculateHorizontalLegendSize( painter,
2293 size,
2294 _legendNewLinesStartAtLeft );
2295 sizeX = size.width();
2296 sizeY = size.height();
2297 }
2298
2299 switch ( params()->legendPosition() ) {
2300 case KDChartParams::LegendTop:
2301 if ( headerLineLeading )
2302 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2303 _legendRect = TQRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
2304 yposTop, sizeX, sizeY );
2305 yposTop = _legendRect.bottom() + params()->legendSpacing();
2306 //tqDebug("A: _legendRect:\n%i,%i\n%i,%i", _legendRect.left(),_legendRect.top(),_legendRect.right(),_legendRect.bottom() );
2307 break;
2308 case KDChartParams::LegendBottom:
2309 if ( params()->showGrid() )
2310 yposTop += headerLineLeading;
2311 _legendRect = TQRect( xposLeft + ( (xposRight-xposLeft) - sizeX ) / 2,
2312 yposBottom - sizeY,
2313 sizeX, sizeY );
2314 yposBottom = _legendRect.top() - params()->legendSpacing();
2315 break;
2316 case KDChartParams::LegendLeft:
2317 if ( params()->showGrid() )
2318 yposTop += headerLineLeading;
2319 _legendRect = TQRect( xposLeft + 1, ( yposBottom - yposTop - sizeY ) / 2 +
2320 yposTop,
2321 sizeX, sizeY );
2322 xposLeft = _legendRect.right() + params()->legendSpacing();
2323 break;
2324 case KDChartParams::LegendRight:
2325 if ( params()->showGrid() )
2326 yposTop += headerLineLeading;
2327 _legendRect = TQRect( xposRight - sizeX - 1,
2328 ( yposBottom - yposTop - sizeY ) / 2 + yposTop,
2329 sizeX, sizeY );
2330 xposRight = _legendRect.left() - params()->legendSpacing();
2331 break;
2332 case KDChartParams::LegendTopLeft:
2333 if ( headerLineLeading )
2334 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2335 _legendRect = TQRect( xposLeft + 1, yposTop, sizeX, sizeY );
2336 yposTop = _legendRect.bottom() + params()->legendSpacing();
2337 xposLeft = _legendRect.right() + params()->legendSpacing();
2338 break;
2339 case KDChartParams::LegendTopLeftTop:
2340 if ( headerLineLeading )
2341 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2342 _legendRect = TQRect( xposLeft + 1, yposTop, sizeX, sizeY );
2343 yposTop = _legendRect.bottom() + params()->legendSpacing();
2344 break;
2345 case KDChartParams::LegendTopLeftLeft:
2346 if ( headerLineLeading )
2347 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2348 _legendRect = TQRect( xposLeft + 1, yposTop, sizeX, sizeY );
2349 xposLeft = _legendRect.right() + params()->legendSpacing();
2350 break;
2351 case KDChartParams::LegendTopRight:
2352 if ( headerLineLeading )
2353 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2354 _legendRect = TQRect( xposRight - sizeX - 1,
2355 yposTop, sizeX, sizeY );
2356 yposTop = _legendRect.bottom() + params()->legendSpacing();
2357 xposRight = _legendRect.left() - params()->legendSpacing();
2358 break;
2359 case KDChartParams::LegendTopRightTop:
2360 if ( headerLineLeading )
2361 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2362 _legendRect = TQRect( xposRight - sizeX - 1,
2363 yposTop, sizeX, sizeY );
2364 yposTop = _legendRect.bottom() + params()->legendSpacing();
2365 break;
2366 case KDChartParams::LegendTopRightRight:
2367 if ( headerLineLeading )
2368 yposTop += TQMAX( (int)params()->legendSpacing(), headerLineLeading );
2369 _legendRect = TQRect( xposRight - sizeX - 1,
2370 yposTop, sizeX, sizeY );
2371 xposRight = _legendRect.left() - params()->legendSpacing();
2372 break;
2373 case KDChartParams::LegendBottomLeft:
2374 if ( params()->showGrid() )
2375 yposTop += headerLineLeading;
2376 _legendRect = TQRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
2377 yposBottom = _legendRect.top() - params()->legendSpacing();
2378 xposLeft = _legendRect.right() + params()->legendSpacing();
2379 break;
2380 case KDChartParams::LegendBottomLeftBottom:
2381 if ( params()->showGrid() )
2382 yposTop += headerLineLeading;
2383 _legendRect = TQRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
2384 yposBottom = _legendRect.top() - params()->legendSpacing();
2385 break;
2386 case KDChartParams::LegendBottomLeftLeft:
2387 if ( params()->showGrid() )
2388 yposTop += headerLineLeading;
2389 _legendRect = TQRect( xposLeft + 1, yposBottom - sizeY, sizeX, sizeY );
2390 xposLeft = _legendRect.right() + params()->legendSpacing();
2391 break;
2392 case KDChartParams::LegendBottomRight:
2393 if ( params()->showGrid() )
2394 yposTop += headerLineLeading;
2395 _legendRect = TQRect( xposRight - sizeX - 1,
2396 yposBottom - sizeY, sizeX, sizeY );
2397 yposBottom = _legendRect.top() - params()->legendSpacing();
2398 xposRight = _legendRect.left() - params()->legendSpacing();
2399 break;
2400 case KDChartParams::LegendBottomRightBottom:
2401 if ( params()->showGrid() )
2402 yposTop += headerLineLeading;
2403 _legendRect = TQRect( xposRight - sizeX - 1,
2404 yposBottom - sizeY, sizeX, sizeY );
2405 yposBottom = _legendRect.top() - params()->legendSpacing();
2406 break;
2407 case KDChartParams::LegendBottomRightRight:
2408 if ( params()->showGrid() )
2409 yposTop += headerLineLeading;
2410 _legendRect = TQRect( xposRight - sizeX - 1,
2411 yposBottom - sizeY, sizeX, sizeY );
2412 xposRight = _legendRect.left() - params()->legendSpacing();
2413 break;
2414 default:
2415 // Should not be able to happen
2416 tqDebug( "KDChart: Unknown legend position" );
2417 }
2418 _params->setLegendArea( _legendRect );
2419
2420 }else{
2421 _params->setLegendArea( TQRect(TQPoint(0,0), TQSize(0,0)) );
2422 }
2423
2424
2425 _axesRect = TQRect( TQPoint(xposLeft, yposTop), TQPoint(xposRight, yposBottom) );
2426
2427 // important rule: do *not* calculate axes areas for Polar charts!
2428 // (even if left and bottom axes might be set active)
2429 if( KDChartParams::Polar == params()->chartType() ) {
2430 _dataRect = _axesRect;
2431 } else {
2432 // 1st step: make a preliminary approximation of the axes sizes,
2433 // as a basis of following label texts calculation
2434 calculateAllAxesRects( painter, false, data );
2435 // 2nd step: calculate all labels (preliminary data, will be
2436 // overwritten by KDChartAxesPainter)
2437 // to find out the longest possible axis labels
2438 double dblDummy;
2439 if( calculateAllAxesLabelTextsAndCalcValues(
2440 painter,
2441 data,
2442 _areaWidthP1000,
2443 _areaHeightP1000,
2444 dblDummy ) )
2445 // 3rd step: calculate the _true_ axes rects based upon
2446 // the preliminary axes labels
2447 calculateAllAxesRects( painter, true, data );
2448 }
2449 _params->setDataArea( _dataRect );
2450
2451 const_cast < KDChartParams* > ( params() )->blockSignals( oldBlockSignalsState );
2452}
2453
2454
2458void KDChartPainter::findLegendTexts( KDChartTableDataBase* data )
2459{
2460 uint dataset;
2461 TQVariant vValY;
2462 switch ( params()->legendSource() ) {
2463 case KDChartParams::LegendManual: {
2464 // The easiest case: Take manually set strings, no matter whether any
2465 // have been set.
2466 _numLegendTexts = numLegendFallbackTexts( data );
2467 for ( dataset = 0; dataset < static_cast<uint>(_numLegendTexts); dataset++ )
2468 _legendTexts[ dataset ] = params()->legendText( dataset );
2469 break;
2470 }
2471 case KDChartParams::LegendFirstColumn: {
2472 // Take whatever is in the first column
2473 for ( dataset = 0; dataset < data->usedRows(); dataset++ ){
2474 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
2475 if( TQVariant::String == vValY.type() )
2476 _legendTexts[ dataset ] = vValY.toString();
2477 else
2478 _legendTexts[ dataset ] = "";
2479 }
2480 }
2481 _numLegendTexts = data->usedRows();
2482 break;
2483 }
2484 case KDChartParams::LegendAutomatic: {
2485 // First, try the first row
2486 bool notfound = false;
2487 _numLegendTexts = numLegendFallbackTexts( data ); // assume this for cleaner
2488 // code below
2489 for ( dataset = 0; dataset < data->usedRows(); dataset++ ) {
2490 if( data->cellCoord( dataset, 0, vValY, 1 ) ){
2491 if( TQVariant::String == vValY.type() )
2492 _legendTexts[ dataset ] = vValY.toString();
2493 else
2494 _legendTexts[ dataset ] = "";
2495 if( _legendTexts[ dataset ].isEmpty() ){
2496 notfound = true;
2497 break;
2498 }
2499 }
2500 }
2501
2502 // If there were no entries for all the datasets, use the manually set
2503 // texts, and resort to Series 1, Series 2, ... where nothing has been
2504 // set.
2505 if ( notfound ) {
2506 for ( dataset = 0; dataset < numLegendFallbackTexts( data );
2507 dataset++ ) {
2508 _legendTexts[ dataset ] = params()->legendText( dataset );
2509 if ( _legendTexts[ dataset ].isEmpty() || _legendTexts[ dataset ].isNull() ) {
2510 _legendTexts[ dataset ] = fallbackLegendText( dataset );
2511 // there
2512 _numLegendTexts = numLegendFallbackTexts( data );
2513 }
2514 }
2515 }
2516 break;
2517 }
2518 default:
2519 // Should not happen
2520 tqDebug( "KDChart: Unknown legend source" );
2521 }
2522}
2523
2524
2540TQString KDChartPainter::fallbackLegendText( uint dataset ) const
2541{
2542 return TQObject::tr( "Series " ) + TQString::number( dataset + 1 );
2543}
2544
2545
2559{
2560 return data->usedRows();
2561}
2562
2563
2573void KDChartPainter::drawMarker( TQPainter* painter,
2574 int style,
2575 const TQColor& color,
2576 const TQPoint& p,
2577 const TQSize& size,
2578 uint align )
2579{
2580 int width = size.width();
2581 int height = size.height();
2582 drawMarker( painter,
2583 0,
2584 0.0, 0.0,
2585 0,0,
2586 style,
2587 color,
2588 p,
2589 0,0,0,
2590 0,
2591 &width,
2592 &height,
2593 align );
2594}
2595
2596
2612KDChartDataRegion* KDChartPainter::drawMarker( TQPainter* painter,
2613 const KDChartParams* params,
2614 double areaWidthP1000,
2615 double areaHeightP1000,
2616 int deltaX,
2617 int deltaY,
2618 int style,
2619 const TQColor& color,
2620 const TQPoint& _p,
2621 uint dataset, uint value, uint chart,
2622 KDChartDataRegionList* regions,
2623 int* width,
2624 int* height,
2625 uint align )
2626{
2627 KDChartDataRegion* datReg = 0;
2628 const double areaSizeP1000 = TQMIN(areaWidthP1000, areaHeightP1000);
2629 int xsize = width ? *width : (params ? params->lineMarkerSize().width() : 12);
2630 if( 0 > xsize )
2631 xsize = static_cast < int > (xsize * -areaSizeP1000);
2632 int ysize = height ? *height : (params ? params->lineMarkerSize().height() : 12);
2633 if( 0 > ysize )
2634 ysize = static_cast < int > (ysize * -areaSizeP1000);
2635 if( KDChartParams::LineMarkerCross != style ){
2636 xsize = TQMAX( xsize, 4 );
2637 ysize = TQMAX( ysize, 4 );
2638 }
2639 uint xsize2 = xsize / 2;
2640 uint ysize2 = ysize / 2;
2641 uint xsize4 = xsize / 4;
2642 uint ysize4 = ysize / 4;
2643 uint xsize6 = xsize / 6;
2644 uint ysize6 = ysize / 6;
2645 painter->setPen( color );
2646 const uint xysize2 = TQMIN( xsize2, ysize2 );
2647
2648 int x = _p.x();
2649 int y = _p.y();
2650 if( align & TQt::AlignLeft )
2651 x += xsize2;
2652 else if( align & TQt::AlignRight )
2653 x -= xsize2;
2654 if( align & TQt::AlignTop )
2655 y += ysize2;
2656 else if( align & TQt::AlignBottom )
2657 y -= ysize2;
2658 const TQPoint p(x, y);
2659
2660 switch ( style ) {
2661 case KDChartParams::LineMarkerSquare: {
2662 const TQPen oldPen( painter->pen() );
2663 const TQBrush oldBrush( painter->brush() );
2664 painter->setBrush( color );
2665 painter->setPen( color );
2666 TQRect rect( TQPoint( p.x() - xsize2, p.y() - ysize2 ), TQPoint( p.x() + xsize2, p.y() + ysize2 ) );
2667 painter->drawRect( rect );
2668 // Don't use rect for drawing after this!
2669 rect.moveBy( deltaX, deltaY );
2670 if ( regions ){
2671 datReg =
2672 new KDChartDataRegion(
2673 dataset, value,
2674 chart, rect );
2675 regions->append( datReg );
2676 }
2677 painter->setPen( oldPen );
2678 painter->setBrush( oldBrush );
2679 break;
2680 }
2681 case KDChartParams::LineMarkerDiamond:{
2682 const TQBrush oldBrush( painter->brush() );
2683 painter->setBrush( color );
2684 TQPointArray points( 4 );
2685 points.setPoint( 0, p.x() - xsize2, p.y() );
2686 points.setPoint( 1, p.x(), p.y() - ysize2 );
2687 points.setPoint( 2, p.x() + xsize2, p.y() );
2688 points.setPoint( 3, p.x(), p.y() + ysize2 );
2689 painter->drawPolygon( points );
2690 // Don't use points for drawing after this!
2691 points.translate( deltaX, deltaY );
2692 if ( regions ){
2693 datReg = new KDChartDataRegion(
2694 dataset, value,
2695 chart, points );
2696 regions->append( datReg );
2697 }
2698 painter->setBrush( oldBrush );
2699 break;
2700 }
2701 case KDChartParams::LineMarker1Pixel: {
2702 TQRect rect( p, p );
2703 painter->drawRect( rect );
2704 // Don't use rect for drawing after this!
2705 rect.moveBy( deltaX, deltaY );
2706 if ( regions ){
2707 datReg = new KDChartDataRegion(
2708 dataset, value,
2709 chart, rect );
2710 regions->append( datReg );
2711 }
2712 break;
2713 }
2714 case KDChartParams::LineMarker4Pixels:{
2715 TQRect rect( p, TQPoint( p.x()+1, p.y()+1 ) );
2716 painter->drawRect( rect );
2717 // Don't use rect for drawing after this!
2718 rect.moveBy( deltaX, deltaY );
2719 if ( regions ){
2720 datReg = new KDChartDataRegion(
2721 dataset, value,
2722 chart, rect );
2723 regions->append( datReg );
2724 }
2725 break;
2726 }
2727 case KDChartParams::LineMarkerRing: {
2728 const TQPen oldPen( painter->pen() );
2729 painter->setPen( TQPen( color, TQMIN(xsize4, ysize4) ) );
2730 const TQBrush oldBrush( painter->brush() );
2731 painter->setBrush( TQt::NoBrush );
2732 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
2733 if ( regions ) {
2734 TQPointArray points;
2735 points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
2736 // Don't use points for drawing after this!
2737 points.translate( deltaX, deltaY );
2738 if( points.size() > 0 ){
2739 datReg = new KDChartDataRegion(
2740 dataset, value,
2741 chart, points );
2742 regions->append( datReg );
2743 }
2744 }
2745 painter->setBrush( oldBrush );
2746 painter->setPen( oldPen );
2747 break;
2748 }
2749 case KDChartParams::LineMarkerCross: {
2750 const TQPen oldPen( painter->pen() );
2751 painter->setPen( color );
2752 const TQBrush oldBrush( painter->brush() );
2753 painter->setBrush( color );
2754 int numPoints = (ysize && xsize) ? 12 : 4;
2755 TQPointArray points( numPoints );
2756 if( ysize && xsize ){
2757 points.setPoint( 0, p.x() - xsize6, p.y() - ysize6 );
2758 points.setPoint( 1, p.x() - xsize6, p.y() - ysize2 );
2759 points.setPoint( 2, p.x() + xsize6, p.y() - ysize2 );
2760 points.setPoint( 3, p.x() + xsize6, p.y() - ysize6 );
2761 points.setPoint( 4, p.x() + xsize2, p.y() - ysize6 );
2762 points.setPoint( 5, p.x() + xsize2, p.y() + ysize6 );
2763 points.setPoint( 6, p.x() + xsize6, p.y() + ysize6 );
2764 points.setPoint( 7, p.x() + xsize6, p.y() + ysize2 );
2765 points.setPoint( 8, p.x() - xsize6, p.y() + ysize2 );
2766 points.setPoint( 9, p.x() - xsize6, p.y() + ysize6 );
2767 points.setPoint(10, p.x() - xsize2, p.y() + ysize6 );
2768 points.setPoint(11, p.x() - xsize2, p.y() - ysize6 );
2769 }else if( ysize ){
2770 points.setPoint( 0, p.x() - ysize6, p.y() - ysize2 );
2771 points.setPoint( 1, p.x() + ysize6, p.y() - ysize2 );
2772 points.setPoint( 2, p.x() + ysize6, p.y() + ysize2 );
2773 points.setPoint( 3, p.x() - ysize6, p.y() + ysize2 );
2774 }else{
2775 points.setPoint( 0, p.x() - xsize2, p.y() - xsize6 );
2776 points.setPoint( 1, p.x() + xsize2, p.y() - xsize6 );
2777 points.setPoint( 2, p.x() + xsize2, p.y() + xsize6 );
2778 points.setPoint( 3, p.x() - xsize2, p.y() + xsize6 );
2779 }
2780 painter->drawPolygon( points );
2781 // Don't use points for drawing after this!
2782 points.translate( deltaX, deltaY );
2783 if( regions ){
2784 datReg = new KDChartDataRegion(
2785 dataset, value,
2786 chart, points );
2787 regions->append( datReg );
2788 }
2789 painter->setBrush( oldBrush );
2790 painter->setPen( oldPen );
2791 break;
2792 }
2793 case KDChartParams::LineMarkerFastCross: {
2794 const TQPen oldPen( painter->pen() );
2795 painter->setPen( color );
2796 painter->drawLine( TQPoint(p.x() - xysize2, p.y()),
2797 TQPoint(p.x() + xysize2, p.y()) );
2798 painter->drawLine( TQPoint(p.x(), p.y() - xysize2),
2799 TQPoint(p.x(), p.y() + xysize2) );
2800 TQRect rect( TQPoint( p.x() - 2, p.y() - 2 ),
2801 TQPoint( p.x() + 2, p.y() + 2 ) );
2802 // Don't use rect for drawing after this!
2803 rect.moveBy( deltaX, deltaY );
2804 if ( regions ){
2805 datReg =
2806 new KDChartDataRegion(
2807 dataset, value,
2808 chart, rect );
2809 regions->append( datReg );
2810 }
2811 painter->setPen( oldPen );
2812 break;
2813 }
2814 case KDChartParams::LineMarkerCircle:
2815 default: {
2816 const TQBrush oldBrush( painter->brush() );
2817 painter->setBrush( color );
2818 painter->drawEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
2819 if ( regions ) {
2820 TQPointArray points;
2821 points.makeEllipse( p.x() - xsize2, p.y() - ysize2, xsize, ysize );
2822 // Don't use points for drawing after this!
2823 points.translate( deltaX, deltaY );
2824 if( points.size() > 0 ){
2825 datReg = new KDChartDataRegion(
2826 dataset, value,
2827 chart, points );
2828 regions->append( datReg );
2829 }
2830 }
2831 painter->setBrush( oldBrush );
2832 }
2833 }
2834 return datReg;
2835}
2836
2837
2838void KDChartPainter::drawExtraLinesAndMarkers(
2839 KDChartPropertySet& propSet,
2840 const TQPen& defaultPen,
2841 const KDChartParams::LineMarkerStyle& defaultMarkerStyle,
2842 int myPointX,
2843 int myPointY,
2844 TQPainter* painter,
2845 const KDChartAxisParams* abscissaPara,
2846 const KDChartAxisParams* ordinatePara,
2847 const double areaWidthP1000,
2848 const double areaHeightP1000,
2849 bool bDrawInFront )
2850{
2851
2852 // we can safely call the following functions and ignore their
2853 // return values since they will touch the parameters' values
2854 // if the propSet *contains* corresponding own values only.
2855 int iDummy;
2856 uint extraLinesAlign = 0;
2857 if( propSet.hasOwnExtraLinesAlign( iDummy, extraLinesAlign )
2858 && ( extraLinesAlign
2859 & ( TQt::AlignLeft | TQt::AlignRight | TQt::AlignHCenter |
2860 TQt::AlignTop | TQt::AlignBottom | TQt::AlignVCenter ) ) ){
2861 bool extraLinesInFront = false;
2862 propSet.hasOwnExtraLinesInFront( iDummy, extraLinesInFront );
2863 if( bDrawInFront == extraLinesInFront ){
2864 const double areaSizeP1000 = TQMIN(areaWidthP1000, areaHeightP1000);
2865 int extraLinesLength = -20;
2866 int extraLinesWidth = defaultPen.width();
2867 TQColor extraLinesColor = defaultPen.color();
2868 TQt::PenStyle extraLinesStyle = defaultPen.style();
2869 uint extraMarkersAlign = 0;
2870 propSet.hasOwnExtraLinesLength( iDummy, extraLinesLength );
2871 propSet.hasOwnExtraLinesWidth( iDummy, extraLinesWidth );
2872 propSet.hasOwnExtraLinesColor( iDummy, extraLinesColor );
2873 propSet.hasOwnExtraLinesStyle( iDummy, extraLinesStyle );
2874 const int horiLenP2 = (0 > extraLinesLength)
2875 ? static_cast<int>(areaWidthP1000 * extraLinesLength) / 2
2876 : extraLinesLength / 2;
2877 const int vertLenP2 = (0 > extraLinesLength)
2878 ? static_cast<int>(areaHeightP1000 * extraLinesLength) / 2
2879 : extraLinesLength / 2;
2880 // draw the extra line(s)
2881 TQPoint pL( (TQt::AlignLeft == (extraLinesAlign & TQt::AlignLeft))
2882 ? 0
2883 : (TQt::AlignHCenter == (extraLinesAlign & TQt::AlignHCenter))
2884 ? myPointX - horiLenP2
2885 : myPointX,
2886 myPointY );
2887 TQPoint pR( (TQt::AlignRight == (extraLinesAlign & TQt::AlignRight))
2888 ? abscissaPara->axisTrueAreaRect().width()
2889 : (TQt::AlignHCenter == (extraLinesAlign & TQt::AlignHCenter))
2890 ? myPointX + horiLenP2
2891 : myPointX,
2892 myPointY );
2893 TQPoint pT( myPointX,
2894 (TQt::AlignTop == (extraLinesAlign & TQt::AlignTop))
2895 ? 0
2896 : (TQt::AlignVCenter == (extraLinesAlign & TQt::AlignVCenter))
2897 ? myPointY - vertLenP2
2898 : myPointY );
2899 TQPoint pB( myPointX,
2900 (TQt::AlignBottom == (extraLinesAlign & TQt::AlignBottom))
2901 ? ordinatePara->axisTrueAreaRect().height()
2902 : (TQt::AlignVCenter == (extraLinesAlign & TQt::AlignVCenter))
2903 ? myPointY + vertLenP2
2904 : myPointY );
2905 const TQPen extraPen( extraLinesColor,
2906 0 > extraLinesWidth
2907 ? static_cast < int > ( areaSizeP1000 * -extraLinesWidth )
2908 : extraLinesWidth,
2909 extraLinesStyle );
2910 const TQPen oldPen( painter->pen() );
2911 painter->setPen( extraPen );
2912 if( extraLinesAlign & ( TQt::AlignLeft | TQt::AlignRight | TQt::AlignHCenter ) )
2913 painter->drawLine( pL, pR );
2914 if( extraLinesAlign & ( TQt::AlignTop | TQt::AlignBottom | TQt::AlignVCenter ) )
2915 painter->drawLine( pT, pB );
2916 painter->setPen( oldPen );
2917 // draw the marker(s) of the extra line(s)
2918 propSet.hasOwnExtraMarkersAlign( iDummy, extraMarkersAlign );
2919 if( extraMarkersAlign
2920 & ( TQt::AlignLeft | TQt::AlignRight |
2921 TQt::AlignTop | TQt::AlignBottom ) ){
2922 TQSize extraMarkersSize = params()->lineMarkerSize();
2923 TQColor extraMarkersColor = extraLinesColor;
2924 int extraMarkersStyle = defaultMarkerStyle;
2925 propSet.hasOwnExtraMarkersSize( iDummy, extraMarkersSize );
2926 propSet.hasOwnExtraMarkersColor( iDummy, extraMarkersColor );
2927 propSet.hasOwnExtraMarkersStyle( iDummy, extraMarkersStyle );
2928 // draw the extra marker(s)
2929 int w = extraMarkersSize.width();
2930 int h = extraMarkersSize.height();
2931 if( w < 0 )
2932 w = static_cast < int > (w * -areaSizeP1000);
2933 if( h < 0 )
2934 h = static_cast < int > (h * -areaSizeP1000);
2935 if( extraMarkersAlign & TQt::AlignLeft )
2936 drawMarker( painter,
2937 params(),
2938 _areaWidthP1000, _areaHeightP1000,
2939 _dataRect.x(), _dataRect.y(),
2940 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
2941 extraMarkersColor,
2942 pL,
2943 0, 0, 0, 0,
2944 &w, &h,
2945 TQt::AlignCenter );
2946 if( extraMarkersAlign & TQt::AlignRight )
2947 drawMarker( painter,
2948 params(),
2949 _areaWidthP1000, _areaHeightP1000,
2950 _dataRect.x(), _dataRect.y(),
2951 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
2952 extraMarkersColor,
2953 pR,
2954 0, 0, 0, 0,
2955 &w, &h,
2956 TQt::AlignCenter );
2957 if( extraMarkersAlign & TQt::AlignTop )
2958 drawMarker( painter,
2959 params(),
2960 _areaWidthP1000, _areaHeightP1000,
2961 _dataRect.x(), _dataRect.y(),
2962 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
2963 extraMarkersColor,
2964 pT,
2965 0, 0, 0, 0,
2966 &w, &h,
2967 TQt::AlignCenter );
2968 if( extraMarkersAlign & TQt::AlignBottom )
2969 drawMarker( painter,
2970 params(),
2971 _areaWidthP1000, _areaHeightP1000,
2972 _dataRect.x(), _dataRect.y(),
2973 (KDChartParams::LineMarkerStyle)extraMarkersStyle,
2974 extraMarkersColor,
2975 pB,
2976 0, 0, 0, 0,
2977 &w, &h,
2978 TQt::AlignCenter );
2979 }
2980 }
2981 }
2982}
2983
2984
#define KDCHART_AXIS_LABELS_AUTO_DATETIME_FORMAT
Use this to specify that date/time format to be used for displaying the axis labels is to be determin...
Definition of a class for specifying and drawing custom boxes.
Definition of global enums.
Header for all common chart parameters.
#define KDCHART_MAX_AXES
Charts have up to 12 axes: up to two axes on both sides for X, Y and Z (if data is 3-dimensional).
Provides a table class holding all data values that are to be used in a chart.
#define KDCHART_NEG_INFINITE
Use special value KDCHART_NEG_INFINITE to indicate negative infinite values.
#define KDCHART_POS_INFINITE
Use special value KDCHART_POS_INFINITE to indicate positive infinite values.
Definition of a single entry-point to the charting engine for applications that wish to provide their...
Implements a chart painter that draws area charts.
access the chart axis parameters.
int axisAreaMax() const
Returns the axis area maximum width (or height, resp.).
TQRect axisTrueAreaRect() const
Returns the true axis area rectangle as calculated and drawn.
AxisAreaMode axisAreaMode() const
Returns the axis size mode configured in this params object.
static AxisPos basicAxisPos(uint pos)
enum KDChartAxisParams::AxisPos { AxisPosSTART = 0,
int axisTrueAreaSize() const
Returns the true axis area width (or height, resp.) as calculated and drawn.
TQFont axisLabelsFont() const
Returns the axis labels font.
int axisLabelsFontRelSize() const
Returns the axis labels relative font size.
TQString axisLabelsDateTimeFormat() const
Returns the format to be used for displaying abscissa axis TQDateTime item labels.
bool axisLabelsFontUseRelSize() const
Returns whether the fix axis font size is used.
AxisType axisType() const
int axisUseAvailableSpaceFrom() const
Returns the beginning offset of the space used by this axis in comparison to the available space that...
bool axisVisible() const
Returns weither the axis will be drawn or not.
int axisUseAvailableSpaceTo() const
Returns the ending offset of the space used by this axis in comparison to the available space that co...
int axisAreaMin() const
Returns the axis area minimum width (or height, resp.).
bool axisLabelsVisible() const
Returns whether the axis labels should be drawn.
A chart painter implementation that can paint Box&Whisker charts.
A chart painter implementation that can paint bar charts.
Class for specifying and drawing custom boxes.
KDChartEnums::PositionFlag anchorPosition() const
Returns the anchor position.
uint dataCol() const
Returns the column number of the KDChart data region that is to be used as anchor area.
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 setInternalFlagAnchorBeingCalculated(bool flag) const
Internal routine for recursion handling.
uint dataRow() const
Returns the row number of the KDChart data region that is to be used as anchor area.
uint data3rd() const
Returns the third dimensions number of the KDChart data region that is to be used as anchor area.
uint anchorArea() const
Returns the area to which the box is to be aligned.
TQRect trueRect(TQPainter *painter, TQPoint anchor, double areaWidthP1000, double areaHeightP1000) const
Return the actual rectangle which to draw box into.
bool anchorBeingCalculated() const
Internal routine for recursion handling.
The collection class used by KD Chart to store data region information.
static TQPoint positionFlagToPoint(const TQRect &rect, PositionFlag pos)
Returns the point representing a position of a rectangle.
PositionFlag
The general position flag to specify a point of an area, for example this could be the anchor point w...
A chart painter implementation that can paint HiLo charts.
A chart painter implementation that can paint line charts.
An abstract base class that defines an interface for classes that implement chart drawing.
virtual void paintAxes(TQPainter *painter, KDChartTableDataBase *data)
Paints the axes for the chart.
virtual ~KDChartPainter()
Destructor.
virtual void setupGeometry(TQPainter *painter, KDChartTableDataBase *data, const TQRect &rect)
This method will be called whenever any parameters that affect geometry have been changed.
virtual void paintHeaderFooter(TQPainter *painter, KDChartTableDataBase *data)
Paints the header and footers for the chart.
virtual void paintAreaWithGap(TQPainter *painter, TQRect rect, const KDChartParams::KDChartFrameSettings &settings)
Paints an area frame.
static void drawMarker(TQPainter *painter, int style, const TQColor &color, const TQPoint &p, const TQSize &size, uint align=TQt::AlignCenter)
Draws the marker for one data point according to the specified style, color, size.
virtual TQString fallbackLegendText(uint dataset) const
This method provides a fallback legend text for the specified dataset, if there was no other way to d...
virtual TQRect calculateAreaRect(bool &allCustomBoxes, uint area, uint dataRow, uint dataCol, uint data3rd, KDChartDataRegionList *regions) const
Calculated the rectangle covered by an area.
KDChartPainter(KDChartParams *)
Constructor.
virtual void paintArea(TQPainter *painter, uint area, KDChartDataRegionList *regions=0, uint dataRow=0, uint dataCol=0, uint data3rd=0)
Paints an area frame.
virtual void paintCustomBoxes(TQPainter *painter, KDChartDataRegionList *regions)
Paints all custom boxes.
virtual void paintDataValues(TQPainter *painter, KDChartTableDataBase *data, KDChartDataRegionList *regions)
Paints the data value texts near the data representations.
virtual TQPoint calculateAnchor(const KDChartCustomBox &box, KDChartDataRegionList *regions=0) const
Calculated the top left corner of a custom box.
virtual void paintLegend(TQPainter *painter, KDChartTableDataBase *data)
Paints the legend for the chart.
virtual uint numLegendFallbackTexts(KDChartTableDataBase *data) const
This methods returns the number of elements to be shown in the legend in case fallback texts are used...
virtual void paint(TQPainter *painter, KDChartTableDataBase *data, bool paintFirst, bool paintLast, KDChartDataRegionList *regions=0, const TQRect *rect=0, bool mustCalculateGeometry=true)
Paints the chart for which this chart painter is configured on a TQPainter.
static KDChartPainter * create(KDChartParams *params, bool make2nd=false)
Creates an object of a concrete subclass of KDChartPainter that KDChart::paint() (and consequently,...
static void unregisterPainter(const TQString &painterName)
Unregisters a user-defined painter implementation.
static void registerPainter(const TQString &painterName, KDChartPainter *painter)
Registers a user-defined painter implementation which is identified by a string.
Stores the frame settings for one of the chart areas:
int innerGapX() const
Return the X-distance between the frame and the inner area.
const KDFrame & frame() const
Return the KDFrame object used for drawing this areas frame.
int innerGapY() const
Return the Y-distance between the frame and the inner area.
Bundles the display parameters of a chart.
TQColor dataColor(uint dataset) const
Returns the color for a dataset.
bool dataValuesAutoColor(uint chart) const
Returns whether the font to be used for printing the data values texts shall have automatically calcu...
TQSize lineMarkerSize() const
Returns the sizes of line markers.
TQColor dataValuesColor(uint chart) const
Returns the colour of the font to be used for printing the data values.
int globalLeadingLeft() const
Return the distance between the chart and the left border of the painter area.
LegendPosition legendPosition() const
Returns where the legend will be shown.
ChartType chartType() const
Returns the chart type configured in this params object.
void setAxisArea(const uint n, const TQRect &areaRect)
Specifies the true axis area rectangle.
const KDChartFrameSettings * frameSettings(uint area, bool &bFound, int *pIterIdx=0) const
Return the frame settings of one of the chart areas.
const KDChartFrameSettings * nextFrameSettings(bool &bFound, int *pIterIdx) const
Return the next frame settings specified for the same area type as the frame that was retrieved by pr...
const KDChartCustomBox * customBox(uint box) const
Retrieve a const pointer to a custom box from the list.
TQColor legendTitleTextColor() const
Returns the color in which the legend title is drawn.
int legendTitleFontRelSize() const
Returns the relative legend title font size.
TQt::Orientation legendOrientation() const
Returns how the legend will be printed.
LineMarkerStyle
The available line marker styles.
int numValues() const
Returns how many of the values should be shown.
TQString headerFooterText(uint pos) const
Returns the text that is displayed in the header (or footer, resp.) section specified by pos.
TQString legendText(uint dataset) const
Returns the manually specified legend text for a given dataset.
int globalLeadingBottom() const
Return the distance between the chart and the lower border of the painter area.
bool allowOverlappingDataValueTexts() const
Returns whether a data value text may be drawn even if it's region intersects with another data value...
ChartType
The chart type.
ChartType additionalChartType() const
Returns the additional chart type configured in this params object.
int globalLeadingRight() const
Return the distance between the chart and the right border of the painter area.
const KDChartAxisParams & axisParams(uint n) const
Returns the parameters that are currently defined for axis n.
int globalLeadingTop() const
Return the distance between the chart and the upper border of the painter area.
const TQRect & headerFooterRect(uint pos) const
TQFont legendFont() const
Returns the font in which the legend texts are drawn.
uint maxCustomBoxIdx() const
Retrieve the biggest custom boxes ID used.
uint legendSpacing() const
Returns how much space in pixels there is between the legend and the data display.
BarChartSubType barChartSubType() const
Returns the bar chart subtype.
A chart painter implementation that can paint pie charts.
A chart painter implementation that can paint polar charts.
Property settings of a single KDChart data cell.
A chart painter implementation that can paint pie charts.
KD Chart's build-in table data for an easy way of storing data values.
virtual uint usedCols() const
Returns the number of cols in the table that actually contain data.
virtual bool cellCoord(uint _row, uint _col, TQVariant &_value, int coordinate=1) const =0
Returns one of the coordinate data value(s) stored in a cell.
virtual uint usedRows() const
Returns the number of rows in the table that actually contain data.
static bool painterToDrawRect(TQPainter *painter, TQRect &drawRect)
Calculates the drawing area from a given TQPainter.
Definition KDChart.cpp:122
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