File indexing completed on 2024-12-15 04:02:28
0001 /* 0002 * SPDX-FileCopyrightText: 2001-2015 Klaralvdalens Datakonsult AB. All rights reserved. 0003 * 0004 * This file is part of the KD Chart library. 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "KChartBarDiagram_p.h" 0010 0011 #include "KChartDataValueAttributes.h" 0012 #include "KChartPainterSaver_p.h" 0013 0014 using namespace KChart; 0015 0016 BarDiagram::Private::Private( const Private& rhs ) 0017 : AbstractCartesianDiagram::Private( rhs ) 0018 { 0019 } 0020 0021 void BarDiagram::BarDiagramType::paintBars( PaintContext* ctx, const QModelIndex& index, const QRectF& bar, qreal maxDepth ) 0022 { 0023 PainterSaver painterSaver( ctx->painter() ); 0024 0025 //Pending Michel: configure threeDBrush settings - shadowColor etc... 0026 QBrush indexBrush( diagram()->brush( index ) ); 0027 QPen indexPen( diagram()->pen( index ) ); 0028 0029 ctx->painter()->setRenderHint( QPainter::Antialiasing, diagram()->antiAliasing() ); 0030 ThreeDBarAttributes threeDAttrs = diagram()->threeDBarAttributes( index ); 0031 if ( threeDAttrs.isEnabled() ) { 0032 indexBrush = threeDAttrs.threeDBrush( indexBrush, bar ); 0033 } 0034 ctx->painter()->setBrush( indexBrush ); 0035 ctx->painter()->setPen( PrintingParameters::scalePen( indexPen ) ); 0036 0037 if ( threeDAttrs.isEnabled() ) { 0038 if ( maxDepth ) { 0039 threeDAttrs.setDepth( -maxDepth ); 0040 } 0041 //fixme adjust the painting to reasonable depth value 0042 const qreal usedDepth = threeDAttrs.depth() * ( type() == BarDiagram::Normal ? 0.25 : 1.0 ); 0043 0044 const QRectF isoRect = bar.translated( usedDepth, -usedDepth ); 0045 // we need to find out if the height is negative 0046 // and in this case paint it up and down 0047 QPolygonF topPoints; 0048 if ( isoRect.height() < 0 ) { 0049 if ( !( type() == BarDiagram::Stacked && index.column() != 0 ) ) { 0050 // fix it when several negative stacked values 0051 topPoints << isoRect.bottomLeft() << isoRect.bottomRight() 0052 << bar.bottomRight() << bar.bottomLeft(); 0053 } 0054 } else { 0055 reverseMapper().addRect( index.row(), index.column(), isoRect ); 0056 ctx->painter()->drawRect( isoRect ); 0057 if ( !( type() == BarDiagram::Percent && isoRect.height() == 0 ) ) { 0058 topPoints << bar.topLeft() << bar.topRight() << isoRect.topRight() << isoRect.topLeft(); 0059 } 0060 } 0061 0062 bool noClippingForTop = false; 0063 if ( !topPoints.isEmpty() ) { 0064 // Draw the top, if at least one of the top's points is 0065 // either inside or near at the edge of the coordinate plane: 0066 bool drawIt = false; 0067 bool hasPointOutside = false; 0068 const QRectF r( ctx->rectangle().adjusted( 0, -1, 1, 0 ) ); 0069 for ( QPointF pt : qAsConst(topPoints) ) { 0070 if ( r.contains( pt ) ) { 0071 drawIt = true; 0072 } else { 0073 hasPointOutside = true; 0074 } 0075 } 0076 if ( drawIt ) { 0077 const PainterSaver p( ctx->painter() ); 0078 noClippingForTop = hasPointOutside && ctx->painter()->hasClipping(); 0079 if ( noClippingForTop ) { 0080 ctx->painter()->setClipping( false ); 0081 } 0082 reverseMapper().addPolygon( index.row(), index.column(), topPoints ); 0083 ctx->painter()->drawPolygon( topPoints ); 0084 } 0085 } 0086 0087 if ( bar.height() != 0 ) { 0088 const PainterSaver p( ctx->painter() ); 0089 if ( noClippingForTop ) { 0090 ctx->painter()->setClipping( false ); 0091 } 0092 QPolygonF sidePoints; 0093 sidePoints << bar.topRight() << isoRect.topRight() 0094 << isoRect.bottomRight() << bar.bottomRight(); 0095 reverseMapper().addPolygon( index.row(), index.column(), sidePoints ); 0096 ctx->painter()->drawPolygon( sidePoints ); 0097 } 0098 } 0099 0100 if ( bar.height() != 0 ) { 0101 reverseMapper().addRect( index.row(), index.column(), bar ); 0102 ctx->painter()->drawRect( bar ); 0103 } 0104 } 0105 0106 AttributesModel* BarDiagram::BarDiagramType::attributesModel() const 0107 { 0108 return m_private->attributesModel; 0109 } 0110 0111 QModelIndex BarDiagram::BarDiagramType::attributesModelRootIndex() const 0112 { 0113 return diagram()->attributesModelRootIndex(); 0114 } 0115 0116 BarDiagram* BarDiagram::BarDiagramType::diagram() const 0117 { 0118 return static_cast< BarDiagram* >( m_private->diagram ); 0119 } 0120 0121 void BarDiagram::BarDiagramType::calculateValueAndGapWidths( int rowCount, int colCount, 0122 qreal groupWidth, 0123 qreal& outBarWidth, 0124 qreal& outSpaceBetweenBars, 0125 qreal& outSpaceBetweenGroups ) 0126 { 0127 0128 Q_UNUSED( rowCount ); 0129 BarAttributes ba = diagram()->barAttributes(); 0130 0131 // Pending Michel Fixme 0132 /* We are colCount groups to paint. Each group is centered around the 0133 * horizontal point position on the grid. The full area covers the 0134 * values -1 to colCount + 1. A bar has a relative width of one unit, 0135 * the gaps between bars are 0.5 wide, and the gap between groups is 0136 * also one unit, by default. */ 0137 0138 qreal units; 0139 if ( type() == Normal ) { 0140 units = colCount // number of bars in group * 1.0 0141 + (colCount-1) * ba.barGapFactor() // number of bar gaps 0142 + 1 * ba.groupGapFactor(); // number of group gaps 0143 } else { 0144 units = 1 + 1 * ba.groupGapFactor(); 0145 } 0146 0147 qreal unitWidth = groupWidth / units; 0148 0149 if ( !ba.useFixedBarWidth() ) { 0150 outBarWidth = unitWidth; 0151 } 0152 0153 outSpaceBetweenBars += unitWidth * ba.barGapFactor(); 0154 0155 // Pending Michel - minLimit: allow space between bars to be reduced until the bars are displayed next to each other. 0156 // is that what we want? 0157 // sebsauer; in the case e.g. CartesianCoordinatePlane::setHorizontalRangeReversed(true) was 0158 // used to reverse the values, we deal with negative outSpaceBetweenBars and unitWidth here 0159 // and since that's correct we don't like to lose e.g. the spacing here. 0160 //if ( outSpaceBetweenBars < 0 ) 0161 // outSpaceBetweenBars = 0; 0162 0163 outSpaceBetweenGroups += unitWidth * ba.groupGapFactor(); 0164 } 0165 0166 ReverseMapper& BarDiagram::BarDiagramType::reverseMapper() 0167 { 0168 return m_private->reverseMapper; 0169 } 0170 0171 CartesianDiagramDataCompressor& BarDiagram::BarDiagramType::compressor() const 0172 { 0173 return m_private->compressor; 0174 }