/**************************************************************************** ** Copyright (C) 2001-2011 Klaralvdalens Datakonsult AB. All rights reserved. ** ** This file is part of the KD Chart library. ** ** Licensees holding valid commercial KD Chart licenses may use this file in ** accordance with the KD Chart Commercial License Agreement provided with ** the Software. ** ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 and version 3 as published by the ** Free Software Foundation and appearing in the file LICENSE.GPL.txt included. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** Contact info@kdab.com if any conditions of this licensing are not ** clear to you. ** **********************************************************************/ #include "KDChartBarDiagram.h" #include "KDChartDataValueAttributes.h" #include "KDChartBarDiagram_p.h" using namespace KDChart; BarDiagram::Private::Private( const Private& rhs ) : AbstractCartesianDiagram::Private( rhs ) { } void BarDiagram::BarDiagramType::paintBars( PaintContext* ctx, const QModelIndex& index, const QRectF& bar, double& maxDepth ) { QRectF isoRect; QPolygonF topPoints, sidePoints; ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index ); double usedDepth = 0; //Pending Michel: configure threeDBrush settings - shadowColor etc... QBrush indexBrush ( diagram()->brush( index ) ); QPen indexPen( diagram()->pen( index ) ); PainterSaver painterSaver( ctx->painter() ); if ( diagram()->antiAliasing() ) ctx->painter()->setRenderHint ( QPainter::Antialiasing ); ctx->painter()->setBrush( indexBrush ); ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) ); if ( threeDAttrs.isEnabled() ) { bool stackedMode = false; bool percentMode = false; bool paintTop = true; if ( maxDepth ) threeDAttrs.setDepth( -maxDepth ); QPointF boundRight = ctx->coordinatePlane()->translate( diagram()->dataBoundaries().second ); //fixme adjust the painting to reasonable depth value switch ( type() ) { case BarDiagram::Normal: usedDepth = threeDAttrs.depth()/4; stackedMode = false; percentMode = false; break; case BarDiagram::Stacked: usedDepth = threeDAttrs.depth(); stackedMode = true; percentMode = false; break; case BarDiagram::Percent: usedDepth = threeDAttrs.depth(); stackedMode = false; percentMode = true; break; default: Q_ASSERT_X ( false, "dataBoundaries()", "Type item does not match a defined bar chart Type." ); } isoRect = bar.translated( usedDepth, -usedDepth ); // we need to find out if the height is negative // and in this case paint it up and down //qDebug() << isoRect.height(); if ( isoRect.height() < 0 ) { topPoints << isoRect.bottomLeft() << isoRect.bottomRight() << bar.bottomRight() << bar.bottomLeft(); if ( stackedMode ) { // fix it when several negative stacked values if ( index.column() == 0 ) { paintTop = true; } else paintTop = false; } } else { reverseMapper().addRect( index.row(), index.column(), isoRect ); ctx->painter()->drawRect( isoRect ); topPoints << bar.topLeft() << bar.topRight() << isoRect.topRight() << isoRect.topLeft(); } if ( percentMode && isoRect.height() == 0 ) paintTop = false; bool needToSetClippingOffForTop = false; if ( paintTop ){ // Draw the top, if at least one of the top's points is // either inside or near at the edge of the coordinate plane: bool drawIt = false; bool hasPointOutside = false; const QRectF r( ctx->rectangle().adjusted(0,-1,1,0) ); KDAB_FOREACH( QPointF pt, topPoints ) { if( r.contains( pt ) ) drawIt = true; else hasPointOutside = true; } if( drawIt ){ const PainterSaver p( ctx->painter() ); needToSetClippingOffForTop = hasPointOutside && ctx->painter()->hasClipping(); if( needToSetClippingOffForTop ) ctx->painter()->setClipping( false ); reverseMapper().addPolygon( index.row(), index.column(), topPoints ); ctx->painter()->drawPolygon( topPoints ); } } sidePoints << bar.topRight() << isoRect.topRight() << isoRect.bottomRight() << bar.bottomRight(); if ( bar.height() != 0 ){ const PainterSaver p( ctx->painter() ); if( needToSetClippingOffForTop ) ctx->painter()->setClipping( false ); reverseMapper().addPolygon( index.row(), index.column(), sidePoints ); ctx->painter()->drawPolygon( sidePoints ); } } if( bar.height() != 0 ) { reverseMapper().addRect( index.row(), index.column(), bar ); ctx->painter()->drawRect( bar ); } // reset //diagram()->maxDepth = threeDAttrs.depth(); } AttributesModel* BarDiagram::BarDiagramType::attributesModel() const { return m_private->attributesModel; } QModelIndex BarDiagram::BarDiagramType::attributesModelRootIndex() const { return m_private->diagram->attributesModelRootIndex(); } BarDiagram* BarDiagram::BarDiagramType::diagram() const { return m_private->diagram; } void BarDiagram::BarDiagramType::appendDataValueTextInfoToList( AbstractDiagram * diagram, DataValueTextInfoList & list, const QModelIndex & index, const PositionPoints& points, const Position& autoPositionPositive, const Position& autoPositionNegative, const qreal value ) { m_private->appendDataValueTextInfoToList( diagram, list, index, 0, points, autoPositionPositive, autoPositionNegative, value ); } void BarDiagram::BarDiagramType::paintDataValueTextsAndMarkers( AbstractDiagram* diagram, PaintContext* ctx, const DataValueTextInfoList & list, bool paintMarkers ) { m_private->paintDataValueTextsAndMarkers( diagram, ctx, list, paintMarkers ); } void BarDiagram::BarDiagramType::calculateValueAndGapWidths( int rowCount,int colCount, double groupWidth, double& outBarWidth, double& outSpaceBetweenBars, double& outSpaceBetweenGroups ) { Q_UNUSED( rowCount ); BarAttributes ba = diagram()->barAttributes( diagram()->model()->index( 0, 0, diagram()->rootIndex() ) ); // Pending Michel Fixme /* We are colCount groups to paint. Each group is centered around the * horizontal point position on the grid. The full area covers the * values -1 to colCount + 1. A bar has a relative width of one unit, * the gaps between bars are 0.5 wide, and the gap between groups is * also one unit, by default. */ double units; if( type() == Normal ) units = colCount // number of bars in group * 1.0 + (colCount-1) * ba.barGapFactor() // number of bar gaps + 1 * ba.groupGapFactor(); // number of group gaps else units = 1 + 1 * ba.groupGapFactor(); double unitWidth = groupWidth / units; outBarWidth = unitWidth; outSpaceBetweenBars += unitWidth * ba.barGapFactor(); // Pending Michel - minLimit: allow space between bars to be reduced until the bars are displayed next to each other. // is that what we want? // sebsauer; in the case e.g. CartesianCoordinatePlane::setHorizontalRangeReversed(true) was // used to reverse the values, we deal with negative outSpaceBetweenBars and unitWidth here // and since that's correct we don't like to lose e.g. the spacing here. //if ( outSpaceBetweenBars < 0 ) // outSpaceBetweenBars = 0; outSpaceBetweenGroups += unitWidth * ba.groupGapFactor(); } ReverseMapper& BarDiagram::BarDiagramType::reverseMapper() { return m_private->reverseMapper; } CartesianDiagramDataCompressor& BarDiagram::BarDiagramType::compressor() const { return m_private->compressor; }