kchart

KDChartBarPainter.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 "KDChartBarPainter.h"
30#include <KDChartParams.h>
31
32#include <tqpainter.h>
33
34#include <stdlib.h>
35
48 KDChartAxesPainter( params )
49{
50 // This constructor intentionally left blank so far; we cannot setup the
51 // geometry yet since we do not know the size of the painter.
52}
53
54
59{
60 // intentionally left blank
61}
62
63bool KDChartBarPainter::isNormalMode() const
64{
65
66 return KDChartParams::BarNormal == params()->barChartSubType();
67}
68
69int KDChartBarPainter::clipShiftUp( bool normalMode, double areaWidthP1000 ) const
70{
71
72 const bool bThreeDBars = params()->threeDBars() || (KDChartParams::BarMultiRows == params()->barChartSubType());
73 return ( normalMode && !bThreeDBars )
74 ? static_cast < int > ( areaWidthP1000 * 16.0 )
75 : 0;
76}
77
78
79void KDChartBarPainter::initMyPainter( TQPainter* painter )
80{
81 _myPainter = painter;
82 _painterDX = 0.0;
83 _painterDY = 0.0;
84}
85
86void KDChartBarPainter::shiftMyPainter( double dx, double dy )
87{
88 if( dx != 0.0 || dy != 0.0 ){
89 _myPainter->translate(dx, dy);
90 _painterDX += dx;
91 _painterDY += dy;
92 }
93}
94
95void KDChartBarPainter::shiftMyPainterBack()
96{
97 if( _painterDX != 0.0 || _painterDY != 0.0 ){
98 _myPainter->translate(-_painterDX, -_painterDY);
99 _painterDX = 0.0;
100 _painterDY = 0.0;
101 }
102}
103
104
105void KDChartBarPainter::calculateXFront1_2( bool bNormalMode, bool bIsVeryFirstBar, bool bIsFirstDataset, bool _bThreeDBars,
106 double xpos, double valueBlockGap, double datasetGap, double frontBarWidth,
107 int& frontX1, int& frontX2, int& prevFrontX2 ){
108
109 if( _bThreeDBars || bIsVeryFirstBar || !bNormalMode )
110 frontX1 = static_cast<int>( xpos );
111 else if( bIsFirstDataset )
112 frontX1 = prevFrontX2 + static_cast <int> ( valueBlockGap ) + 1;
113 else
114 frontX1 = prevFrontX2 + static_cast < int > ( datasetGap ) + 1;
115
116 // Note: frontX2 is calculated by using xpos but NOT by using frontX1.
117 // So we make sure that (a) the gaps between all bars of one dataset
118 // are exactly the same size, and that (b) the bars are automatically
119 // adjusted in their width: to match their very position within the abscissa range.
120 // Adjusting will result in them being ONE pixel wider sometimes.
121 frontX2 = static_cast < int > ( xpos + frontBarWidth );
122 prevFrontX2 = frontX2;
123}
124
125
126TQPointArray rectToPointArray( const TQRect& r )
127{
128 TQPointArray a(4);
129 a.putPoints( 0, 4, r.left(),r.top(), r.right(),r.top(), r.right(),r.bottom(), r.left(),r.bottom() );
130 return a;
131}
132
133
134void KDChartBarPainter::specificPaintData( TQPainter* painter,
135 const TQRect& ourClipRect,
137 KDChartDataRegionList* regions,
138 const KDChartAxisParams* ordinatePara,
139 bool bNormalMode,
140 uint chart,
141 double logWidth,
142 double areaWidthP1000,
143 double logHeight,
144 double axisYOffset,
145 double minColumnValue,
146 double maxColumnValue,
147 double columnValueDistance,
148 uint chartDatasetStart,
149 uint chartDatasetEnd,
150 uint datasetStart,
151 uint datasetEnd )
152{
153 /****************Pending Michel***********************
154 *Rectangles are painted in the following order: *
155 *front , right side, top. *
156 *Store the painted rectangles in order to paint *
157 *them in relation to each other for more precision. *
158 ****************************************************/
159 TQRect frontRectPositive,frontRectNegative,
160 rightRectPositive, rightRectNegative,
161 excessRectPositive,excessRectNegative;
162
163 _areaP1000 = areaWidthP1000;
164
165
166
167 if( !data ) return;
168 // tqDebug("datasetStart: %i datasetEnd: %i", datasetStart, datasetEnd);
169 const TQPen defaultOutlinePen( params()->outlineDataColor(),
170 params()->outlineDataLineWidth(),
171 params()->outlineDataLineStyle() );
172 abscissaInfos ai;
173 ai.bCenterThePoints = true;
174 calculateAbscissaInfos( *params(), *data,
175 datasetStart, datasetEnd,
176 logWidth, _dataRect,
177 ai );
178
179 const TQRect devRect( painter->window() );
180
181 initMyPainter( painter );
182
183 const bool ordinateIsLogarithmic
184 = KDChartAxisParams::AxisCalcLogarithmic == ordinatePara->axisCalcMode();
185
186 const bool bMultiRows = KDChartParams::BarMultiRows == params()->barChartSubType();
187 _bThreeDBars = params()->threeDBars() || bMultiRows;
188 int numChartDataEntryDatasets = 0;
189 uint myLastDataEntryDataset = 0;
190 for( uint iD = chartDatasetStart; iD <= chartDatasetEnd; ++iD ){
191 if( params()->chartSourceMode( iD ) == KDChartParams::DataEntry ){
192 ++numChartDataEntryDatasets;
193 myLastDataEntryDataset = iD;
194 }
195 }
196
197 const bool bHadClipping = painter->hasClipping();
198
199 //this allow the height/size of the bar to be painted fully
200 if( bMultiRows ) {
201 painter->setClipping( false );
202 }
203 // Number of columns in one dataset: If -1, use all values,
204 // otherwise use the specified number of values.
205 int numValues = 0;
206 if ( params()->numValues() != -1 )
207 numValues = params()->numValues();
208 else
209 numValues = data->usedCols();
210
211 double datasetGap = bMultiRows
212 ? 0.0
213 : params()->datasetGap()
214 * ( params()->datasetGapIsRelative()
215 ? areaWidthP1000
216 : 1.0 );
217 double valueBlockGap = bMultiRows
218 ? 0.0
219 : params()->valueBlockGap()
220 * ( params()->valueBlockGapIsRelative()
221 ? areaWidthP1000
222 : 1.0 );
223
224 // This is the same for all three bar types except for multi-bar Surface charts.
225 double spaceBetweenValueBlocks = bMultiRows
226 ? 0.0
227 : static_cast<int>( valueBlockGap ) * numValues;
228
229 // Set some geometry values that apply to bar charts only
230 double totalNumberOfBars = 0.0;
231 double spaceBetweenDatasets = 0.0;
232 switch ( params()->barChartSubType() ) {
233 case KDChartParams::BarNormal: {
234 totalNumberOfBars = numChartDataEntryDatasets * numValues;
235 spaceBetweenDatasets = datasetGap
236 * ( totalNumberOfBars - numValues );
237 break;
238 }
239 case KDChartParams::BarStacked:
240 case KDChartParams::BarPercent:
241 case KDChartParams::BarMultiRows:
242 totalNumberOfBars = numValues;
243 spaceBetweenDatasets = 0; // always 0 when stacked/percent/multi-rows
244 break;
245 default:
246 tqFatal( "Unsupported bar chart type" );
247 };
248
249 double barWidth = 0.0;
250 if( params()->barWidth() == KDCHART_AUTO_SIZE ) {
251
252 //Default auto calc. to optimize when many bars datasetGap == blockGap/2 == barWidth/2
253 //unless valueBlockGap or datasetGap are different from default values == users value
254 barWidth = logWidth / totalNumberOfBars;
255 do {
256 barWidth -= 0.1;
257 params()->valueBlockGap() != 24 ? spaceBetweenValueBlocks = params()->valueBlockGap() * numValues
258 : spaceBetweenValueBlocks = ( barWidth/2 ) * numValues;
259 if ( spaceBetweenDatasets != 0 )
260 params()->datasetGap()!= 6 ? spaceBetweenDatasets = params()->datasetGap() * ( totalNumberOfBars - numValues )
261 : spaceBetweenDatasets = ( barWidth/4 ) * ( totalNumberOfBars - numValues );
262 }
263 while ( barWidth*totalNumberOfBars + spaceBetweenValueBlocks + spaceBetweenDatasets > logWidth );
264
265 valueBlockGap = ( spaceBetweenValueBlocks )/ numValues;
266 if ( spaceBetweenDatasets != 0 )
267 datasetGap = spaceBetweenDatasets / ( totalNumberOfBars - numValues );
268
269 barWidth = (logWidth - ( valueBlockGap * numValues ) - ( datasetGap * ( totalNumberOfBars - numValues ) ) ) / totalNumberOfBars;
270 ;
271
272 /* Debug space available
273 tqDebug ( " logWidth %f" , logWidth );
274 tqDebug ( "compare value %f", barWidth*totalNumberOfBars + spaceBetweenValueBlocks + datasetGap * ( totalNumberOfBars - numValues ) );
275 */
276 } else if( 0 > params()->barWidth() )
277 barWidth = params()->barWidth() * -areaWidthP1000;
278 else
279 barWidth = params()->barWidth();
280
281 //sideBarWidth: pre-calculate in order to have a reference
282 //we will correct according to the available space later.
283 //This in order to center the labels in relation to the front width
284 //when painting 3DBars
285 double sideBarWidth = _bThreeDBars
286 ? ( barWidth - barWidth / (1.0 + params()->cosThreeDBarAngle()) ) *
287 params()->threeDBarDepth()
288 : 0.0;
289
290 const double frontBarWidth = _bThreeDBars && !bMultiRows
291 ? barWidth - sideBarWidth
292 : barWidth;
293
294 //correct the width for the side of the bar
295 double totalThreeDBarWidth = totalNumberOfBars*barWidth + sideBarWidth;
296 double totalSpaceOccupied = totalThreeDBarWidth + spaceBetweenDatasets + spaceBetweenValueBlocks;
297 if ( logWidth < totalSpaceOccupied) {
298 sideBarWidth -= (totalSpaceOccupied /*+ spaceBetweenDatasets + spaceBetweenValueBlocks*/ - logWidth)/totalNumberOfBars;
299
300 //tqDebug ( "logWidth %f", logWidth );
301 //tqDebug ( "totalSpaceOccupied %f", totalSpaceOccupied );
302 }
303
304 const double sideBarHeight = sideBarWidth;
305
306
307 double pixelsPerUnit = 0.0;
308
309 if ( params()->barChartSubType() != KDChartParams::BarPercent ) // not used for percent
310 pixelsPerUnit = logHeight / ( columnValueDistance ? columnValueDistance : 10 );
311
312 //tqDebug("\nordinatePara->trueAxisLow() = %f", ordinatePara->trueAxisLow());
313 //tqDebug( "ordinatePara->trueAxisHigh() = %f", ordinatePara->trueAxisHigh());
314 //tqDebug( "sideBarHeight = %f", sideBarHeight);
315 //tqDebug( "pixelsPerUnit = %f", pixelsPerUnit);
316
317 double zeroXAxisI;
318 if ( params()->barChartSubType() == KDChartParams::BarPercent ) {
319 if ( minColumnValue == 0.0 )
320 zeroXAxisI = 0.0;
321 else if ( maxColumnValue == 0.0 )
322 zeroXAxisI = logHeight - sideBarHeight;
323 else
324 zeroXAxisI = ( logHeight - sideBarHeight ) / 2.0;
325
326 } else {
327 zeroXAxisI = logHeight
328 - ordinatePara->axisZeroLineStartY()
329 + _dataRect.y();
330 }
331
332 double shiftUpperBars = (params()->barChartSubType() != KDChartParams::BarPercent)
333 && (ordinatePara->axisTrueLineWidth() % 2)
334 ? 1.0
335 : 0.0;
336
337 // Initializing drawing positions
338 double yposPositivesStart = logHeight;
339 double yposNegativesStart = logHeight;
340 if( params()->barChartSubType() == KDChartParams::BarPercent ){
341 yposPositivesStart += axisYOffset;
342 yposNegativesStart += axisYOffset;
343 }
344
345 for ( int iPaintExtraLinesOrTheData = 0;
346 iPaintExtraLinesOrTheData < 3;
347 ++iPaintExtraLinesOrTheData )
348 {
349
350 const bool bDrawExtraLines = (1 != iPaintExtraLinesOrTheData);
351 const bool bDrawExtraLinesInFront = (2 == iPaintExtraLinesOrTheData);
352
353 double xpos = 0.0;
354
355 if ( _bThreeDBars && !bMultiRows )
356 xpos = 0.0 + (barWidth/2) + (valueBlockGap/2) - (frontBarWidth/2);
357 else
358 xpos = 0.0 + (valueBlockGap / 2.0);
359
360 double yposPositives = yposPositivesStart;
361 double yposNegatives = yposNegativesStart;
362
363 /* Pending Michel: no need for this anymore */
364 //double totalThreeDBarWidth = bMultiRows
365 //? barWidth + sideBarWidth
366 // : barWidth;
367
368 double nShiftX = bMultiRows
369 ? sideBarWidth
370 : 0.0;
371 double nShiftY = bMultiRows
372 ? sideBarHeight
373 : 0.0;
374
375 double valueTotal = 0.0; // valueTotal is used for percent bars only
376
377 // iterate over all columns: item1, item2, item3 ...
378 int prevFrontX2 = 0;
379 bool bIsVeryFirstBar = true;
380 for ( int value = 0; value < numValues; ++value ) {
381
382 bool bFirstValidValueUnknown = true;
383 uint firstValidValue = 0;
384 uint lastValidPositiveValue = 0;
385 double maxValueInThisColumn = 0.0, minValueInThisColumn = 0.0;
386 if ( params()->barChartSubType() == KDChartParams::BarStacked ||
387 params()->barChartSubType() == KDChartParams::BarPercent) {
388 valueTotal = 0.0;
389 // iterate over datasets of this axis only:
390 for ( uint dataset = datasetStart;
391 dataset <= datasetEnd;
392 ++dataset ) {
393
394 TQVariant vVal;
395 if( data->cellCoord( dataset, value, vVal, 1 )
396 && params()->chartSourceMode( dataset ) == KDChartParams::DataEntry
397 && TQVariant::Double == vVal.type() ){
398
399 const double cellValue
400 = ordinateIsLogarithmic
401 ? log10( vVal.toDouble() )
402 : vVal.toDouble();
403 //tqDebug("value %u dataset %u logHeight %f", value,dataset,logHeight);
404
405 if( bFirstValidValueUnknown ){
406 firstValidValue = dataset;
407 bFirstValidValueUnknown = false;
408 }
409 if( 0.0 <= cellValue )
410 lastValidPositiveValue = dataset;
411
412 maxValueInThisColumn = TQMAX( maxValueInThisColumn, cellValue );
413 minValueInThisColumn = TQMIN( minValueInThisColumn, cellValue );
414 if( params()->barChartSubType() == KDChartParams::BarPercent /*||
415 params()->barChartSubType() == KDChartParams::BarStacked*/ )
416 valueTotal += cellValue;
417 }
418 }
419 }
420
421 //tqDebug("shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );");
422 shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );
423
424 // iterate over all datasets of this chart:
425 // (but draw only the bars of this axis)
426 bool bIsFirstDataset = true;
427 for ( uint dataset = bMultiRows
428 ? chartDatasetEnd
429 : chartDatasetStart;
430 dataset >= chartDatasetStart && dataset <= chartDatasetEnd;
431 bMultiRows
432 ? --dataset
433 : ++dataset ) {
434 //tqDebug("value %u dataset %u logHeight %f", value,dataset,logHeight);
435
436 const bool bDataEntrySourceMode
437 = (params()->chartSourceMode( dataset ) == KDChartParams::DataEntry);
438
439
440 TQVariant coord1;
441 TQVariant coord2;
442 int propID;
443 if( data->cellContent( dataset, value, coord1, coord2, propID )
444 && TQVariant::Double == coord1.type() ){
445
446 const double cellValue
447 = ordinateIsLogarithmic
448 ? log10( coord1.toDouble() )
449 : coord1.toDouble();
450 //tqDebug("b");
451 // there is a numeric value
452
453 double barHeight;
454
455 if ( params()->barChartSubType() == KDChartParams::BarPercent )
456 barHeight = ( cellValue / valueTotal ) * fabs(zeroXAxisI - logHeight );
457 else {
458 barHeight = pixelsPerUnit * cellValue;
459
460 if( 0.0 <= barHeight )
461 //barHeight = TQMAX(0.0, barHeight - sideBarHeight);
462 barHeight = barHeight - sideBarHeight;
463 else
464 barHeight -= sideBarHeight;
465 }
466
467 // This little adjustment avoids a crash when trying
468 // to retrieve the bounding rect of a zero size region...
469 if( 0 == barHeight || 0.0 == barHeight ) {
470
471 barHeight = 1.0; // makes sense to have a min size anyway
472 }
473
474 // draw only the bars belonging to the axis
475 // which we are processing currently
476 if( dataset >= datasetStart && dataset <= datasetEnd ) {
477 //tqDebug("b2");
478
479 // calculate Abscissa axis value, if there are X coordinates
480 // ---------------------------------------------------------
481 bool skipMe = false;
482 if( ai.bCellsHaveSeveralCoordinates ){
483 skipMe = !calculateAbscissaAxisValue( coord2,
484 ai, 0, xpos );
485 // adjust bar position to have it horizontally centered to the point
486 if( ai.bAbscissaHasTrueAxisDtValues &&
487 TQVariant::DateTime == coord2.type() )
488 xpos -= frontBarWidth / 2.0;
489 }
490
491 if( !skipMe ){
492 // Configure colors
493 TQColor myBarColor( params()->dataColor( dataset ) );
494 TQColor myShadow1Color( params()->dataShadow1Color( dataset ) );
495 TQColor myShadow2Color( params()->dataShadow2Color( dataset ) );
496
497 // Get default values for extra lines and their markers
499 defaultMarkerStyle = params()->lineMarkerStyle( dataset );
500 const TQPen defaultPen( params()->lineColor().isValid()
501 ? params()->lineColor()
502 : params()->dataColor( dataset ),
503 params()->lineWidth(),
504 params()->lineStyle( dataset ) );
505
506 // --------------------------------------------------------
507 // determine any 'extra' properties assigned to this cell
508 // by traversing the property set chain (if necessary)
509 // --------------------------------------------------------
510 KDChartPropertySet propSet;
511 bool bCellPropertiesFound =
512 params()->calculateProperties( propID,
513 propSet );
514 bool bShowThisBar = bDataEntrySourceMode;
515 if( bCellPropertiesFound ){
516 if( bShowThisBar && !bDrawExtraLines ){
517 int iDummy;
518 if( propSet.hasOwnShowBar( iDummy, bShowThisBar ) ){
519 // NOP
520 }
521 if( propSet.hasOwnBarColor( iDummy, myBarColor ) ){
522 // adjust the shadow colors
523 params()->calculateShadowColors( myBarColor,
524 myShadow1Color,
525 myShadow2Color );
526 }
527 }
528 }
529
530 if( !bDrawExtraLines || bCellPropertiesFound ){
531
532 //TQRegion* region = 0;
533 KDChartDataRegion::PointArrayList * pointArrayList = 0;
534 if( bDataEntrySourceMode && !bDrawExtraLines ){
535 painter->setPen( defaultOutlinePen );
536 if ( myBarColor.isValid() )
537 painter->setBrush( myBarColor );
538 else
539 painter->setBrush( NoBrush );
540
541 // Prepare region for detection of mouse clicks
542 // and for finding anchor positions of data value texts
543 if ( regions )
544 pointArrayList = new KDChartDataRegion::PointArrayList();
545 }
546
547 // Start drawing
548 int frontX1 = 0;
549 int frontX2 = 0;
550 bool tooLow = false;
551 bool tooHigh = false;
552
553 if ( cellValue < 0 || cellValue < minColumnValue ) {
554 double maxValueYPos = maxColumnValue * pixelsPerUnit;
555 double yZero = yposNegatives - zeroXAxisI - sideBarHeight;
556
557 tooLow = (barHeight - yZero + logHeight + axisYOffset) < 0;
558
559 /*we need to handle those values in case we have a negative view*/
560 if ( cellValue <= 0 && cellValue > maxColumnValue && minColumnValue < 0 && maxColumnValue < 0 )
561 tooLow = true;
562
563 if ( tooLow && ( bNormalMode || bMultiRows) ) {
564 double delta = 0.0125 * logHeight;
565 double height = -1*(-1.0 * (yZero + sideBarHeight) - 2 * delta);
566 double height1 = height - 3.0 * delta;
567
568 int yArrowGap = static_cast < int > ( 2.5 * delta );
569 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
570 xpos, valueBlockGap, datasetGap, frontBarWidth,
571 frontX1, frontX2, prevFrontX2 );
572
573 const int xm = static_cast < int > ( (frontX1 + frontX2) / 2.0 );
574 TQRect rect( ourClipRect );
575
576 rect.setHeight( static_cast<int>( rect.height() + 3.0 * delta ) );
577 painter->setClipRect( rect );
578
579 //Pending Michel: Make sure the point of the arrow is always at the same distance
580 //from the X axis reference to the point of the arrow.
581 int arrowXAxisGap;
582 TQPoint arrowTop( xm,static_cast<int>( yZero + height1 + 2 * yArrowGap) );
583
584 if ( arrowTop.y()== yposNegatives )
585 arrowXAxisGap = -2;
586 else
587 arrowXAxisGap = static_cast <int> (yposNegatives - arrowTop.y() - 2);
588
589 if( bDrawExtraLines ){
590 drawExtraLinesAndMarkers(
591 propSet,
592 defaultPen,
593 defaultMarkerStyle,
594 xm, static_cast<int>( yZero + height1 ),
595 painter,
596 ai.abscissaPara,
597 ordinatePara,
598 areaWidthP1000,
599 logHeight/1000.0,
600 bDrawExtraLinesInFront );
601 }else if( bShowThisBar ){
602 if( params()->drawSolidExcessArrows() ) {
603
604 /* PENDING Michel:
605 * Here we have two situations.
606 * The value is too low because over the Min negative value
607 * or it is not within the configured view.
608 */
609 // Draw solid excess arrows negatives
610
611 TQPointArray points( 5 );
612 /*this works in a positive view -> 200 500*/
613 points.setPoint( 0, frontX1, cellValue < 0 ?
614 static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
615 static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
616 points.setPoint( 1, frontX2, cellValue < 0 ?
617 static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
618 static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap );
619 points.setPoint( 2, frontX2, cellValue < 0 ?
620 static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
621 static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
622 points.setPoint( 3, xm, cellValue < 0 ?
623 static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap:
624 static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap);
625 points.setPoint( 4, frontX1, cellValue < 0 ?
626 static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
627 static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
628
629 /* 0 between start and end -> -500 500*/
630 if ( minColumnValue < 0 && maxColumnValue > 0 ) {
631 points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
632 points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
633 }
634
635 /* negative view -> -200 -500 */
636 if ( minColumnValue < 0 && maxColumnValue < 0 ) {
637 /*value negative or zero > maxColumnValue*/
638 if ( cellValue > maxColumnValue ) {
639 // the view is under Yaxis 0 level
640 // we need to show a symbol for the bars which are over the Yaxis.
641 // calculate the coordinate and direction for the arrow.
642 // arrow downward for negative values and upward for positives value
643 int diffArrowBase = points.point(2).y() - points.point(3).y();
644 double maxValueYPos = maxColumnValue * pixelsPerUnit;
645 double minValueYPos = minColumnValue * pixelsPerUnit;
646 double adjustedArrow = (cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase + 2:
647 minValueYPos - maxValueYPos - diffArrowBase + 1);
648 points.setPoint( 0, frontX1, points.point(0).y() + static_cast <int> (adjustedArrow));
649 points.setPoint( 1, frontX2, points.point(1).y() + static_cast <int> (adjustedArrow ));
650 points.setPoint( 2, frontX2, points.point(2).y() + static_cast <int> (adjustedArrow));
651 points.setPoint( 3, xm, points.point(3).y() + static_cast <int> (adjustedArrow));
652 points.setPoint( 4, frontX1, points.point(4).y() + static_cast <int> (adjustedArrow));
653 }
654 /*value < mincolumn value*/
655 if ( cellValue < minColumnValue ) {
656 points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos ) );
657 points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos ) );
658 }
659
660 }
661
662 /*Pending Michel: case setbarWidth */
663 //adjust the painting in case we have a user given Width allow it
664 //to be larger than the auto calculated width in case we want to overlap
665
666 if ( params()->userWidth() != 0 ) {
667 int userwidth = 0;
668 if ( params()->userWidth() < 0 )
669 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
670 else
671 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
672 //if ( userwidth < frontBarWidth ) {
673 TQRect tmpRect ( points.point(0), points.point(2));
674 points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
675 points.point(0).y());
676 points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
677 points.point(1).y());
678 points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
679 points.point(2).y());
680 points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
681 points.point(4).y());
682 //}
683 }
684 if ( bMultiRows )painter->setClipping( false );
685 painter->drawPolygon( points );
686
687 //correct the y position: displaying position for the value label
688 TQPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
689 TQPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
690
691 //store the front rectangle
692 excessRectNegative.setTopLeft(tpLeft);
693 excessRectNegative.setTopRight(tpRight);
694 excessRectNegative.setBottomRight(points.point(1));
695 excessRectNegative.setBottomLeft(points.point(0));
696
697 // Don't use points for drawing after this!
698 if ( pointArrayList ) {
699 if ( cellValue < 0 ) {
700 //correction for labels vertical position
701 int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
702 points.setPoint( 4 ,tpLeft );
703 points.setPoint( 2, tpRight );
704 if ( cellValue < maxColumnValue )
705 points.translate( _dataRect.x(), -_dataRect.y() - size );
706 else
707 points.translate( _dataRect.x(), _dataRect.y() );
708 } else
709 points.translate( _dataRect.x(), _dataRect.y() );
710
711 pointArrayList->append( points );
712 }
713
714 } else {
715 // Draw split excess arrows negatives
716
717 /* PENDING Michel:
718 * Here we have two situations.
719 * The value is too low because over the Min negative value
720 * The value is not within the configured view..
721 */
722 TQPointArray points( 5 );
723 /*this works in a positive view -> 200 500*/
724 points.setPoint( 0, frontX1, cellValue < 0 ?
725 static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
726 static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
727 points.setPoint( 1, frontX2, cellValue < 0 ?
728 static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
729 static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
730 points.setPoint( 2, frontX2, cellValue < 0 ?
731 static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
732 static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
733 points.setPoint( 3, xm, cellValue < 0 ?
734 static_cast<int>( yZero + height1) + arrowXAxisGap:
735 static_cast<int>(yZero+height1 - 3.0*delta)+(2 * yArrowGap)+ arrowXAxisGap);
736 points.setPoint( 4, frontX1, cellValue < 0 ?
737 static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
738 static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
739
740 /* 0 between start and end -> -500 500*/
741 if ( minColumnValue < 0 && maxColumnValue > 0 ) {
742 points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
743 points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
744 }
745
746 /* negative view -> -200 -500 */
747 if ( minColumnValue < 0 && maxColumnValue < 0 ) {
748 /*value negative or zero > maxColumnValue*/
749 if ( cellValue > maxColumnValue ) {
750 // the view is under Yaxis 0 level
751 // we need to show a symbol for the bars which are over the Yaxis.
752 // calculate the coordinate and direction for the arrow.
753 // arrow downward for negative values and upward for positives value
754 int diffArrowBase = points.point(2).y() - points.point(3).y();
755 double maxValueYPos = maxColumnValue * pixelsPerUnit;
756
757 points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
758 points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
759 points.setPoint( 2, frontX2, static_cast <int> ( yZero - maxValueYPos) );
760 points.setPoint( 3, xm, static_cast <int> ( yZero - maxValueYPos - diffArrowBase ) );
761 points.setPoint( 4, frontX1, static_cast <int> ( yZero - maxValueYPos) );
762 }
763 /*value < mincolumn value*/
764 if ( cellValue < minColumnValue ) {
765 points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
766 points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
767 }
768 }
769
770 //Pending Michel adjust the painting in case we have a user given Width
771 //allow it to be larger than the auto calculated width in case we want
772 //to overlap
773 if ( params()->userWidth() != 0 ) {
774 int userwidth = 0;
775 if ( params()->userWidth() < 0 )
776 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
777 else
778 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
779 //if ( userwidth < frontBarWidth ) {
780 TQRect tmpRect ( points.point(0), points.point(2));
781 points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
782 points.point(0).y());
783 points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
784 points.point(1).y());
785 points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
786 points.point(2).y());
787 points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
788 points.point(4).y());
789 }
790 if ( bMultiRows )painter->setClipping( false );
791 painter->drawPolygon( points );
792
793 //correct the y position: displaying position for the value label
794 TQPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
795 TQPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
796
797 //store the excess front rectangle
798 excessRectNegative.setTopLeft(tpLeft);
799 excessRectNegative.setTopRight(tpRight);
800 excessRectNegative.setBottomRight(points.point(1));
801 excessRectNegative.setBottomLeft(points.point(0));
802
803 // Don't use points for drawing after this!
804 if ( pointArrayList ) {
805 if ( cellValue < 0 ) {
806 //calculate correction for labels vertical position
807 int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
808 if ( cellValue < maxColumnValue )
809 points.translate( _dataRect.x(), -_dataRect.y() - size );
810 else
811 points.translate( _dataRect.x(), _dataRect.y() + ( 2 * yArrowGap ) );
812 } else
813 points.translate( _dataRect.x(), -_dataRect.y() );
814
815 pointArrayList->append( points );
816 }
817
818 TQPointArray points2( 6 );
819 points2.setPoint( 0, frontX1, cellValue < 0 ?
820 static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap:
821 static_cast<int>(yZero + height1) + arrowXAxisGap);
822 points2.setPoint( 1, xm, cellValue < 0 ?
823 static_cast<int>(yZero + height1) + arrowXAxisGap:
824 static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap);
825 points2.setPoint( 2, frontX2, cellValue < 0 ?
826 static_cast<int>(yZero + height1 - 3.0 * delta) + arrowXAxisGap:
827 static_cast<int>(yZero + height1) + arrowXAxisGap);
828 points2.setPoint( 3, frontX2, cellValue < 0 ?
829 static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap :
830 static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap);
831 points2.setPoint( 4, xm, cellValue < 0 ?
832 static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap:
833 static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap);
834 points2.setPoint( 5, frontX1, cellValue < 0 ?
835 static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap:
836 static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap);
837 points2.translate( 0, yArrowGap );
838
839 if ( minColumnValue < 0 && maxColumnValue < 0 && cellValue > maxColumnValue ) {
840 // the view is under Yaxis 0 level
841 // we need to show a symbol for the bars which are over the Yaxis.
842 // calculate the coordinate and direction for the arrow.
843 // arrow downward for negative values and upward for positives value
844 int diffArrowBase = points.point(2).y() - points.point(3).y();
845 double maxValueYPos = maxColumnValue * pixelsPerUnit;
846 double minValueYPos = minColumnValue * pixelsPerUnit;
847 double adjustedArrow = cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase:
848 minValueYPos - maxValueYPos - diffArrowBase + 1;
849
850 points2.setPoint( 0, frontX1, points2.point(0).y()
851 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
852 points2.setPoint( 1, xm, points2.point(1).y()
853 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
854 points2.setPoint( 2, frontX2, points2.point(2).y()
855 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
856 points2.setPoint( 3, frontX2, points2.point(3).y()
857 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
858 points2.setPoint( 4, xm, points2.point(4).y()
859 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
860 points2.setPoint( 5, frontX1, points2.point(5).y()
861 + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
862 }
863
864 //Pending Michel adjust the painting in case we have a user given Width
865 //allow it to be larger than the auto calculated width in case we want
866 //to overlap
867 if ( params()->userWidth() != 0 ) {
868 int userwidth = 0;
869 if ( params()->userWidth() < 0 )
870 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
871 else
872 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
873 //if ( userwidth < frontBarWidth ) {
874
875 points2.setPoint(0, excessRectNegative.topLeft().x(),points2.point(0).y());
876 points2.setPoint(2, excessRectNegative.topRight().x(),points2.point(2).y());
877 points2.setPoint(3, excessRectNegative.topRight().x(),points2.point(3).y());
878 points2.setPoint(5, excessRectNegative.topLeft().x(),points2.point(5).y());
879 }
880
881 painter->drawPolygon( points2 );
882
883 /*
884 NOTE: We do NOT want to store the region here, but
885 we use the front rectangle above in order to display the
886 data value labels inside the front rectangle.
887 Disadvantage: clicking onto these excess arrows, will not
888 result in a signal being sent, because KDChartWidget will
889 not notice, that the user has clicked onto the bar.
890 That's a minor drawback, compared to the gain of being
891 able to position the labels correctly.
892 */
893
894 if ( cellValue < 0 )
895 points2.translate( 0, yArrowGap );
896 else
897 points2.translate( 0, -yArrowGap );
898
899 painter->drawPolygon( points2 );
900
901
902 /*
903 NOTE: We do NOT want to store the region here
904 (see comment above)
905 */
906 }
907 }
908 painter->setClipRect( ourClipRect );
909 } /*if (tooLow && bNormalMode)*/
910 else {
911 //
912 // old code (sometimes not touching the grid):
913 //TQRect rec( xpos, yZero, frontBarWidth, -barHeight );
914 //painter->drawRect( rec );
915 //
916
917 int pt1Y = static_cast < int > ( yZero - barHeight /*- sideBarsHeight*/ );
918
919 /*
920 if ( cellValue != 0 ) {
921 pt1Y = static_cast <int> (cellValue * pixelsPerUnit * -2);
922 tqDebug( "value %s",TQString::number(static_cast <int> (cellValue)).latin1());
923 tqDebug( "pt1Y %s", TQString::number(static_cast <int> (cellValue * pixelsPerUnit * -2)).latin1());
924 }
925 else
926 pt1Y = static_cast < int > ( yZero - barHeight);
927 */
928 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
929 xpos, valueBlockGap, datasetGap, frontBarWidth,
930 frontX1, frontX2, prevFrontX2 );
931
932 TQPoint pt1( frontX1, pt1Y );
933 TQPoint pt2( frontX2,
934 static_cast < int > ( yZero + sideBarHeight) );
935
936 if( 0.0 > maxColumnValue ){
937 pt2.setY(pt2.y() - static_cast < int > (pixelsPerUnit * maxColumnValue));
938 }
939 if( pt2.y() < pt1Y ) {
940 pt1.setY( pt2.y() );
941 pt2.setY( pt1Y );
942 }
943 if( pt2.x() < frontX1 ) {
944 pt1.setX( frontX2 );
945 pt2.setX( frontX1 );
946 }
947 if( bDrawExtraLines ){
948 int y = pt2.y();
949 if( _bThreeDBars )
950 y -= static_cast < int > ( sideBarHeight );
951 drawExtraLinesAndMarkers(
952 propSet,
953 defaultPen,
954 defaultMarkerStyle,
955 (frontX1+frontX2)/2, y,
956 painter,
957 ai.abscissaPara,
958 ordinatePara,
959 areaWidthP1000,
960 logHeight/1000.0,
961 bDrawExtraLinesInFront );
962 }else if( bShowThisBar ){
963
964 TQSize siz( pt2.x() - pt1.x(),
965 pt2.y() - pt1.y() );
966 TQRect rect( pt1, siz );
967
968 if( 1.5 > frontBarWidth ){
969 TQPen oldPen( painter->pen() );
970 painter->setPen( TQPen(painter->brush().color(), 0) );
971 painter->drawLine(pt1, TQPoint(pt1.x(),pt2.y()));
972 painter->setPen( oldPen );
973 }else{
974 // store the front rect negative
975 if ( tooLow || cellValue < minColumnValue) {
976 frontRectNegative.setTopLeft(excessRectNegative.bottomLeft());
977 frontRectNegative.setTopRight(excessRectNegative.bottomRight());
978 frontRectNegative.setBottomRight(excessRectNegative.topRight());
979 frontRectNegative.setBottomLeft(excessRectNegative.topLeft());
980
981 } else {
982 frontRectNegative.setTopLeft(rect.topLeft());
983 frontRectNegative.setTopRight(rect.topRight());
984 frontRectNegative.setBottomRight(rect.bottomRight());
985 frontRectNegative.setBottomLeft(rect.bottomLeft());
986
987 if ( cellValue == 0 && params()->barChartSubType() == KDChartParams::BarPercent)
988 rect.setTop( rect.bottom());
989 }
990
991 //debug lines and points
992 /*
993 painter->drawLine( rect.topLeft(), rect.topRight());
994 painter->drawLine( rect.topRight(), rect.bottomRight());
995 painter->drawLine( rect.bottomRight(), rect.bottomLeft());
996 painter->drawLine( rect.bottomLeft(), rect.topLeft());
997
998 painter->drawText( frontRectNegative.topLeft(), "0f");
999 painter->drawText( frontRectNegative.topRight(), "1f");
1000 painter->drawText( frontRectNegative.bottomRight(), "2f");
1001 painter->drawText( frontRectNegative.bottomLeft(), "3f");
1002 */
1003
1004 //Pending Michel adjust the painting in case we have a user given Width
1005 //and it is not larger than the auto calculated width
1006
1007 if ( params()->userWidth() != 0 ) {
1008 int userwidth = 0;
1009 if ( params()->userWidth() < 0 )
1010 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
1011 else
1012 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
1013 //if ( userwidth < frontBarWidth ) {
1014 rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
1015 rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
1016 rect.setWidth( static_cast <int> (userwidth) );
1017 frontRectNegative.setLeft( tooLow || cellValue < minColumnValue ?
1018 static_cast <int> (excessRectNegative.center().x() - (userwidth/2)):rect.left());
1019 frontRectNegative.setRight( tooHigh ? static_cast <int> (excessRectNegative.center().x() + (userwidth/2)):rect.right());
1020 }
1021 //drawing the front size negative values
1022 if ( cellValue != 0 && params()->barChartSubType() != KDChartParams::BarPercent) {
1023 painter->setClipping( false );
1024 painter->drawRect( rect );
1025 }
1026 }
1027 // Don't use rect for drawing after this!
1028 if ( pointArrayList ) {
1029 rect.moveBy( _dataRect.x(), _dataRect.y() );
1030 pointArrayList->append( rectToPointArray( rect ) );
1031 }
1032 }
1033 }
1034 } else {
1035 //
1036 // Positive values:
1037 //
1038 /*Pending Michel: all values under the min value are handled as negative*/
1039
1040 double maxValueYPos = maxColumnValue * pixelsPerUnit;
1041 double minValueYPos = minColumnValue * pixelsPerUnit;
1042 double minDataValueYPos = maxValueYPos - minValueYPos;
1043 double yZero = yposPositives - zeroXAxisI;
1044 //tqDebug( "yposPositives %f - zeroXAxisI %f = %f" , yposPositives, zeroXAxisI, yZero );
1045 //tqDebug( "yZero %s", TQString::number( yZero ).latin1());
1046 //tqDebug( "minDataValueYPos = %s", TQString::number( minDataValueYPos).latin1());
1047 //tqDebug( "positive value %s", TQString::number( cellValue).latin1());
1048 //Pending Michel: draw the default split excess arrows
1049 //when the front top of the 3d chart reach the max Y value
1050
1051 if(!_bThreeDBars)
1052 tooHigh = ( barHeight > maxValueYPos*1.001 ) || ( cellValue < minColumnValue );
1053 else {
1054 //calculate the Y position for the top front line
1055 //if it is over the max height pos - tooHigh becomes true
1056 if ( params()->barChartSubType()!= KDChartParams::BarStacked ) {
1057 int dataValueYPos = static_cast <int>( ( cellValue * pixelsPerUnit ) );
1058 tooHigh = dataValueYPos > maxValueYPos;
1059 } else {
1060 tooHigh = maxValueInThisColumn > maxColumnValue;
1061 }
1062 }
1063
1064 if ( tooHigh && bNormalMode ||
1065 tooHigh && params()->barChartSubType()== KDChartParams::BarStacked
1066 || tooHigh && bMultiRows ) {
1067
1068 double delta = -0.0125 * logHeight;
1069 double height = -1.0 * yZero
1070 - 2.0 * delta;
1071 double height1 = height + -3.0 * delta;
1072
1073 int yArrowGap = static_cast < int > ( 2.5 * delta );
1074 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
1075 xpos, valueBlockGap, datasetGap, frontBarWidth,
1076 frontX1, frontX2, prevFrontX2 );
1077
1078 const int xm = static_cast < int > ( ( frontX1 + frontX2 ) / 2.0 );
1079 TQRect rect( ourClipRect );
1080
1081 rect.setTop( static_cast<int>( rect.top() + 3 * delta ) );
1082 rect.setHeight( static_cast<int>( rect.height() - 3 * delta ) );
1083 painter->setClipRect( rect );
1084
1085 if( bDrawExtraLines ){
1086 drawExtraLinesAndMarkers(
1087 propSet,
1088 defaultPen,
1089 defaultMarkerStyle,
1090 xm, static_cast<int>( yZero + height1 ),
1091 painter,
1092 ai.abscissaPara,
1093 ordinatePara,
1094 areaWidthP1000,
1095 logHeight/1000.0,
1096 bDrawExtraLinesInFront );
1097 }else if( bShowThisBar ){
1098 if( params()->drawSolidExcessArrows() ) {
1099 // Draw solid excess arrows
1100 TQPointArray points( 5 );
1101 /*this works for positive config and 0 include config*/
1102 points.setPoint( 0, frontX1,
1103 (minDataValueYPos < static_cast <int> (yZero))?
1104 static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
1105 points.setPoint( 1, frontX2,
1106 (minDataValueYPos < static_cast <int> (yZero))?
1107 static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
1108 points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta )
1109 + 2 * yArrowGap );
1110 points.setPoint( 3, xm, static_cast<int>( yZero + height1 )
1111 + 2 * yArrowGap );
1112 points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta )
1113 + 2 * yArrowGap );
1114
1115 /*case where start and end value are negatives */
1116 if ( cellValue > maxColumnValue && 0 >= maxColumnValue ) {
1117 points.setPoint( 0, frontX1,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
1118 points.setPoint( 1, frontX2,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
1119 }
1120
1121 //Pending Michel adjust the painting in case we have a user given Width
1122 //allow it to be larger than the auto calculated width in case we want
1123 //to overlap
1124 if ( params()->userWidth() != 0 ) {
1125 int userwidth = 0;
1126 if ( params()->userWidth() < 0 )
1127 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
1128 else
1129 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
1130 //if ( userwidth < frontBarWidth ) {
1131 TQRect tmpRect ( points.point(0), points.point(2));
1132 points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
1133 points.point(0).y());
1134 points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
1135 points.point(1).y());
1136 points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
1137 points.point(2).y());
1138 points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
1139 points.point(4).y());
1140 //}
1141 }
1142 if ( params()->barChartSubType() != KDChartParams::BarStacked ||
1143 params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
1144 //drawing a single front in case it is too high
1145 painter->setClipping( false );
1146 painter->drawPolygon( points );
1147 }
1148 //correct the y position: displaying position for the value label
1149 TQPoint tpLeft (points.point(4).x(), static_cast <int> (points.point(4).y() - yArrowGap));
1150 TQPoint tpRight(points.point(2).x(), static_cast <int> (points.point(2).y() - yArrowGap));
1151
1152 //debugging points
1153 /*
1154 painter->drawText( points.point(0), "p0");
1155 painter->drawText( points.point(1), "p1");
1156 painter->drawText( points.point(2), "p2");
1157 painter->drawText( points.point(3), "p3");
1158 */
1159 //store the front rectangle
1160 excessRectPositive.setTopLeft(tpLeft);
1161 excessRectPositive.setTopRight(tpRight);
1162 excessRectPositive.setBottomRight(points.point(1));
1163 excessRectPositive.setBottomLeft(points.point(0));
1164
1165 // Don't use points for drawing after this!
1166 if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
1167 points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() - yArrowGap );
1168 pointArrayList->append( points );
1169 } else if ( params()->barChartSubType() == KDChartParams::BarStacked ) {
1170 if ( dataset != datasetEnd ) {
1171 points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
1172 pointArrayList->append( points );
1173 } else {
1174 //adjust the display of the value label under Y max value level
1175 points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
1176 pointArrayList->append( points );
1177 }
1178 }
1179 } else {
1180
1181 // Draw split excess arrows (default)
1182 /* PENDING Michel:
1183 * Here we have two situations.
1184 * The value is too high because over the Max positive value
1185 * or it is not within the configured view.
1186 */
1187 TQPointArray points( 5 );
1188 /*this works for positive config and 0 include config*/
1189 points.setPoint( 0, frontX1,
1190 (minDataValueYPos < static_cast <int> (yZero))?
1191 static_cast <int> (minDataValueYPos - 1) : static_cast <int>(yZero));
1192 points.setPoint( 1, frontX2,
1193 (minDataValueYPos < static_cast <int> (yZero))?
1194 static_cast<int> ( minDataValueYPos - 1) : static_cast <int>(yZero));
1195 points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
1196 points.setPoint( 3, xm, static_cast<int>( yZero + height1 ) );
1197 points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
1198
1199 /*case where start and end value are negatives */
1200 if ( cellValue > maxColumnValue && 0 >= maxColumnValue || cellValue == 0) {
1201 points.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ));
1202 points.setPoint( 1, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ));
1203 }
1204
1205 //Pending Michel adjust the painting in case we have a user given Width
1206 //allow it to be larger than the auto calculated width in case we want
1207 //to overlap
1208 if ( params()->userWidth() != 0 ) {
1209 int userwidth = 0;
1210 if ( params()->userWidth() < 0 )
1211 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
1212 else
1213 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
1214 //if ( userwidth < frontBarWidth ) {
1215 TQRect tmpRect ( points.point(0), points.point(2));
1216 points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
1217 points.point(0).y());
1218 points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
1219 points.point(1).y());
1220 points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
1221 points.point(2).y());
1222 points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
1223 points.point(4).y());
1224 //}
1225 }
1226 if ( params()->barChartSubType() != KDChartParams::BarStacked ||
1227 params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
1228 painter->setClipping( false );
1229 painter->drawPolygon( points );
1230 }
1231
1232 //store the front rectangle
1233 excessRectPositive.setTopLeft(points.point(4));
1234 excessRectPositive.setTopRight(points.point(2));
1235 excessRectPositive.setBottomRight(points.point(1));
1236 excessRectPositive.setBottomLeft(points.point(0));
1237
1238 // Don't use points for drawing after this!
1239 if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
1240 points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
1241 pointArrayList->append( points );
1242 } else if ( params()->barChartSubType() == KDChartParams::BarStacked ) {
1243 if ( dataset != datasetEnd ) {
1244 points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
1245 pointArrayList->append( points );
1246 } else {
1247 //adjust the display of the value label under Y max value level
1248 points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
1249 pointArrayList->append( points );
1250 }
1251 }
1252
1253 TQPointArray points2( 6 );
1254 points2.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
1255 points2.setPoint( 1, xm, static_cast<int>( yZero + height1 ) );
1256 points2.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
1257 points2.setPoint( 3, frontX2, static_cast<int>( yZero + height1 - 3.75 * delta ) );
1258 points2.setPoint( 4, xm, static_cast<int>( yZero + height1 - 0.75 * delta ) );
1259 points2.setPoint( 5, frontX1, static_cast<int>( yZero + height1 - 3.75 * delta ) );
1260 points2.translate( 0, yArrowGap );
1261
1262 //Pending Michel adjust the painting in case we have a user given Width
1263 //allow it to be larger than the auto calculated width in case we want
1264 //to overlap
1265 if ( params()->userWidth() != 0 ) {
1266 int userwidth = 0;
1267 if ( params()->userWidth() < 0 )
1268 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
1269 else
1270 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
1271 //if ( userwidth < frontBarWidth ) {
1272 points2.setPoint(0, excessRectPositive.topLeft().x(),points2.point(0).y());
1273 points2.setPoint(2, excessRectPositive.topRight().x(),points2.point(2).y());
1274 points2.setPoint(3, excessRectPositive.topRight().x(),points2.point(3).y());
1275 points2.setPoint(5, excessRectPositive.topLeft().x(),points2.point(5).y());
1276 //}
1277 }
1278
1279 painter->drawPolygon( points2 );
1280 /*
1281 NOTE: We do NOT want to store the region here, but
1282 we use the front rectangle above in order to display the
1283 data value labels inside the front rectangle.
1284 Disadvantage: clicking onto these excess arrows, will not
1285 result in a signal being sent, because KDChartWidget will
1286 not notice, that the user has clicked onto the bar.
1287 That's a minor drawback, compared to the gain of being
1288 able to position the labels correctly.
1289 */
1290 points2.translate( 0, yArrowGap );
1291 painter->drawPolygon( points2 );
1292 /*
1293 NOTE: We do NOT want to store the region here
1294 (see comment above)
1295 */
1296 } // draw split excess arrow
1297 } //if( bShowThisBar )
1298
1299 painter->setClipRect( ourClipRect );
1300 } // not tooLow && bNormalMode )
1301 else {
1302 //bool fromBottom = bNormalMode && !_bThreeDBars;
1303 double y0 = yposPositives - zeroXAxisI;
1304
1305 int pt1Y = static_cast < int > ( y0 - barHeight - sideBarHeight);
1306
1307 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
1308 xpos, valueBlockGap, datasetGap, frontBarWidth,
1309 frontX1, frontX2, prevFrontX2 );
1310
1311 TQPoint pt1( frontX1, pt1Y );
1312 TQPoint pt2( frontX2,
1313 static_cast < int > ( y0 + shiftUpperBars ) );
1314
1315 if( 0.0 < minColumnValue )
1316 pt2.setY(pt2.y() - static_cast < int > ( pixelsPerUnit * minColumnValue ));
1317
1318 if( pt2.y() < pt1Y ) {
1319 pt1.setY( pt2.y() );
1320 pt2.setY( pt1Y );
1321 }
1322 if( pt2.x() < frontX1 ) {
1323 pt1.setX( frontX2 );
1324 pt2.setX( frontX1 );
1325 }
1326 if( bDrawExtraLines ){
1327 int y = pt1.y();
1328 if( _bThreeDBars )
1329 y -= static_cast < int > ( sideBarHeight );
1330
1331 drawExtraLinesAndMarkers(
1332 propSet,
1333 defaultPen,
1334 defaultMarkerStyle,
1335 (frontX1+frontX2)/2, y,
1336 painter,
1337 ai.abscissaPara,
1338 ordinatePara,
1339 areaWidthP1000,
1340 logHeight/1000.0,
1341 bDrawExtraLinesInFront );
1342 }else if( bShowThisBar ){
1343
1344 TQSize siz( pt2.x() - pt1.x(),
1345 pt2.y() - pt1.y());
1346
1347 TQRect rect( pt1, siz );
1348
1349 //adjust display for the 3d percent bars - last dataset.
1350 if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue != 0)
1351 rect.setTop( rect.top() + static_cast <int> (sideBarHeight) - 1);
1352
1353 // store the front rect
1354 if( tooHigh ) {
1355 frontRectPositive.setTopLeft(excessRectPositive.topLeft());
1356 frontRectPositive.setTopRight(excessRectPositive.topRight());
1357 frontRectPositive.setBottomRight(excessRectPositive.bottomRight());
1358 frontRectPositive.setBottomLeft(excessRectPositive.bottomLeft());
1359 } else {
1360 frontRectPositive.setTopLeft(rect.topLeft());
1361 frontRectPositive.setTopRight(rect.topRight());
1362 frontRectPositive.setBottomRight(rect.bottomRight());
1363 frontRectPositive.setBottomLeft(rect.bottomLeft());
1364 if( _bThreeDBars && cellValue == 0 )
1365 frontRectNegative = frontRectPositive;
1366 }
1367
1368 if( 1.5 > frontBarWidth ){
1369 //tqDebug("1.5 > frontBarWidth ");
1370 TQPen oldPen( painter->pen() );
1371 painter->setPen( TQPen(painter->brush().color(), 0) );
1372 painter->drawLine(pt1, TQPoint(pt1.x(),pt2.y()));
1373 painter->setPen( oldPen );
1374 }else{
1375 //debugging points and lines
1376 /*
1377 painter->drawText( rect.topLeft(), TQString::number(cellValue).latin1());
1378 painter->drawText( rect.topRight(), "1f");
1379 painter->drawText( rect.bottomRight(), "2f");
1380 painter->drawText( rect.bottomLeft(), "3f");
1381 painter->drawLine( rect.topLeft(), rect.topRight());
1382 painter->drawLine( rect.topRight(), rect.bottomRight());
1383 painter->drawLine( rect.bottomRight(), rect.bottomLeft());
1384 painter->drawLine( rect.bottomLeft(), rect.topLeft());
1385 */
1386
1387 //Pending Michel adjust the painting in case we have a user given Width
1388 //allow it to be larger than the auto calculated width in case we want
1389 //to overlap
1390 if ( params()->userWidth() != 0 ) {
1391 int userwidth = 0;
1392 if ( params()->userWidth() < 0 )
1393 userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
1394 else
1395 userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
1396 //if ( userwidth < frontBarWidth ) {
1397 rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
1398 rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
1399 rect.setWidth( static_cast <int> (userwidth) );
1400 //adjust the front rect
1401 frontRectPositive.setLeft( tooHigh ? static_cast <int> (excessRectPositive.center().x() - (userwidth/2)):rect.left());
1402 frontRectPositive.setRight( tooHigh ? static_cast <int> (excessRectPositive.center().x() + (userwidth/2)):rect.right());
1403 }
1404
1405 // drawing the front side
1406 if (!tooHigh && !tooLow || params()->barChartSubType() == KDChartParams::BarPercent ) {
1407 if ( bMultiRows )
1408 painter->setClipping( false );
1409 else
1410 painter->setClipping( true );
1411 painter->drawRect( rect );
1412 }
1413 // Don't use rect for drawing after this
1414 if ( pointArrayList ) {
1415 rect.moveBy( _dataRect.x(), _dataRect.y());
1416 pointArrayList->append( rectToPointArray( rect ) );
1417 }
1418 }
1419 } // bShowThisBar
1420 } // positive values
1421 }
1422 if ( bShowThisBar && _bThreeDBars && !bDrawExtraLines ) {
1423 //Pending Michel: no need to use that anymore
1424 //const int maxY = 2*devRect.height();
1425 TQPointArray points( 4 );
1426 if (cellValue <= 0 || cellValue < minColumnValue) {
1427 if ( tooLow || cellValue < minColumnValue ) {
1428 points.setPoint(0, excessRectNegative.topRight());
1429 points.setPoint(1, excessRectNegative.topRight().x() + static_cast<int>(sideBarHeight),
1430 excessRectNegative.top() - static_cast<int>(sideBarHeight));
1431 points.setPoint(2, excessRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
1432 excessRectNegative.bottom() - static_cast<int>(sideBarHeight));
1433 points.setPoint(3, excessRectNegative.bottomRight());
1434 } else {
1435 points.setPoint( 0, frontRectNegative.bottomRight());
1436 points.setPoint( 1, frontRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
1437 frontRectNegative.bottom() - static_cast<int>(sideBarHeight) );
1438 points.setPoint(2, frontRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
1439 frontRectNegative.top() - static_cast<int>(sideBarHeight));
1440 points.setPoint(3, frontRectNegative.topRight() );
1441 }
1442
1443 rightRectNegative.setTopLeft( points.point(0));
1444 rightRectNegative.setTopRight( points.point(2));
1445 rightRectNegative.setBottomRight(points.point(1));
1446 rightRectNegative.setBottomLeft(points.point(3));
1447
1448 } else {
1449 // Pending Michel
1450 // Make sure to align the right side top and bottom points
1451 // to the front side points
1452 if ( tooHigh ) {
1453 points.setPoint(0, excessRectPositive.topRight());
1454 points.setPoint(1, excessRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
1455 excessRectPositive.top() - static_cast <int> (sideBarHeight) );
1456 points.setPoint(2, excessRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
1457 excessRectPositive.bottom() - static_cast <int> (sideBarHeight));
1458 points.setPoint(3, excessRectPositive.bottomRight());
1459 } else {
1460 points.setPoint(0, frontRectPositive.topRight());
1461 points.setPoint(1, frontRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
1462 frontRectPositive.top() - static_cast<int>(sideBarHeight));
1463 points.setPoint(2, frontRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
1464 frontRectPositive.bottom() - static_cast<int>(sideBarHeight));
1465 points.setPoint(3, frontRectPositive.bottomRight());
1466 }
1467 //register the right rect
1468 rightRectPositive.setTopLeft( points.point(0));
1469 rightRectPositive.setTopRight( points.point(1));
1470 rightRectPositive.setBottomLeft( points.point(3));
1471 rightRectPositive.setBottomRight(points.point(2));
1472 }
1473
1474 if ( myShadow2Color.isValid() )
1475 painter->setBrush( TQBrush( myShadow2Color, params()->shadowPattern() ) );
1476 else
1477 painter->setBrush( NoBrush );
1478
1479 //debug points and lines
1480 /*
1481 painter->drawText( points.point(0), "0r");
1482 painter->drawText( points.point(1), "1r");
1483 painter->drawText( points.point(2), "2r");
1484 painter->drawText( points.point(3), "3r");
1485
1486 painter->drawLine( points.point(0), points.point(1));
1487 painter->drawLine( points.point(1), points.point(2));
1488 painter->drawLine( points.point(2), points.point(3));
1489 painter->drawLine( points.point(3), points.point(0));
1490 */
1491
1492 //drawing the right side
1493 if( (!tooHigh && !tooLow) || (tooHigh && cellValue <= 0 ) ) {
1494 if (( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarPercent ) ||
1495 ( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarStacked ) ||
1496 ( cellValue != 0 && bNormalMode ||
1497 cellValue != 0 && bMultiRows)) {
1498 painter->setClipping( false );
1499 painter->drawPolygon( points );
1500 }
1501 }
1502
1503 // Dont override the region stored in case of excess values or barPercent this in order to display
1504 // the value labels closer to the corner of the front bar.
1505 if ( pointArrayList && !tooHigh && !tooLow && params()->barChartSubType() != KDChartParams::BarPercent ) {
1506 TQPointArray points2cpy( points.copy() );
1507 //tqDebug("g2");
1508 points2cpy.translate( _dataRect.x(), _dataRect.y());
1509 //tqDebug("g3");
1510 pointArrayList->append( points2cpy );
1511 //tqDebug("g4");
1512 }
1513
1514 // drawing the top, but only for the topmost piece for stacked and percent
1515 if ( bNormalMode || bMultiRows ||
1516 // For stacked and percent bars, there are three ways to determine
1517 // the top:
1518 // 1. all values are negative: the top is the one in the first dataset
1519 ( maxValueInThisColumn <= 0.0 && dataset == firstValidValue ) ||
1520 // 2. all values are positive: the top is the one in the last dataset
1521 ( minValueInThisColumn >= 0.0 && dataset == lastValidPositiveValue ) ||
1522 // 3. some values are positive, some negative:
1523 // the top is the one in the last positive
1524 // dataset value
1525 ( dataset == lastValidPositiveValue ) ) {
1526 if (cellValue <= 0 || cellValue < minColumnValue) {
1527 if ( tooLow ) {
1528 points.setPoint(0,excessRectNegative.bottomLeft());
1529 points.setPoint(1,excessRectNegative.topLeft().x() + static_cast <int> (sideBarHeight),
1530 excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
1531 points.setPoint(2,excessRectNegative.bottomRight().x() + static_cast <int> (sideBarHeight),
1532 excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
1533 points.setPoint(3,excessRectNegative.bottomRight());
1534 }else {
1535 // Align the top to the front and the right side
1536 points.setPoint(0,frontRectNegative.topLeft() );
1537 points.setPoint(1,frontRectNegative.topLeft().x() + static_cast <int> (sideBarHeight), rightRectNegative.top());
1538 points.setPoint(2,rightRectNegative.topRight() );
1539 points.setPoint(3,rightRectNegative.topRight().x() - static_cast <int> (sideBarHeight),
1540 frontRectNegative.topRight().y() );
1541 //make sure the top rect color is the right one - barStacked - Noll values
1542 if ( (params()->barChartSubType() == KDChartParams::BarStacked && cellValue == 0 && maxValueInThisColumn != 0 ) )
1543 points.translate(0, maxValueInThisColumn <= 0?-(static_cast <int> (1*pixelsPerUnit) + 1):
1544 -static_cast<int>(maxValueInThisColumn*pixelsPerUnit));
1545
1546 if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue == 0 ) {
1547 if ( dataset == datasetEnd && maxValueInThisColumn != 0)
1548 points.translate(0, -static_cast<int>( logHeight - sideBarHeight ));
1549 else if ( maxValueInThisColumn == 0)
1550 points.translate(0, static_cast <int> (logHeight + (sideBarHeight - sideBarWidth)));
1551 }
1552 }
1553 } else {
1554 if ( tooHigh ) {
1555 points.setPoint(0, excessRectPositive.topLeft());
1556 points.setPoint(1, excessRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
1557 excessRectPositive.top() - static_cast <int> (sideBarHeight) );
1558 points.setPoint(2, excessRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
1559 excessRectPositive.top() - static_cast <int> (sideBarHeight));
1560 points.setPoint(3, excessRectPositive.topRight());
1561 } else {
1562 // Pending Michel
1563 // Align the top to the front and the right side
1564 points.setPoint(0, frontRectPositive.topLeft());
1565 points.setPoint(1, frontRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
1566 rightRectPositive.top() );
1567 points.setPoint(2, rightRectPositive.topRight());
1568 points.setPoint(3, rightRectPositive.topRight().x() - static_cast <int> (sideBarHeight),
1569 frontRectPositive.topRight().y());
1570 }
1571 }
1572
1573 if (cellValue < 0.0 && maxValueInThisColumn < 0)
1574 painter->setBrush( bMultiRows ? myBarColor : black );
1575 else
1576 painter->setBrush( TQBrush( myShadow1Color, params()->shadowPattern() ) );
1577
1578 if ( !myShadow1Color.isValid() )
1579 painter->setBrush( NoBrush ); // override prev. setting
1580 // debug points and lines
1581 /*
1582 painter->drawText( points.point(0), "0t");
1583 painter->drawText( points.point(1), "1t");
1584 painter->drawText( points.point(2), "2t");
1585 painter->drawText( points.point(3), "3t");
1586
1587 painter->drawLine( points.point(0), points.point(1) );
1588 painter->drawLine( points.point(1),points.point(2) );
1589 painter->drawLine( points.point(2),points.point(3) );
1590 painter->drawLine( points.point(3),points.point(0) );
1591 */
1592
1593 // drawing the top side
1594 if (!tooHigh && !tooLow || (tooHigh && cellValue <= 0) )
1595 painter->drawPolygon( points );
1596
1597 // dont override the region stored in case of excess values.
1598 if (pointArrayList && !tooHigh && !tooLow
1599 && params()->barChartSubType() != KDChartParams::BarPercent
1600 && params()->barChartSubType() != KDChartParams::BarStacked) {
1601 points.translate( _dataRect.x(), _dataRect.y());
1602 pointArrayList->append( points );
1603 }
1604 }
1605 }//if ( _bThreeDBars )
1606
1607 if( regions && pointArrayList && ! pointArrayList->empty() ) {
1608 if( bShowThisBar && !bDrawExtraLines ){
1609 KDChartDataRegion * region;
1610 if( _bThreeDBars ){
1611 region = new KDChartDataRegion( dataset, value, chart,
1612 pointArrayList, true );
1613 } else {
1614 // just store a rectangle if NOT in 3-D bar mode
1615 region = new KDChartDataRegion( dataset, value, chart,
1616 pointArrayList->first().boundingRect() );
1617 delete pointArrayList;
1618 }
1619 /*tqDebug("KDChartDataRegion stored! x: %i y: %i w: %i h: %i",
1620 region->rect().x(),region->rect().y(),
1621 region->rect().width(),region->rect().height());*/
1622 regions->append( region );
1623 } else {
1624 delete pointArrayList;
1625 }
1626 }
1627 }// if( !bDrawExtraLines || bCellPropertiesFound )
1628 }// if( !skipMe )
1629 }else{
1630 // Do not paint a bar, but update the position
1631 // variable: to find the exact x1 position for
1632 // the next bar that will be drawn.
1633 int iDummy1, iDummy2;
1634 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
1635 xpos, valueBlockGap, datasetGap, frontBarWidth,
1636 iDummy1, iDummy2, prevFrontX2 );
1637 }// if( dataset >= datasetStart && dataset <= datasetEnd )
1638
1639 // Vertical advancement in stacked or percent only if there was a value
1640 // Pending Michel add sideBarHeight in case we are in 3D mode but not for Percent
1641 // where we need to display the top rect but cant resize the YAxis.
1642 if ( params()->barChartSubType() == KDChartParams::BarStacked ||
1643 params()->barChartSubType() == KDChartParams::BarPercent )
1644 if ( /*barHeight*/ cellValue < 0 )
1645 (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposNegatives -= sideBarHeight + barHeight:
1646 yposNegatives -= barHeight;
1647 else
1648 (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposPositives -= sideBarHeight + barHeight:
1649 yposPositives -= barHeight;
1650
1651 } else {
1652 // Do not paint a bar, but update the position
1653 // variable: to find the exact x1 position for
1654 // the next bar that will be drawn.
1655 int iDummy1, iDummy2;
1656 calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
1657 xpos, valueBlockGap, datasetGap, frontBarWidth,
1658 iDummy1, iDummy2, prevFrontX2 );
1659 }
1660
1661
1662 // advance only if the next dataset has DataEntry mode
1663 bool bAdvanceToNextValue =
1664 ( bMultiRows ? (dataset == chartDatasetStart) : (dataset == chartDatasetEnd)
1665 || ( params()->chartSourceMode( bMultiRows ? dataset-1 : dataset+1 )
1666 == KDChartParams::DataEntry ) );
1667 // Advance to next value; only for normal bars
1668 if ( bNormalMode ) {
1669 if( bAdvanceToNextValue )
1670 xpos += barWidth;
1671 // skip gap between datasets, unless last dataset
1672 if ( dataset < myLastDataEntryDataset )
1673 xpos += datasetGap;
1674 }
1675 if( bAdvanceToNextValue || bMultiRows ){
1676 //tqDebug("shiftMyPainter( -nShiftX, nShiftY );");
1677 shiftMyPainter( -nShiftX, nShiftY );
1678 }
1679 bIsVeryFirstBar = false;
1680 bIsFirstDataset = false;
1681 }
1682
1683
1684 // Advancement between value blocks
1685 if ( bNormalMode ){
1686 // skip gap between value blocks, don't worry about last one here
1687 xpos += valueBlockGap;
1688 //tqDebug("**************************** xpos: %f + valueBlockGap: %f = %f", xpos, valueBlockGap, xpos+valueBlockGap);
1689 }else{
1690 // skip gap between value blocks
1691 xpos += valueBlockGap + barWidth;
1692 //tqDebug ( "2/ barWidth %f", barWidth );
1693 //tqDebug ( " valueBlockGap %f", valueBlockGap );
1694 // start at bottom with next value group
1695 yposPositives = yposPositivesStart;
1696 yposNegatives = yposNegativesStart;
1697 }
1698 //tqDebug("shiftMyPainterBack");
1699 shiftMyPainterBack();
1700 }
1701
1702 }
1703
1704
1705 if( bMultiRows )
1706 painter->setClipping( bHadClipping );
1707}
Header for all common chart parameters.
A common base class for classes that implement chart painters for chart types ith axes.
access the chart axis parameters.
int axisTrueLineWidth() const
Returns the axis true line width, as calculated and drawn.
double axisZeroLineStartY() const
Returns the not-rounded y-position where drawing of this axis zero line started.
AxisCalcMode axisCalcMode() const
Returns the axis calculation mode configured in this params object.
virtual ~KDChartBarPainter()
Destructor.
KDChartBarPainter(KDChartParams *params)
Constructor.
The collection class used by KD Chart to store data region information.
Bundles the display parameters of a chart.
int datasetGap() const
Returns the number of pixels between two dataset values.
double threeDBarDepth() const
Returns the depth of the 3D Effect used for 3D bars.
bool valueBlockGapIsRelative() const
Returns if the value set by setValueBlockGap is a per mille value of the chart data area width.
int barWidth() const
Returns the width of one bar as set by setBarWidth or KDCHART_AUTO_SIZE if setBarWidth was never call...
LineMarkerStyle lineMarkerStyle(uint dataset) const
Returns the marker to be used for a dataset.
LineMarkerStyle
The available line marker styles.
int numValues() const
Returns how many of the values should be shown.
bool calculateProperties(int startId, KDChartPropertySet &rSet) const
Retrieves the values that correspond to a property set by reading this set's properties and obtaining...
int valueBlockGap() const
Returns the number of pixels between each value block.
SourceMode chartSourceMode(uint dataset, uint dataset2=KDCHART_NO_DATASET, uint *chart=0) const
Retrieves usage information of a given dataset or a range of datasets.
bool datasetGapIsRelative() const
Returns if the value set by setDatasetGap is a per mille value of the chart data area width.
double cosThreeDBarAngle() const
Returns the cosine in rad of the angle used for 3D bars.
bool threeDBars() const
Returns whether the engine should draw any bars in 3D.
BarChartSubType barChartSubType() const
Returns the bar chart subtype.
Property settings of a single KDChart data cell.
bool hasOwnBarColor(int &idBarColor, TQColor &barColor)
Returns whether this property set is specifying it's own bar color settings.
bool hasOwnShowBar(int &idShowBar, bool &showBar)
Returns whether this property set is specifying it's own flag indicating whether this cell's bar is t...
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 cellContent(uint _row, uint _col, TQVariant &_value1, TQVariant &_value2, int &_prop) const
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.