237 lines
8.7 KiB
C++
237 lines
8.7 KiB
C++
|
/****************************************************************************
|
||
|
** 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;
|
||
|
}
|