summaryrefslogtreecommitdiffstats
path: root/libkdchart/KDChartBarPainter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libkdchart/KDChartBarPainter.cpp')
-rw-r--r--libkdchart/KDChartBarPainter.cpp1707
1 files changed, 1707 insertions, 0 deletions
diff --git a/libkdchart/KDChartBarPainter.cpp b/libkdchart/KDChartBarPainter.cpp
new file mode 100644
index 0000000..b41fa34
--- /dev/null
+++ b/libkdchart/KDChartBarPainter.cpp
@@ -0,0 +1,1707 @@
+/* -*- Mode: C++ -*-
+ KDChart - a multi-platform charting engine
+*/
+
+/****************************************************************************
+ ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB. All rights reserved.
+ **
+ ** This file is part of the KDChart library.
+ **
+ ** This file may be distributed and/or modified under the terms of the
+ ** GNU General Public License version 2 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file.
+ **
+ ** Licensees holding valid commercial KDChart licenses may use this file in
+ ** accordance with the KDChart Commercial License Agreement provided with
+ ** the Software.
+ **
+ ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ **
+ ** See http://www.klaralvdalens-datakonsult.se/?page=products for
+ ** information about KDChart Commercial License Agreements.
+ **
+ ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
+ ** licensing are not clear to you.
+ **
+ **********************************************************************/
+#include "KDChartBarPainter.h"
+#include <KDChartParams.h>
+
+#include <qpainter.h>
+
+#include <stdlib.h>
+
+/**
+ \class KDChartBarPainter KDChartBarPainter.h
+
+ \brief A chart painter implementation that can paint bar charts.
+*/
+
+/**
+ Constructor. Sets up internal data structures as necessary.
+
+ \param params the KDChartParams structure that defines the chart
+*/
+KDChartBarPainter::KDChartBarPainter( KDChartParams* params ) :
+ KDChartAxesPainter( params )
+{
+ // This constructor intentionally left blank so far; we cannot setup the
+ // geometry yet since we do not know the size of the painter.
+}
+
+
+/**
+ Destructor.
+*/
+KDChartBarPainter::~KDChartBarPainter()
+{
+ // intentionally left blank
+}
+
+bool KDChartBarPainter::isNormalMode() const
+{
+
+ return KDChartParams::BarNormal == params()->barChartSubType();
+}
+
+int KDChartBarPainter::clipShiftUp( bool normalMode, double areaWidthP1000 ) const
+{
+
+ const bool bThreeDBars = params()->threeDBars() || (KDChartParams::BarMultiRows == params()->barChartSubType());
+ return ( normalMode && !bThreeDBars )
+ ? static_cast < int > ( areaWidthP1000 * 16.0 )
+ : 0;
+}
+
+
+void KDChartBarPainter::initMyPainter( QPainter* painter )
+{
+ _myPainter = painter;
+ _painterDX = 0.0;
+ _painterDY = 0.0;
+}
+
+void KDChartBarPainter::shiftMyPainter( double dx, double dy )
+{
+ if( dx != 0.0 || dy != 0.0 ){
+ _myPainter->translate(dx, dy);
+ _painterDX += dx;
+ _painterDY += dy;
+ }
+}
+
+void KDChartBarPainter::shiftMyPainterBack()
+{
+ if( _painterDX != 0.0 || _painterDY != 0.0 ){
+ _myPainter->translate(-_painterDX, -_painterDY);
+ _painterDX = 0.0;
+ _painterDY = 0.0;
+ }
+}
+
+
+void KDChartBarPainter::calculateXFront1_2( bool bNormalMode, bool bIsVeryFirstBar, bool bIsFirstDataset, bool _bThreeDBars,
+ double xpos, double valueBlockGap, double datasetGap, double frontBarWidth,
+ int& frontX1, int& frontX2, int& prevFrontX2 ){
+
+ if( _bThreeDBars || bIsVeryFirstBar || !bNormalMode )
+ frontX1 = static_cast<int>( xpos );
+ else if( bIsFirstDataset )
+ frontX1 = prevFrontX2 + static_cast <int> ( valueBlockGap ) + 1;
+ else
+ frontX1 = prevFrontX2 + static_cast < int > ( datasetGap ) + 1;
+
+ // Note: frontX2 is calculated by using xpos but NOT by using frontX1.
+ // So we make sure that (a) the gaps between all bars of one dataset
+ // are exactly the same size, and that (b) the bars are automatically
+ // adjusted in their width: to match their very position within the abscissa range.
+ // Adjusting will result in them being ONE pixel wider sometimes.
+ frontX2 = static_cast < int > ( xpos + frontBarWidth );
+ prevFrontX2 = frontX2;
+}
+
+
+QPointArray rectToPointArray( const QRect& r )
+{
+ QPointArray a(4);
+ a.putPoints( 0, 4, r.left(),r.top(), r.right(),r.top(), r.right(),r.bottom(), r.left(),r.bottom() );
+ return a;
+}
+
+
+void KDChartBarPainter::specificPaintData( QPainter* painter,
+ const QRect& ourClipRect,
+ KDChartTableDataBase* data,
+ KDChartDataRegionList* regions,
+ const KDChartAxisParams* ordinatePara,
+ bool bNormalMode,
+ uint chart,
+ double logWidth,
+ double areaWidthP1000,
+ double logHeight,
+ double axisYOffset,
+ double minColumnValue,
+ double maxColumnValue,
+ double columnValueDistance,
+ uint chartDatasetStart,
+ uint chartDatasetEnd,
+ uint datasetStart,
+ uint datasetEnd )
+{
+ /****************Pending Michel***********************
+ *Rectangles are painted in the following order: *
+ *front , right side, top. *
+ *Store the painted rectangles in order to paint *
+ *them in relation to each other for more precision. *
+ ****************************************************/
+ QRect frontRectPositive,frontRectNegative,
+ rightRectPositive, rightRectNegative,
+ excessRectPositive,excessRectNegative;
+
+ _areaP1000 = areaWidthP1000;
+
+
+
+ if( !data ) return;
+ // qDebug("datasetStart: %i datasetEnd: %i", datasetStart, datasetEnd);
+ const QPen defaultOutlinePen( params()->outlineDataColor(),
+ params()->outlineDataLineWidth(),
+ params()->outlineDataLineStyle() );
+ abscissaInfos ai;
+ ai.bCenterThePoints = true;
+ calculateAbscissaInfos( *params(), *data,
+ datasetStart, datasetEnd,
+ logWidth, _dataRect,
+ ai );
+
+ const QRect devRect( painter->window() );
+
+ initMyPainter( painter );
+
+ const bool ordinateIsLogarithmic
+ = KDChartAxisParams::AxisCalcLogarithmic == ordinatePara->axisCalcMode();
+
+ const bool bMultiRows = KDChartParams::BarMultiRows == params()->barChartSubType();
+ _bThreeDBars = params()->threeDBars() || bMultiRows;
+ int numChartDataEntryDatasets = 0;
+ uint myLastDataEntryDataset = 0;
+ for( uint iD = chartDatasetStart; iD <= chartDatasetEnd; ++iD ){
+ if( params()->chartSourceMode( iD ) == KDChartParams::DataEntry ){
+ ++numChartDataEntryDatasets;
+ myLastDataEntryDataset = iD;
+ }
+ }
+
+ const bool bHadClipping = painter->hasClipping();
+
+ //this allow the height/size of the bar to be painted fully
+ if( bMultiRows ) {
+ painter->setClipping( false );
+ }
+ // Number of columns in one dataset: If -1, use all values,
+ // otherwise use the specified number of values.
+ int numValues = 0;
+ if ( params()->numValues() != -1 )
+ numValues = params()->numValues();
+ else
+ numValues = data->usedCols();
+
+ double datasetGap = bMultiRows
+ ? 0.0
+ : params()->datasetGap()
+ * ( params()->datasetGapIsRelative()
+ ? areaWidthP1000
+ : 1.0 );
+ double valueBlockGap = bMultiRows
+ ? 0.0
+ : params()->valueBlockGap()
+ * ( params()->valueBlockGapIsRelative()
+ ? areaWidthP1000
+ : 1.0 );
+
+ // This is the same for all three bar types except for multi-bar Surface charts.
+ double spaceBetweenValueBlocks = bMultiRows
+ ? 0.0
+ : static_cast<int>( valueBlockGap ) * numValues;
+
+ // Set some geometry values that apply to bar charts only
+ double totalNumberOfBars = 0.0;
+ double spaceBetweenDatasets = 0.0;
+ switch ( params()->barChartSubType() ) {
+ case KDChartParams::BarNormal: {
+ totalNumberOfBars = numChartDataEntryDatasets * numValues;
+ spaceBetweenDatasets = datasetGap
+ * ( totalNumberOfBars - numValues );
+ break;
+ }
+ case KDChartParams::BarStacked:
+ case KDChartParams::BarPercent:
+ case KDChartParams::BarMultiRows:
+ totalNumberOfBars = numValues;
+ spaceBetweenDatasets = 0; // always 0 when stacked/percent/multi-rows
+ break;
+ default:
+ qFatal( "Unsupported bar chart type" );
+ };
+
+ double barWidth = 0.0;
+ if( params()->barWidth() == KDCHART_AUTO_SIZE ) {
+
+ //Default auto calc. to optimize when many bars datasetGap == blockGap/2 == barWidth/2
+ //unless valueBlockGap or datasetGap are different from default values == users value
+ barWidth = logWidth / totalNumberOfBars;
+ do {
+ barWidth -= 0.1;
+ params()->valueBlockGap() != 24 ? spaceBetweenValueBlocks = params()->valueBlockGap() * numValues
+ : spaceBetweenValueBlocks = ( barWidth/2 ) * numValues;
+ if ( spaceBetweenDatasets != 0 )
+ params()->datasetGap()!= 6 ? spaceBetweenDatasets = params()->datasetGap() * ( totalNumberOfBars - numValues )
+ : spaceBetweenDatasets = ( barWidth/4 ) * ( totalNumberOfBars - numValues );
+ }
+ while ( barWidth*totalNumberOfBars + spaceBetweenValueBlocks + spaceBetweenDatasets > logWidth );
+
+ valueBlockGap = ( spaceBetweenValueBlocks )/ numValues;
+ if ( spaceBetweenDatasets != 0 )
+ datasetGap = spaceBetweenDatasets / ( totalNumberOfBars - numValues );
+
+ barWidth = (logWidth - ( valueBlockGap * numValues ) - ( datasetGap * ( totalNumberOfBars - numValues ) ) ) / totalNumberOfBars;
+ ;
+
+ /* Debug space available
+ qDebug ( " logWidth %f" , logWidth );
+ qDebug ( "compare value %f", barWidth*totalNumberOfBars + spaceBetweenValueBlocks + datasetGap * ( totalNumberOfBars - numValues ) );
+ */
+ } else if( 0 > params()->barWidth() )
+ barWidth = params()->barWidth() * -areaWidthP1000;
+ else
+ barWidth = params()->barWidth();
+
+ //sideBarWidth: pre-calculate in order to have a reference
+ //we will correct according to the available space later.
+ //This in order to center the labels in relation to the front width
+ //when painting 3DBars
+ double sideBarWidth = _bThreeDBars
+ ? ( barWidth - barWidth / (1.0 + params()->cosThreeDBarAngle()) ) *
+ params()->threeDBarDepth()
+ : 0.0;
+
+ const double frontBarWidth = _bThreeDBars && !bMultiRows
+ ? barWidth - sideBarWidth
+ : barWidth;
+
+ //correct the width for the side of the bar
+ double totalThreeDBarWidth = totalNumberOfBars*barWidth + sideBarWidth;
+ double totalSpaceOccupied = totalThreeDBarWidth + spaceBetweenDatasets + spaceBetweenValueBlocks;
+ if ( logWidth < totalSpaceOccupied) {
+ sideBarWidth -= (totalSpaceOccupied /*+ spaceBetweenDatasets + spaceBetweenValueBlocks*/ - logWidth)/totalNumberOfBars;
+
+ //qDebug ( "logWidth %f", logWidth );
+ //qDebug ( "totalSpaceOccupied %f", totalSpaceOccupied );
+ }
+
+ const double sideBarHeight = sideBarWidth;
+
+
+ double pixelsPerUnit = 0.0;
+
+ if ( params()->barChartSubType() != KDChartParams::BarPercent ) // not used for percent
+ pixelsPerUnit = logHeight / ( columnValueDistance ? columnValueDistance : 10 );
+
+ //qDebug("\nordinatePara->trueAxisLow() = %f", ordinatePara->trueAxisLow());
+ //qDebug( "ordinatePara->trueAxisHigh() = %f", ordinatePara->trueAxisHigh());
+ //qDebug( "sideBarHeight = %f", sideBarHeight);
+ //qDebug( "pixelsPerUnit = %f", pixelsPerUnit);
+
+ double zeroXAxisI;
+ if ( params()->barChartSubType() == KDChartParams::BarPercent ) {
+ if ( minColumnValue == 0.0 )
+ zeroXAxisI = 0.0;
+ else if ( maxColumnValue == 0.0 )
+ zeroXAxisI = logHeight - sideBarHeight;
+ else
+ zeroXAxisI = ( logHeight - sideBarHeight ) / 2.0;
+
+ } else {
+ zeroXAxisI = logHeight
+ - ordinatePara->axisZeroLineStartY()
+ + _dataRect.y();
+ }
+
+ double shiftUpperBars = (params()->barChartSubType() != KDChartParams::BarPercent)
+ && (ordinatePara->axisTrueLineWidth() % 2)
+ ? 1.0
+ : 0.0;
+
+ // Initializing drawing positions
+ double yposPositivesStart = logHeight;
+ double yposNegativesStart = logHeight;
+ if( params()->barChartSubType() == KDChartParams::BarPercent ){
+ yposPositivesStart += axisYOffset;
+ yposNegativesStart += axisYOffset;
+ }
+
+ for ( int iPaintExtraLinesOrTheData = 0;
+ iPaintExtraLinesOrTheData < 3;
+ ++iPaintExtraLinesOrTheData )
+ {
+
+ const bool bDrawExtraLines = (1 != iPaintExtraLinesOrTheData);
+ const bool bDrawExtraLinesInFront = (2 == iPaintExtraLinesOrTheData);
+
+ double xpos = 0.0;
+
+ if ( _bThreeDBars && !bMultiRows )
+ xpos = 0.0 + (barWidth/2) + (valueBlockGap/2) - (frontBarWidth/2);
+ else
+ xpos = 0.0 + (valueBlockGap / 2.0);
+
+ double yposPositives = yposPositivesStart;
+ double yposNegatives = yposNegativesStart;
+
+ /* Pending Michel: no need for this anymore */
+ //double totalThreeDBarWidth = bMultiRows
+ //? barWidth + sideBarWidth
+ // : barWidth;
+
+ double nShiftX = bMultiRows
+ ? sideBarWidth
+ : 0.0;
+ double nShiftY = bMultiRows
+ ? sideBarHeight
+ : 0.0;
+
+ double valueTotal = 0.0; // valueTotal is used for percent bars only
+
+ // iterate over all columns: item1, item2, item3 ...
+ int prevFrontX2 = 0;
+ bool bIsVeryFirstBar = true;
+ for ( int value = 0; value < numValues; ++value ) {
+
+ bool bFirstValidValueUnknown = true;
+ uint firstValidValue = 0;
+ uint lastValidPositiveValue = 0;
+ double maxValueInThisColumn = 0.0, minValueInThisColumn = 0.0;
+ if ( params()->barChartSubType() == KDChartParams::BarStacked ||
+ params()->barChartSubType() == KDChartParams::BarPercent) {
+ valueTotal = 0.0;
+ // iterate over datasets of this axis only:
+ for ( uint dataset = datasetStart;
+ dataset <= datasetEnd;
+ ++dataset ) {
+
+ QVariant vVal;
+ if( data->cellCoord( dataset, value, vVal, 1 )
+ && params()->chartSourceMode( dataset ) == KDChartParams::DataEntry
+ && QVariant::Double == vVal.type() ){
+
+ const double cellValue
+ = ordinateIsLogarithmic
+ ? log10( vVal.toDouble() )
+ : vVal.toDouble();
+ //qDebug("value %u dataset %u logHeight %f", value,dataset,logHeight);
+
+ if( bFirstValidValueUnknown ){
+ firstValidValue = dataset;
+ bFirstValidValueUnknown = false;
+ }
+ if( 0.0 <= cellValue )
+ lastValidPositiveValue = dataset;
+
+ maxValueInThisColumn = QMAX( maxValueInThisColumn, cellValue );
+ minValueInThisColumn = QMIN( minValueInThisColumn, cellValue );
+ if( params()->barChartSubType() == KDChartParams::BarPercent /*||
+ params()->barChartSubType() == KDChartParams::BarStacked*/ )
+ valueTotal += cellValue;
+ }
+ }
+ }
+
+ //qDebug("shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );");
+ shiftMyPainter( (numChartDataEntryDatasets-1)*nShiftX, (numChartDataEntryDatasets-1)*-nShiftY );
+
+ // iterate over all datasets of this chart:
+ // (but draw only the bars of this axis)
+ bool bIsFirstDataset = true;
+ for ( uint dataset = bMultiRows
+ ? chartDatasetEnd
+ : chartDatasetStart;
+ dataset >= chartDatasetStart && dataset <= chartDatasetEnd;
+ bMultiRows
+ ? --dataset
+ : ++dataset ) {
+ //qDebug("value %u dataset %u logHeight %f", value,dataset,logHeight);
+
+ const bool bDataEntrySourceMode
+ = (params()->chartSourceMode( dataset ) == KDChartParams::DataEntry);
+
+
+ QVariant coord1;
+ QVariant coord2;
+ int propID;
+ if( data->cellContent( dataset, value, coord1, coord2, propID )
+ && QVariant::Double == coord1.type() ){
+
+ const double cellValue
+ = ordinateIsLogarithmic
+ ? log10( coord1.toDouble() )
+ : coord1.toDouble();
+ //qDebug("b");
+ // there is a numeric value
+
+ double barHeight;
+
+ if ( params()->barChartSubType() == KDChartParams::BarPercent )
+ barHeight = ( cellValue / valueTotal ) * fabs(zeroXAxisI - logHeight );
+ else {
+ barHeight = pixelsPerUnit * cellValue;
+
+ if( 0.0 <= barHeight )
+ //barHeight = QMAX(0.0, barHeight - sideBarHeight);
+ barHeight = barHeight - sideBarHeight;
+ else
+ barHeight -= sideBarHeight;
+ }
+
+ // This little adjustment avoids a crash when trying
+ // to retrieve the bounding rect of a zero size region...
+ if( 0 == barHeight || 0.0 == barHeight ) {
+
+ barHeight = 1.0; // makes sense to have a min size anyway
+ }
+
+ // draw only the bars belonging to the axis
+ // which we are processing currently
+ if( dataset >= datasetStart && dataset <= datasetEnd ) {
+ //qDebug("b2");
+
+ // calculate Abscissa axis value, if there are X coordinates
+ // ---------------------------------------------------------
+ bool skipMe = false;
+ if( ai.bCellsHaveSeveralCoordinates ){
+ skipMe = !calculateAbscissaAxisValue( coord2,
+ ai, 0, xpos );
+ // adjust bar position to have it horizontally centered to the point
+ if( ai.bAbscissaHasTrueAxisDtValues &&
+ QVariant::DateTime == coord2.type() )
+ xpos -= frontBarWidth / 2.0;
+ }
+
+ if( !skipMe ){
+ // Configure colors
+ QColor myBarColor( params()->dataColor( dataset ) );
+ QColor myShadow1Color( params()->dataShadow1Color( dataset ) );
+ QColor myShadow2Color( params()->dataShadow2Color( dataset ) );
+
+ // Get default values for extra lines and their markers
+ const KDChartParams::LineMarkerStyle
+ defaultMarkerStyle = params()->lineMarkerStyle( dataset );
+ const QPen defaultPen( params()->lineColor().isValid()
+ ? params()->lineColor()
+ : params()->dataColor( dataset ),
+ params()->lineWidth(),
+ params()->lineStyle( dataset ) );
+
+ // --------------------------------------------------------
+ // determine any 'extra' properties assigned to this cell
+ // by traversing the property set chain (if necessary)
+ // --------------------------------------------------------
+ KDChartPropertySet propSet;
+ bool bCellPropertiesFound =
+ params()->calculateProperties( propID,
+ propSet );
+ bool bShowThisBar = bDataEntrySourceMode;
+ if( bCellPropertiesFound ){
+ if( bShowThisBar && !bDrawExtraLines ){
+ int iDummy;
+ if( propSet.hasOwnShowBar( iDummy, bShowThisBar ) ){
+ // NOP
+ }
+ if( propSet.hasOwnBarColor( iDummy, myBarColor ) ){
+ // adjust the shadow colors
+ params()->calculateShadowColors( myBarColor,
+ myShadow1Color,
+ myShadow2Color );
+ }
+ }
+ }
+
+ if( !bDrawExtraLines || bCellPropertiesFound ){
+
+ //QRegion* region = 0;
+ KDChartDataRegion::PointArrayList * pointArrayList = 0;
+ if( bDataEntrySourceMode && !bDrawExtraLines ){
+ painter->setPen( defaultOutlinePen );
+ if ( myBarColor.isValid() )
+ painter->setBrush( myBarColor );
+ else
+ painter->setBrush( NoBrush );
+
+ // Prepare region for detection of mouse clicks
+ // and for finding anchor positions of data value texts
+ if ( regions )
+ pointArrayList = new KDChartDataRegion::PointArrayList();
+ }
+
+ // Start drawing
+ int frontX1 = 0;
+ int frontX2 = 0;
+ bool tooLow = false;
+ bool tooHigh = false;
+
+ if ( cellValue < 0 || cellValue < minColumnValue ) {
+ double maxValueYPos = maxColumnValue * pixelsPerUnit;
+ double yZero = yposNegatives - zeroXAxisI - sideBarHeight;
+
+ tooLow = (barHeight - yZero + logHeight + axisYOffset) < 0;
+
+ /*we need to handle those values in case we have a negative view*/
+ if ( cellValue <= 0 && cellValue > maxColumnValue && minColumnValue < 0 && maxColumnValue < 0 )
+ tooLow = true;
+
+ if ( tooLow && ( bNormalMode || bMultiRows) ) {
+ double delta = 0.0125 * logHeight;
+ double height = -1*(-1.0 * (yZero + sideBarHeight) - 2 * delta);
+ double height1 = height - 3.0 * delta;
+
+ int yArrowGap = static_cast < int > ( 2.5 * delta );
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ frontX1, frontX2, prevFrontX2 );
+
+ const int xm = static_cast < int > ( (frontX1 + frontX2) / 2.0 );
+ QRect rect( ourClipRect );
+
+ rect.setHeight( static_cast<int>( rect.height() + 3.0 * delta ) );
+ painter->setClipRect( rect );
+
+ //Pending Michel: Make sure the point of the arrow is always at the same distance
+ //from the X axis reference to the point of the arrow.
+ int arrowXAxisGap;
+ QPoint arrowTop( xm,static_cast<int>( yZero + height1 + 2 * yArrowGap) );
+
+ if ( arrowTop.y()== yposNegatives )
+ arrowXAxisGap = -2;
+ else
+ arrowXAxisGap = static_cast <int> (yposNegatives - arrowTop.y() - 2);
+
+ if( bDrawExtraLines ){
+ drawExtraLinesAndMarkers(
+ propSet,
+ defaultPen,
+ defaultMarkerStyle,
+ xm, static_cast<int>( yZero + height1 ),
+ painter,
+ ai.abscissaPara,
+ ordinatePara,
+ areaWidthP1000,
+ logHeight/1000.0,
+ bDrawExtraLinesInFront );
+ }else if( bShowThisBar ){
+ if( params()->drawSolidExcessArrows() ) {
+
+ /* PENDING Michel:
+ * Here we have two situations.
+ * The value is too low because over the Min negative value
+ * or it is not within the configured view.
+ */
+ // Draw solid excess arrows negatives
+
+ QPointArray points( 5 );
+ /*this works in a positive view -> 200 500*/
+ points.setPoint( 0, frontX1, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 1, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap );
+ points.setPoint( 2, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 3, xm, cellValue < 0 ?
+ static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap:
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 4, frontX1, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2*yArrowGap)+ arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2*yArrowGap)+ arrowXAxisGap);
+
+ /* 0 between start and end -> -500 500*/
+ if ( minColumnValue < 0 && maxColumnValue > 0 ) {
+ points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
+ points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
+ }
+
+ /* negative view -> -200 -500 */
+ if ( minColumnValue < 0 && maxColumnValue < 0 ) {
+ /*value negative or zero > maxColumnValue*/
+ if ( cellValue > maxColumnValue ) {
+ // the view is under Yaxis 0 level
+ // we need to show a symbol for the bars which are over the Yaxis.
+ // calculate the coordinate and direction for the arrow.
+ // arrow downward for negative values and upward for positives value
+ int diffArrowBase = points.point(2).y() - points.point(3).y();
+ double maxValueYPos = maxColumnValue * pixelsPerUnit;
+ double minValueYPos = minColumnValue * pixelsPerUnit;
+ double adjustedArrow = (cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase + 2:
+ minValueYPos - maxValueYPos - diffArrowBase + 1);
+ points.setPoint( 0, frontX1, points.point(0).y() + static_cast <int> (adjustedArrow));
+ points.setPoint( 1, frontX2, points.point(1).y() + static_cast <int> (adjustedArrow ));
+ points.setPoint( 2, frontX2, points.point(2).y() + static_cast <int> (adjustedArrow));
+ points.setPoint( 3, xm, points.point(3).y() + static_cast <int> (adjustedArrow));
+ points.setPoint( 4, frontX1, points.point(4).y() + static_cast <int> (adjustedArrow));
+ }
+ /*value < mincolumn value*/
+ if ( cellValue < minColumnValue ) {
+ points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos ) );
+ points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos ) );
+ }
+
+ }
+
+ /*Pending Michel: case setbarWidth */
+ //adjust the painting in case we have a user given Width allow it
+ //to be larger than the auto calculated width in case we want to overlap
+
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ QRect tmpRect ( points.point(0), points.point(2));
+ points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(0).y());
+ points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(1).y());
+ points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(2).y());
+ points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(4).y());
+ //}
+ }
+ if ( bMultiRows )painter->setClipping( false );
+ painter->drawPolygon( points );
+
+ //correct the y position: displaying position for the value label
+ QPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
+ QPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
+
+ //store the front rectangle
+ excessRectNegative.setTopLeft(tpLeft);
+ excessRectNegative.setTopRight(tpRight);
+ excessRectNegative.setBottomRight(points.point(1));
+ excessRectNegative.setBottomLeft(points.point(0));
+
+ // Don't use points for drawing after this!
+ if ( pointArrayList ) {
+ if ( cellValue < 0 ) {
+ //correction for labels vertical position
+ int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
+ points.setPoint( 4 ,tpLeft );
+ points.setPoint( 2, tpRight );
+ if ( cellValue < maxColumnValue )
+ points.translate( _dataRect.x(), -_dataRect.y() - size );
+ else
+ points.translate( _dataRect.x(), _dataRect.y() );
+ } else
+ points.translate( _dataRect.x(), _dataRect.y() );
+
+ pointArrayList->append( points );
+ }
+
+ } else {
+ // Draw split excess arrows negatives
+
+ /* PENDING Michel:
+ * Here we have two situations.
+ * The value is too low because over the Min negative value
+ * The value is not within the configured view..
+ */
+ QPointArray points( 5 );
+ /*this works in a positive view -> 200 500*/
+ points.setPoint( 0, frontX1, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 1, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 2, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 3, xm, cellValue < 0 ?
+ static_cast<int>( yZero + height1) + arrowXAxisGap:
+ static_cast<int>(yZero+height1 - 3.0*delta)+(2 * yArrowGap)+ arrowXAxisGap);
+ points.setPoint( 4, frontX1, cellValue < 0 ?
+ static_cast<int>(yZero+height1 - 3.0*delta) + arrowXAxisGap:
+ static_cast<int>( yZero + height1)+(2 * yArrowGap)+ arrowXAxisGap);
+
+ /* 0 between start and end -> -500 500*/
+ if ( minColumnValue < 0 && maxColumnValue > 0 ) {
+ points.setPoint(0, points.point(0).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
+ points.setPoint(1, points.point(1).x(), static_cast <int> (yposNegatives - zeroXAxisI) );
+ }
+
+ /* negative view -> -200 -500 */
+ if ( minColumnValue < 0 && maxColumnValue < 0 ) {
+ /*value negative or zero > maxColumnValue*/
+ if ( cellValue > maxColumnValue ) {
+ // the view is under Yaxis 0 level
+ // we need to show a symbol for the bars which are over the Yaxis.
+ // calculate the coordinate and direction for the arrow.
+ // arrow downward for negative values and upward for positives value
+ int diffArrowBase = points.point(2).y() - points.point(3).y();
+ double maxValueYPos = maxColumnValue * pixelsPerUnit;
+
+ points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
+ points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
+ points.setPoint( 2, frontX2, static_cast <int> ( yZero - maxValueYPos) );
+ points.setPoint( 3, xm, static_cast <int> ( yZero - maxValueYPos - diffArrowBase ) );
+ points.setPoint( 4, frontX1, static_cast <int> ( yZero - maxValueYPos) );
+ }
+ /*value < mincolumn value*/
+ if ( cellValue < minColumnValue ) {
+ points.setPoint( 0, frontX1, static_cast <int> ( yZero - maxValueYPos) );
+ points.setPoint( 1, frontX2, static_cast <int> ( yZero - maxValueYPos) );
+ }
+ }
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ QRect tmpRect ( points.point(0), points.point(2));
+ points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(0).y());
+ points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(1).y());
+ points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(2).y());
+ points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(4).y());
+ }
+ if ( bMultiRows )painter->setClipping( false );
+ painter->drawPolygon( points );
+
+ //correct the y position: displaying position for the value label
+ QPoint tpLeft (points.point(4).x(), points.point(4).y() - 2 * yArrowGap );
+ QPoint tpRight(points.point(2).x(), points.point(2).y() - 2 * yArrowGap );
+
+ //store the excess front rectangle
+ excessRectNegative.setTopLeft(tpLeft);
+ excessRectNegative.setTopRight(tpRight);
+ excessRectNegative.setBottomRight(points.point(1));
+ excessRectNegative.setBottomLeft(points.point(0));
+
+ // Don't use points for drawing after this!
+ if ( pointArrayList ) {
+ if ( cellValue < 0 ) {
+ //calculate correction for labels vertical position
+ int size = static_cast <int> ( ( points.point( 3 ).y() - tpRight.y() + excessRectNegative.width() )/2 );
+ if ( cellValue < maxColumnValue )
+ points.translate( _dataRect.x(), -_dataRect.y() - size );
+ else
+ points.translate( _dataRect.x(), _dataRect.y() + ( 2 * yArrowGap ) );
+ } else
+ points.translate( _dataRect.x(), -_dataRect.y() );
+
+ pointArrayList->append( points );
+ }
+
+ QPointArray points2( 6 );
+ points2.setPoint( 0, frontX1, cellValue < 0 ?
+ static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap:
+ static_cast<int>(yZero + height1) + arrowXAxisGap);
+ points2.setPoint( 1, xm, cellValue < 0 ?
+ static_cast<int>(yZero + height1) + arrowXAxisGap:
+ static_cast<int>( yZero + height1 - 3.0 * delta ) + arrowXAxisGap);
+ points2.setPoint( 2, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero + height1 - 3.0 * delta) + arrowXAxisGap:
+ static_cast<int>(yZero + height1) + arrowXAxisGap);
+ points2.setPoint( 3, frontX2, cellValue < 0 ?
+ static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap :
+ static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap);
+ points2.setPoint( 4, xm, cellValue < 0 ?
+ static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap:
+ static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap);
+ points2.setPoint( 5, frontX1, cellValue < 0 ?
+ static_cast<int>(yZero + height1 - 3.75 * delta) + arrowXAxisGap:
+ static_cast<int>(yZero + height1 - 0.75 * delta) + arrowXAxisGap);
+ points2.translate( 0, yArrowGap );
+
+ if ( minColumnValue < 0 && maxColumnValue < 0 && cellValue > maxColumnValue ) {
+ // the view is under Yaxis 0 level
+ // we need to show a symbol for the bars which are over the Yaxis.
+ // calculate the coordinate and direction for the arrow.
+ // arrow downward for negative values and upward for positives value
+ int diffArrowBase = points.point(2).y() - points.point(3).y();
+ double maxValueYPos = maxColumnValue * pixelsPerUnit;
+ double minValueYPos = minColumnValue * pixelsPerUnit;
+ double adjustedArrow = cellValue == 0 ? minValueYPos - maxValueYPos + diffArrowBase:
+ minValueYPos - maxValueYPos - diffArrowBase + 1;
+
+ points2.setPoint( 0, frontX1, points2.point(0).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ points2.setPoint( 1, xm, points2.point(1).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ points2.setPoint( 2, frontX2, points2.point(2).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ points2.setPoint( 3, frontX2, points2.point(3).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ points2.setPoint( 4, xm, points2.point(4).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ points2.setPoint( 5, frontX1, points2.point(5).y()
+ + static_cast <int> (adjustedArrow - diffArrowBase + yArrowGap) );
+ }
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+
+ points2.setPoint(0, excessRectNegative.topLeft().x(),points2.point(0).y());
+ points2.setPoint(2, excessRectNegative.topRight().x(),points2.point(2).y());
+ points2.setPoint(3, excessRectNegative.topRight().x(),points2.point(3).y());
+ points2.setPoint(5, excessRectNegative.topLeft().x(),points2.point(5).y());
+ }
+
+ painter->drawPolygon( points2 );
+
+ /*
+ NOTE: We do NOT want to store the region here, but
+ we use the front rectangle above in order to display the
+ data value labels inside the front rectangle.
+ Disadvantage: clicking onto these excess arrows, will not
+ result in a signal being sent, because KDChartWidget will
+ not notice, that the user has clicked onto the bar.
+ That's a minor drawback, compared to the gain of being
+ able to position the labels correctly.
+ */
+
+ if ( cellValue < 0 )
+ points2.translate( 0, yArrowGap );
+ else
+ points2.translate( 0, -yArrowGap );
+
+ painter->drawPolygon( points2 );
+
+
+ /*
+ NOTE: We do NOT want to store the region here
+ (see comment above)
+ */
+ }
+ }
+ painter->setClipRect( ourClipRect );
+ } /*if (tooLow && bNormalMode)*/
+ else {
+ //
+ // old code (sometimes not touching the grid):
+ //QRect rec( xpos, yZero, frontBarWidth, -barHeight );
+ //painter->drawRect( rec );
+ //
+
+ int pt1Y = static_cast < int > ( yZero - barHeight /*- sideBarsHeight*/ );
+
+ /*
+ if ( cellValue != 0 ) {
+ pt1Y = static_cast <int> (cellValue * pixelsPerUnit * -2);
+ qDebug( "value %s",QString::number(static_cast <int> (cellValue)).latin1());
+ qDebug( "pt1Y %s", QString::number(static_cast <int> (cellValue * pixelsPerUnit * -2)).latin1());
+ }
+ else
+ pt1Y = static_cast < int > ( yZero - barHeight);
+ */
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ frontX1, frontX2, prevFrontX2 );
+
+ QPoint pt1( frontX1, pt1Y );
+ QPoint pt2( frontX2,
+ static_cast < int > ( yZero + sideBarHeight) );
+
+ if( 0.0 > maxColumnValue ){
+ pt2.setY(pt2.y() - static_cast < int > (pixelsPerUnit * maxColumnValue));
+ }
+ if( pt2.y() < pt1Y ) {
+ pt1.setY( pt2.y() );
+ pt2.setY( pt1Y );
+ }
+ if( pt2.x() < frontX1 ) {
+ pt1.setX( frontX2 );
+ pt2.setX( frontX1 );
+ }
+ if( bDrawExtraLines ){
+ int y = pt2.y();
+ if( _bThreeDBars )
+ y -= static_cast < int > ( sideBarHeight );
+ drawExtraLinesAndMarkers(
+ propSet,
+ defaultPen,
+ defaultMarkerStyle,
+ (frontX1+frontX2)/2, y,
+ painter,
+ ai.abscissaPara,
+ ordinatePara,
+ areaWidthP1000,
+ logHeight/1000.0,
+ bDrawExtraLinesInFront );
+ }else if( bShowThisBar ){
+
+ QSize siz( pt2.x() - pt1.x(),
+ pt2.y() - pt1.y() );
+ QRect rect( pt1, siz );
+
+ if( 1.5 > frontBarWidth ){
+ QPen oldPen( painter->pen() );
+ painter->setPen( QPen(painter->brush().color(), 0) );
+ painter->drawLine(pt1, QPoint(pt1.x(),pt2.y()));
+ painter->setPen( oldPen );
+ }else{
+ // store the front rect negative
+ if ( tooLow || cellValue < minColumnValue) {
+ frontRectNegative.setTopLeft(excessRectNegative.bottomLeft());
+ frontRectNegative.setTopRight(excessRectNegative.bottomRight());
+ frontRectNegative.setBottomRight(excessRectNegative.topRight());
+ frontRectNegative.setBottomLeft(excessRectNegative.topLeft());
+
+ } else {
+ frontRectNegative.setTopLeft(rect.topLeft());
+ frontRectNegative.setTopRight(rect.topRight());
+ frontRectNegative.setBottomRight(rect.bottomRight());
+ frontRectNegative.setBottomLeft(rect.bottomLeft());
+
+ if ( cellValue == 0 && params()->barChartSubType() == KDChartParams::BarPercent)
+ rect.setTop( rect.bottom());
+ }
+
+ //debug lines and points
+ /*
+ painter->drawLine( rect.topLeft(), rect.topRight());
+ painter->drawLine( rect.topRight(), rect.bottomRight());
+ painter->drawLine( rect.bottomRight(), rect.bottomLeft());
+ painter->drawLine( rect.bottomLeft(), rect.topLeft());
+
+ painter->drawText( frontRectNegative.topLeft(), "0f");
+ painter->drawText( frontRectNegative.topRight(), "1f");
+ painter->drawText( frontRectNegative.bottomRight(), "2f");
+ painter->drawText( frontRectNegative.bottomLeft(), "3f");
+ */
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //and it is not larger than the auto calculated width
+
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
+ rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
+ rect.setWidth( static_cast <int> (userwidth) );
+ frontRectNegative.setLeft( tooLow || cellValue < minColumnValue ?
+ static_cast <int> (excessRectNegative.center().x() - (userwidth/2)):rect.left());
+ frontRectNegative.setRight( tooHigh ? static_cast <int> (excessRectNegative.center().x() + (userwidth/2)):rect.right());
+ }
+ //drawing the front size negative values
+ if ( cellValue != 0 && params()->barChartSubType() != KDChartParams::BarPercent) {
+ painter->setClipping( false );
+ painter->drawRect( rect );
+ }
+ }
+ // Don't use rect for drawing after this!
+ if ( pointArrayList ) {
+ rect.moveBy( _dataRect.x(), _dataRect.y() );
+ pointArrayList->append( rectToPointArray( rect ) );
+ }
+ }
+ }
+ } else {
+ //
+ // Positive values:
+ //
+ /*Pending Michel: all values under the min value are handled as negative*/
+
+ double maxValueYPos = maxColumnValue * pixelsPerUnit;
+ double minValueYPos = minColumnValue * pixelsPerUnit;
+ double minDataValueYPos = maxValueYPos - minValueYPos;
+ double yZero = yposPositives - zeroXAxisI;
+ //qDebug( "yposPositives %f - zeroXAxisI %f = %f" , yposPositives, zeroXAxisI, yZero );
+ //qDebug( "yZero %s", QString::number( yZero ).latin1());
+ //qDebug( "minDataValueYPos = %s", QString::number( minDataValueYPos).latin1());
+ //qDebug( "positive value %s", QString::number( cellValue).latin1());
+ //Pending Michel: draw the default split excess arrows
+ //when the front top of the 3d chart reach the max Y value
+
+ if(!_bThreeDBars)
+ tooHigh = ( barHeight > maxValueYPos*1.001 ) || ( cellValue < minColumnValue );
+ else {
+ //calculate the Y position for the top front line
+ //if it is over the max height pos - tooHigh becomes true
+ if ( params()->barChartSubType()!= KDChartParams::BarStacked ) {
+ int dataValueYPos = static_cast <int>( ( cellValue * pixelsPerUnit ) );
+ tooHigh = dataValueYPos > maxValueYPos;
+ } else {
+ tooHigh = maxValueInThisColumn > maxColumnValue;
+ }
+ }
+
+ if ( tooHigh && bNormalMode ||
+ tooHigh && params()->barChartSubType()== KDChartParams::BarStacked
+ || tooHigh && bMultiRows ) {
+
+ double delta = -0.0125 * logHeight;
+ double height = -1.0 * yZero
+ - 2.0 * delta;
+ double height1 = height + -3.0 * delta;
+
+ int yArrowGap = static_cast < int > ( 2.5 * delta );
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ frontX1, frontX2, prevFrontX2 );
+
+ const int xm = static_cast < int > ( ( frontX1 + frontX2 ) / 2.0 );
+ QRect rect( ourClipRect );
+
+ rect.setTop( static_cast<int>( rect.top() + 3 * delta ) );
+ rect.setHeight( static_cast<int>( rect.height() - 3 * delta ) );
+ painter->setClipRect( rect );
+
+ if( bDrawExtraLines ){
+ drawExtraLinesAndMarkers(
+ propSet,
+ defaultPen,
+ defaultMarkerStyle,
+ xm, static_cast<int>( yZero + height1 ),
+ painter,
+ ai.abscissaPara,
+ ordinatePara,
+ areaWidthP1000,
+ logHeight/1000.0,
+ bDrawExtraLinesInFront );
+ }else if( bShowThisBar ){
+ if( params()->drawSolidExcessArrows() ) {
+ // Draw solid excess arrows
+ QPointArray points( 5 );
+ /*this works for positive config and 0 include config*/
+ points.setPoint( 0, frontX1,
+ (minDataValueYPos < static_cast <int> (yZero))?
+ static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
+ points.setPoint( 1, frontX2,
+ (minDataValueYPos < static_cast <int> (yZero))?
+ static_cast <int> (minDataValueYPos-1):static_cast <int>(yZero));
+ points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta )
+ + 2 * yArrowGap );
+ points.setPoint( 3, xm, static_cast<int>( yZero + height1 )
+ + 2 * yArrowGap );
+ points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta )
+ + 2 * yArrowGap );
+
+ /*case where start and end value are negatives */
+ if ( cellValue > maxColumnValue && 0 >= maxColumnValue ) {
+ points.setPoint( 0, frontX1,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
+ points.setPoint( 1, frontX2,static_cast<int>( yZero + height1 - 3.0 * delta ) + 2 * yArrowGap);
+ }
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ QRect tmpRect ( points.point(0), points.point(2));
+ points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(0).y());
+ points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(1).y());
+ points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(2).y());
+ points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(4).y());
+ //}
+ }
+ if ( params()->barChartSubType() != KDChartParams::BarStacked ||
+ params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
+ //drawing a single front in case it is too high
+ painter->setClipping( false );
+ painter->drawPolygon( points );
+ }
+ //correct the y position: displaying position for the value label
+ QPoint tpLeft (points.point(4).x(), static_cast <int> (points.point(4).y() - yArrowGap));
+ QPoint tpRight(points.point(2).x(), static_cast <int> (points.point(2).y() - yArrowGap));
+
+ //debugging points
+ /*
+ painter->drawText( points.point(0), "p0");
+ painter->drawText( points.point(1), "p1");
+ painter->drawText( points.point(2), "p2");
+ painter->drawText( points.point(3), "p3");
+ */
+ //store the front rectangle
+ excessRectPositive.setTopLeft(tpLeft);
+ excessRectPositive.setTopRight(tpRight);
+ excessRectPositive.setBottomRight(points.point(1));
+ excessRectPositive.setBottomLeft(points.point(0));
+
+ // Don't use points for drawing after this!
+ if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
+ points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() - yArrowGap );
+ pointArrayList->append( points );
+ } else if ( params()->barChartSubType() == KDChartParams::BarStacked ) {
+ if ( dataset != datasetEnd ) {
+ points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
+ pointArrayList->append( points );
+ } else {
+ //adjust the display of the value label under Y max value level
+ points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
+ pointArrayList->append( points );
+ }
+ }
+ } else {
+
+ // Draw split excess arrows (default)
+ /* PENDING Michel:
+ * Here we have two situations.
+ * The value is too high because over the Max positive value
+ * or it is not within the configured view.
+ */
+ QPointArray points( 5 );
+ /*this works for positive config and 0 include config*/
+ points.setPoint( 0, frontX1,
+ (minDataValueYPos < static_cast <int> (yZero))?
+ static_cast <int> (minDataValueYPos - 1) : static_cast <int>(yZero));
+ points.setPoint( 1, frontX2,
+ (minDataValueYPos < static_cast <int> (yZero))?
+ static_cast<int> ( minDataValueYPos - 1) : static_cast <int>(yZero));
+ points.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
+ points.setPoint( 3, xm, static_cast<int>( yZero + height1 ) );
+ points.setPoint( 4, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
+
+ /*case where start and end value are negatives */
+ if ( cellValue > maxColumnValue && 0 >= maxColumnValue || cellValue == 0) {
+ points.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ));
+ points.setPoint( 1, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ));
+ }
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ QRect tmpRect ( points.point(0), points.point(2));
+ points.setPoint(0, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(0).y());
+ points.setPoint(1, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(1).y());
+ points.setPoint(2, static_cast <int>(tmpRect.center().x() + userwidth/2),
+ points.point(2).y());
+ points.setPoint(4, static_cast <int>(tmpRect.center().x() - userwidth/2),
+ points.point(4).y());
+ //}
+ }
+ if ( params()->barChartSubType() != KDChartParams::BarStacked ||
+ params()->barChartSubType() == KDChartParams::BarStacked && dataset != datasetEnd ) {
+ painter->setClipping( false );
+ painter->drawPolygon( points );
+ }
+
+ //store the front rectangle
+ excessRectPositive.setTopLeft(points.point(4));
+ excessRectPositive.setTopRight(points.point(2));
+ excessRectPositive.setBottomRight(points.point(1));
+ excessRectPositive.setBottomLeft(points.point(0));
+
+ // Don't use points for drawing after this!
+ if ( pointArrayList && params()->barChartSubType() != KDChartParams::BarStacked ) {
+ points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
+ pointArrayList->append( points );
+ } else if ( params()->barChartSubType() == KDChartParams::BarStacked ) {
+ if ( dataset != datasetEnd ) {
+ points.translate( _dataRect.x(), _dataRect.y() + excessRectPositive.top() );
+ pointArrayList->append( points );
+ } else {
+ //adjust the display of the value label under Y max value level
+ points.translate( _dataRect.x(), _dataRect.y() - excessRectPositive.bottom() - yArrowGap);
+ pointArrayList->append( points );
+ }
+ }
+
+ QPointArray points2( 6 );
+ points2.setPoint( 0, frontX1, static_cast<int>( yZero + height1 - 3.0 * delta ) );
+ points2.setPoint( 1, xm, static_cast<int>( yZero + height1 ) );
+ points2.setPoint( 2, frontX2, static_cast<int>( yZero + height1 - 3.0 * delta ) );
+ points2.setPoint( 3, frontX2, static_cast<int>( yZero + height1 - 3.75 * delta ) );
+ points2.setPoint( 4, xm, static_cast<int>( yZero + height1 - 0.75 * delta ) );
+ points2.setPoint( 5, frontX1, static_cast<int>( yZero + height1 - 3.75 * delta ) );
+ points2.translate( 0, yArrowGap );
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ points2.setPoint(0, excessRectPositive.topLeft().x(),points2.point(0).y());
+ points2.setPoint(2, excessRectPositive.topRight().x(),points2.point(2).y());
+ points2.setPoint(3, excessRectPositive.topRight().x(),points2.point(3).y());
+ points2.setPoint(5, excessRectPositive.topLeft().x(),points2.point(5).y());
+ //}
+ }
+
+ painter->drawPolygon( points2 );
+ /*
+ NOTE: We do NOT want to store the region here, but
+ we use the front rectangle above in order to display the
+ data value labels inside the front rectangle.
+ Disadvantage: clicking onto these excess arrows, will not
+ result in a signal being sent, because KDChartWidget will
+ not notice, that the user has clicked onto the bar.
+ That's a minor drawback, compared to the gain of being
+ able to position the labels correctly.
+ */
+ points2.translate( 0, yArrowGap );
+ painter->drawPolygon( points2 );
+ /*
+ NOTE: We do NOT want to store the region here
+ (see comment above)
+ */
+ } // draw split excess arrow
+ } //if( bShowThisBar )
+
+ painter->setClipRect( ourClipRect );
+ } // not tooLow && bNormalMode )
+ else {
+ //bool fromBottom = bNormalMode && !_bThreeDBars;
+ double y0 = yposPositives - zeroXAxisI;
+
+ int pt1Y = static_cast < int > ( y0 - barHeight - sideBarHeight);
+
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ frontX1, frontX2, prevFrontX2 );
+
+ QPoint pt1( frontX1, pt1Y );
+ QPoint pt2( frontX2,
+ static_cast < int > ( y0 + shiftUpperBars ) );
+
+ if( 0.0 < minColumnValue )
+ pt2.setY(pt2.y() - static_cast < int > ( pixelsPerUnit * minColumnValue ));
+
+ if( pt2.y() < pt1Y ) {
+ pt1.setY( pt2.y() );
+ pt2.setY( pt1Y );
+ }
+ if( pt2.x() < frontX1 ) {
+ pt1.setX( frontX2 );
+ pt2.setX( frontX1 );
+ }
+ if( bDrawExtraLines ){
+ int y = pt1.y();
+ if( _bThreeDBars )
+ y -= static_cast < int > ( sideBarHeight );
+
+ drawExtraLinesAndMarkers(
+ propSet,
+ defaultPen,
+ defaultMarkerStyle,
+ (frontX1+frontX2)/2, y,
+ painter,
+ ai.abscissaPara,
+ ordinatePara,
+ areaWidthP1000,
+ logHeight/1000.0,
+ bDrawExtraLinesInFront );
+ }else if( bShowThisBar ){
+
+ QSize siz( pt2.x() - pt1.x(),
+ pt2.y() - pt1.y());
+
+ QRect rect( pt1, siz );
+
+ //adjust display for the 3d percent bars - last dataset.
+ if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue != 0)
+ rect.setTop( rect.top() + static_cast <int> (sideBarHeight) - 1);
+
+ // store the front rect
+ if( tooHigh ) {
+ frontRectPositive.setTopLeft(excessRectPositive.topLeft());
+ frontRectPositive.setTopRight(excessRectPositive.topRight());
+ frontRectPositive.setBottomRight(excessRectPositive.bottomRight());
+ frontRectPositive.setBottomLeft(excessRectPositive.bottomLeft());
+ } else {
+ frontRectPositive.setTopLeft(rect.topLeft());
+ frontRectPositive.setTopRight(rect.topRight());
+ frontRectPositive.setBottomRight(rect.bottomRight());
+ frontRectPositive.setBottomLeft(rect.bottomLeft());
+ if( _bThreeDBars && cellValue == 0 )
+ frontRectNegative = frontRectPositive;
+ }
+
+ if( 1.5 > frontBarWidth ){
+ //qDebug("1.5 > frontBarWidth ");
+ QPen oldPen( painter->pen() );
+ painter->setPen( QPen(painter->brush().color(), 0) );
+ painter->drawLine(pt1, QPoint(pt1.x(),pt2.y()));
+ painter->setPen( oldPen );
+ }else{
+ //debugging points and lines
+ /*
+ painter->drawText( rect.topLeft(), QString::number(cellValue).latin1());
+ painter->drawText( rect.topRight(), "1f");
+ painter->drawText( rect.bottomRight(), "2f");
+ painter->drawText( rect.bottomLeft(), "3f");
+ painter->drawLine( rect.topLeft(), rect.topRight());
+ painter->drawLine( rect.topRight(), rect.bottomRight());
+ painter->drawLine( rect.bottomRight(), rect.bottomLeft());
+ painter->drawLine( rect.bottomLeft(), rect.topLeft());
+ */
+
+ //Pending Michel adjust the painting in case we have a user given Width
+ //allow it to be larger than the auto calculated width in case we want
+ //to overlap
+ if ( params()->userWidth() != 0 ) {
+ int userwidth = 0;
+ if ( params()->userWidth() < 0 )
+ userwidth = static_cast <int> (params()->userWidth() * -areaWidthP1000);
+ else
+ userwidth = static_cast <int> (params()->userWidth() * areaWidthP1000);
+ //if ( userwidth < frontBarWidth ) {
+ rect.setLeft( static_cast <int> (rect.center().x() - (userwidth/2)));
+ rect.setRight( static_cast <int> (rect.center().x() + (userwidth/2)));
+ rect.setWidth( static_cast <int> (userwidth) );
+ //adjust the front rect
+ frontRectPositive.setLeft( tooHigh ? static_cast <int> (excessRectPositive.center().x() - (userwidth/2)):rect.left());
+ frontRectPositive.setRight( tooHigh ? static_cast <int> (excessRectPositive.center().x() + (userwidth/2)):rect.right());
+ }
+
+ // drawing the front side
+ if (!tooHigh && !tooLow || params()->barChartSubType() == KDChartParams::BarPercent ) {
+ if ( bMultiRows )
+ painter->setClipping( false );
+ else
+ painter->setClipping( true );
+ painter->drawRect( rect );
+ }
+ // Don't use rect for drawing after this
+ if ( pointArrayList ) {
+ rect.moveBy( _dataRect.x(), _dataRect.y());
+ pointArrayList->append( rectToPointArray( rect ) );
+ }
+ }
+ } // bShowThisBar
+ } // positive values
+ }
+ if ( bShowThisBar && _bThreeDBars && !bDrawExtraLines ) {
+ //Pending Michel: no need to use that anymore
+ //const int maxY = 2*devRect.height();
+ QPointArray points( 4 );
+ if (cellValue <= 0 || cellValue < minColumnValue) {
+ if ( tooLow || cellValue < minColumnValue ) {
+ points.setPoint(0, excessRectNegative.topRight());
+ points.setPoint(1, excessRectNegative.topRight().x() + static_cast<int>(sideBarHeight),
+ excessRectNegative.top() - static_cast<int>(sideBarHeight));
+ points.setPoint(2, excessRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
+ excessRectNegative.bottom() - static_cast<int>(sideBarHeight));
+ points.setPoint(3, excessRectNegative.bottomRight());
+ } else {
+ points.setPoint( 0, frontRectNegative.bottomRight());
+ points.setPoint( 1, frontRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
+ frontRectNegative.bottom() - static_cast<int>(sideBarHeight) );
+ points.setPoint(2, frontRectNegative.bottomRight().x() + static_cast<int>(sideBarHeight),
+ frontRectNegative.top() - static_cast<int>(sideBarHeight));
+ points.setPoint(3, frontRectNegative.topRight() );
+ }
+
+ rightRectNegative.setTopLeft( points.point(0));
+ rightRectNegative.setTopRight( points.point(2));
+ rightRectNegative.setBottomRight(points.point(1));
+ rightRectNegative.setBottomLeft(points.point(3));
+
+ } else {
+ // Pending Michel
+ // Make sure to align the right side top and bottom points
+ // to the front side points
+ if ( tooHigh ) {
+ points.setPoint(0, excessRectPositive.topRight());
+ points.setPoint(1, excessRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
+ excessRectPositive.top() - static_cast <int> (sideBarHeight) );
+ points.setPoint(2, excessRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
+ excessRectPositive.bottom() - static_cast <int> (sideBarHeight));
+ points.setPoint(3, excessRectPositive.bottomRight());
+ } else {
+ points.setPoint(0, frontRectPositive.topRight());
+ points.setPoint(1, frontRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
+ frontRectPositive.top() - static_cast<int>(sideBarHeight));
+ points.setPoint(2, frontRectPositive.bottomRight().x() + static_cast <int> (sideBarHeight),
+ frontRectPositive.bottom() - static_cast<int>(sideBarHeight));
+ points.setPoint(3, frontRectPositive.bottomRight());
+ }
+ //register the right rect
+ rightRectPositive.setTopLeft( points.point(0));
+ rightRectPositive.setTopRight( points.point(1));
+ rightRectPositive.setBottomLeft( points.point(3));
+ rightRectPositive.setBottomRight(points.point(2));
+ }
+
+ if ( myShadow2Color.isValid() )
+ painter->setBrush( QBrush( myShadow2Color, params()->shadowPattern() ) );
+ else
+ painter->setBrush( NoBrush );
+
+ //debug points and lines
+ /*
+ painter->drawText( points.point(0), "0r");
+ painter->drawText( points.point(1), "1r");
+ painter->drawText( points.point(2), "2r");
+ painter->drawText( points.point(3), "3r");
+
+ painter->drawLine( points.point(0), points.point(1));
+ painter->drawLine( points.point(1), points.point(2));
+ painter->drawLine( points.point(2), points.point(3));
+ painter->drawLine( points.point(3), points.point(0));
+ */
+
+ //drawing the right side
+ if( (!tooHigh && !tooLow) || (tooHigh && cellValue <= 0 ) ) {
+ if (( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarPercent ) ||
+ ( cellValue != 0 && params()->barChartSubType() == KDChartParams::BarStacked ) ||
+ ( cellValue != 0 && bNormalMode ||
+ cellValue != 0 && bMultiRows)) {
+ painter->setClipping( false );
+ painter->drawPolygon( points );
+ }
+ }
+
+ // Dont override the region stored in case of excess values or barPercent this in order to display
+ // the value labels closer to the corner of the front bar.
+ if ( pointArrayList && !tooHigh && !tooLow && params()->barChartSubType() != KDChartParams::BarPercent ) {
+ QPointArray points2cpy( points.copy() );
+ //qDebug("g2");
+ points2cpy.translate( _dataRect.x(), _dataRect.y());
+ //qDebug("g3");
+ pointArrayList->append( points2cpy );
+ //qDebug("g4");
+ }
+
+ // drawing the top, but only for the topmost piece for stacked and percent
+ if ( bNormalMode || bMultiRows ||
+ // For stacked and percent bars, there are three ways to determine
+ // the top:
+ // 1. all values are negative: the top is the one in the first dataset
+ ( maxValueInThisColumn <= 0.0 && dataset == firstValidValue ) ||
+ // 2. all values are positive: the top is the one in the last dataset
+ ( minValueInThisColumn >= 0.0 && dataset == lastValidPositiveValue ) ||
+ // 3. some values are positive, some negative:
+ // the top is the one in the last positive
+ // dataset value
+ ( dataset == lastValidPositiveValue ) ) {
+ if (cellValue <= 0 || cellValue < minColumnValue) {
+ if ( tooLow ) {
+ points.setPoint(0,excessRectNegative.bottomLeft());
+ points.setPoint(1,excessRectNegative.topLeft().x() + static_cast <int> (sideBarHeight),
+ excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
+ points.setPoint(2,excessRectNegative.bottomRight().x() + static_cast <int> (sideBarHeight),
+ excessRectNegative.bottom() - static_cast <int> (sideBarHeight));
+ points.setPoint(3,excessRectNegative.bottomRight());
+ }else {
+ // Align the top to the front and the right side
+ points.setPoint(0,frontRectNegative.topLeft() );
+ points.setPoint(1,frontRectNegative.topLeft().x() + static_cast <int> (sideBarHeight), rightRectNegative.top());
+ points.setPoint(2,rightRectNegative.topRight() );
+ points.setPoint(3,rightRectNegative.topRight().x() - static_cast <int> (sideBarHeight),
+ frontRectNegative.topRight().y() );
+ //make sure the top rect color is the right one - barStacked - Noll values
+ if ( (params()->barChartSubType() == KDChartParams::BarStacked && cellValue == 0 && maxValueInThisColumn != 0 ) )
+ points.translate(0, maxValueInThisColumn <= 0?-(static_cast <int> (1*pixelsPerUnit) + 1):
+ -static_cast<int>(maxValueInThisColumn*pixelsPerUnit));
+
+ if ( params()->barChartSubType() == KDChartParams::BarPercent && cellValue == 0 ) {
+ if ( dataset == datasetEnd && maxValueInThisColumn != 0)
+ points.translate(0, -static_cast<int>( logHeight - sideBarHeight ));
+ else if ( maxValueInThisColumn == 0)
+ points.translate(0, static_cast <int> (logHeight + (sideBarHeight - sideBarWidth)));
+ }
+ }
+ } else {
+ if ( tooHigh ) {
+ points.setPoint(0, excessRectPositive.topLeft());
+ points.setPoint(1, excessRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
+ excessRectPositive.top() - static_cast <int> (sideBarHeight) );
+ points.setPoint(2, excessRectPositive.topRight().x() + static_cast <int> (sideBarHeight),
+ excessRectPositive.top() - static_cast <int> (sideBarHeight));
+ points.setPoint(3, excessRectPositive.topRight());
+ } else {
+ // Pending Michel
+ // Align the top to the front and the right side
+ points.setPoint(0, frontRectPositive.topLeft());
+ points.setPoint(1, frontRectPositive.topLeft().x() + static_cast <int> (sideBarHeight),
+ rightRectPositive.top() );
+ points.setPoint(2, rightRectPositive.topRight());
+ points.setPoint(3, rightRectPositive.topRight().x() - static_cast <int> (sideBarHeight),
+ frontRectPositive.topRight().y());
+ }
+ }
+
+ if (cellValue < 0.0 && maxValueInThisColumn < 0)
+ painter->setBrush( bMultiRows ? myBarColor : black );
+ else
+ painter->setBrush( QBrush( myShadow1Color, params()->shadowPattern() ) );
+
+ if ( !myShadow1Color.isValid() )
+ painter->setBrush( NoBrush ); // override prev. setting
+ // debug points and lines
+ /*
+ painter->drawText( points.point(0), "0t");
+ painter->drawText( points.point(1), "1t");
+ painter->drawText( points.point(2), "2t");
+ painter->drawText( points.point(3), "3t");
+
+ painter->drawLine( points.point(0), points.point(1) );
+ painter->drawLine( points.point(1),points.point(2) );
+ painter->drawLine( points.point(2),points.point(3) );
+ painter->drawLine( points.point(3),points.point(0) );
+ */
+
+ // drawing the top side
+ if (!tooHigh && !tooLow || (tooHigh && cellValue <= 0) )
+ painter->drawPolygon( points );
+
+ // dont override the region stored in case of excess values.
+ if (pointArrayList && !tooHigh && !tooLow
+ && params()->barChartSubType() != KDChartParams::BarPercent
+ && params()->barChartSubType() != KDChartParams::BarStacked) {
+ points.translate( _dataRect.x(), _dataRect.y());
+ pointArrayList->append( points );
+ }
+ }
+ }//if ( _bThreeDBars )
+
+ if( regions && pointArrayList && ! pointArrayList->empty() ) {
+ if( bShowThisBar && !bDrawExtraLines ){
+ KDChartDataRegion * region;
+ if( _bThreeDBars ){
+ region = new KDChartDataRegion( dataset, value, chart,
+ pointArrayList, true );
+ } else {
+ // just store a rectangle if NOT in 3-D bar mode
+ region = new KDChartDataRegion( dataset, value, chart,
+ pointArrayList->first().boundingRect() );
+ delete pointArrayList;
+ }
+ /*qDebug("KDChartDataRegion stored! x: %i y: %i w: %i h: %i",
+ region->rect().x(),region->rect().y(),
+ region->rect().width(),region->rect().height());*/
+ regions->append( region );
+ } else {
+ delete pointArrayList;
+ }
+ }
+ }// if( !bDrawExtraLines || bCellPropertiesFound )
+ }// if( !skipMe )
+ }else{
+ // Do not paint a bar, but update the position
+ // variable: to find the exact x1 position for
+ // the next bar that will be drawn.
+ int iDummy1, iDummy2;
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ iDummy1, iDummy2, prevFrontX2 );
+ }// if( dataset >= datasetStart && dataset <= datasetEnd )
+
+ // Vertical advancement in stacked or percent only if there was a value
+ // Pending Michel add sideBarHeight in case we are in 3D mode but not for Percent
+ // where we need to display the top rect but cant resize the YAxis.
+ if ( params()->barChartSubType() == KDChartParams::BarStacked ||
+ params()->barChartSubType() == KDChartParams::BarPercent )
+ if ( /*barHeight*/ cellValue < 0 )
+ (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposNegatives -= sideBarHeight + barHeight:
+ yposNegatives -= barHeight;
+ else
+ (_bThreeDBars && params()->barChartSubType() != KDChartParams::BarPercent)?yposPositives -= sideBarHeight + barHeight:
+ yposPositives -= barHeight;
+
+ } else {
+ // Do not paint a bar, but update the position
+ // variable: to find the exact x1 position for
+ // the next bar that will be drawn.
+ int iDummy1, iDummy2;
+ calculateXFront1_2( bNormalMode, bIsVeryFirstBar, bIsFirstDataset, _bThreeDBars,
+ xpos, valueBlockGap, datasetGap, frontBarWidth,
+ iDummy1, iDummy2, prevFrontX2 );
+ }
+
+
+ // advance only if the next dataset has DataEntry mode
+ bool bAdvanceToNextValue =
+ ( bMultiRows ? (dataset == chartDatasetStart) : (dataset == chartDatasetEnd)
+ || ( params()->chartSourceMode( bMultiRows ? dataset-1 : dataset+1 )
+ == KDChartParams::DataEntry ) );
+ // Advance to next value; only for normal bars
+ if ( bNormalMode ) {
+ if( bAdvanceToNextValue )
+ xpos += barWidth;
+ // skip gap between datasets, unless last dataset
+ if ( dataset < myLastDataEntryDataset )
+ xpos += datasetGap;
+ }
+ if( bAdvanceToNextValue || bMultiRows ){
+ //qDebug("shiftMyPainter( -nShiftX, nShiftY );");
+ shiftMyPainter( -nShiftX, nShiftY );
+ }
+ bIsVeryFirstBar = false;
+ bIsFirstDataset = false;
+ }
+
+
+ // Advancement between value blocks
+ if ( bNormalMode ){
+ // skip gap between value blocks, don't worry about last one here
+ xpos += valueBlockGap;
+ //qDebug("**************************** xpos: %f + valueBlockGap: %f = %f", xpos, valueBlockGap, xpos+valueBlockGap);
+ }else{
+ // skip gap between value blocks
+ xpos += valueBlockGap + barWidth;
+ //qDebug ( "2/ barWidth %f", barWidth );
+ //qDebug ( " valueBlockGap %f", valueBlockGap );
+ // start at bottom with next value group
+ yposPositives = yposPositivesStart;
+ yposNegatives = yposNegativesStart;
+ }
+ //qDebug("shiftMyPainterBack");
+ shiftMyPainterBack();
+ }
+
+ }
+
+
+ if( bMultiRows )
+ painter->setClipping( bHadClipping );
+}