File indexing completed on 2024-06-16 04:09:13

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 #ifndef KCHARTPIEDIAGRAM_H
0010 #define KCHARTPIEDIAGRAM_H
0011 
0012 #include "KChartAbstractPieDiagram.h"
0013 
0014 namespace KChart {
0015 
0016     class LabelPaintCache;
0017 
0018 /**
0019   * @brief PieDiagram defines a common pie diagram
0020   */
0021 class KCHART_EXPORT PieDiagram : public AbstractPieDiagram
0022 {
0023     Q_OBJECT
0024 
0025     Q_DISABLE_COPY( PieDiagram )
0026     KCHART_DECLARE_DERIVED_DIAGRAM( PieDiagram, PolarCoordinatePlane )
0027 
0028 public:
0029     explicit PieDiagram(
0030         QWidget* parent = nullptr, PolarCoordinatePlane* plane = nullptr );
0031     ~PieDiagram() override;
0032 
0033 protected:
0034     // Implement AbstractDiagram
0035     /** \reimpl */
0036     void paint( PaintContext* paintContext ) override;
0037 
0038 public:
0039     /**
0040      * Describes which decorations are painted around data labels.
0041      */
0042     enum LabelDecoration {
0043         NoDecoration = 0, ///< No decoration
0044         FrameDecoration = 1, ///< A rectangular frame is painted around the label text
0045         LineFromSliceDecoration = 2 ///< A line is drawn from the pie slice to its label
0046     };
0047     Q_DECLARE_FLAGS( LabelDecorations, LabelDecoration )
0048     /// Set the decorations to be painted around data labels according to @p decorations.
0049     void setLabelDecorations( LabelDecorations decorations );
0050     /// Return the decorations to be painted around data labels.
0051     LabelDecorations labelDecorations() const;
0052 
0053     /// If @p enabled is set to true, labels that would overlap will be shuffled to avoid overlap.
0054     /// \note Collision avoidance may allow labels to be closer than AbstractDiagram with
0055     ///       allowOverlappingDataValueTexts() == false, so you should usually also call
0056     ///       setAllowOverlappingDataValueTexts( true ) if you enable this feature.
0057     void setLabelCollisionAvoidanceEnabled( bool enabled );
0058     /// Return whether overlapping labels will be moved to until they don't overlap anymore.
0059     bool isLabelCollisionAvoidanceEnabled() const;
0060 
0061     /** \reimpl */
0062     void resize ( const QSizeF& area ) override;
0063 
0064     // Implement AbstractPolarDiagram
0065     /** \reimpl */
0066     qreal valueTotals () const override;
0067     /** \reimpl */
0068     qreal numberOfValuesPerDataset() const override;
0069     /** \reimpl */
0070     qreal numberOfGridRings() const override;
0071 
0072 
0073     /**
0074       * Creates an exact copy of this diagram.
0075       */
0076    virtual PieDiagram * clone() const;
0077 
0078 protected:
0079     /** \reimpl */
0080     const QPair<QPointF, QPointF> calculateDataBoundaries() const override;
0081     void paintEvent( QPaintEvent* ) override;
0082     void resizeEvent( QResizeEvent* ) override;
0083 
0084 private:
0085     // ### move to private class?
0086     void placeLabels( PaintContext* paintContext );
0087     // Solve problems with label overlap by changing label positions inside d->labelPaintCache.
0088     void shuffleLabels( QRectF* textBoundingRect );
0089     void paintInternal( PaintContext* paintContext );
0090 
0091     /**
0092       Internal method that draws one of the slices in a pie chart.
0093 
0094       \param painter the QPainter to draw in
0095       \param dataset the dataset to draw the pie for
0096       \param slice the slice to draw
0097       \param threeDPieHeight the height of the three dimensional effect
0098       */
0099     void drawSlice( QPainter* painter, const QRectF& drawPosition, uint slice );
0100 
0101     /**
0102       Internal method that draws the surface of one of the slices in a pie chart.
0103 
0104       \param painter the QPainter to draw in
0105       \param dataset the dataset to draw the slice for
0106       \param slice the slice to draw
0107       */
0108     void drawSliceSurface( QPainter* painter, const QRectF& drawPosition, uint slice );
0109     void addSliceLabel( LabelPaintCache* lpc, const QRectF& drawPosition, uint slice );
0110 
0111     /**
0112       Internal method that draws the shadow creating the 3D effect of a pie
0113 
0114       \param painter the QPainter to draw in
0115       \param drawPosition the position to draw at
0116       \param slice the slice to draw the shadow for
0117       */
0118     void draw3DEffect( QPainter* painter, const QRectF& drawPosition, uint slice );
0119 
0120     /**
0121       Internal method that draws the cut surface of a slice (think of a real pie cut into slices)
0122       in 3D mode, for surfaces that are facing the observer.
0123 
0124       \param painter the QPainter to draw in
0125       \param rect the position to draw at
0126       \param threeDHeight the height of the shadow
0127       \param angle the angle of the segment
0128       */
0129     void draw3dCutSurface( QPainter* painter,
0130         const QRectF& rect,
0131         qreal threeDHeight,
0132         qreal angle );
0133 
0134     /**
0135       Internal method that draws the outer rim of a slice when the rim is facing the observer.
0136 
0137       \param painter the QPainter to draw in
0138       \param rect the position to draw at
0139       \param threeDHeight the height of the shadow
0140       \param startAngle the starting angle of the segment
0141       \param endAngle the ending angle of the segment
0142       */
0143     void draw3dOuterRim( QPainter* painter,
0144         const QRectF& rect,
0145         qreal threeDHeight,
0146         qreal startAngle,
0147         qreal endAngle );
0148     void calcSliceAngles();
0149     void calcPieSize( const QRectF &contentsRect );
0150     QRectF twoDPieRect( const QRectF &contentsRect, const ThreeDPieAttributes& threeDAttrs ) const;
0151     QRectF explodedDrawPosition( const QRectF& drawPosition, uint slice ) const;
0152 
0153     /**
0154       Internal method that finds the slice that is located at the position specified by \c angle.
0155 
0156       \param angle the angle at which to search for a slice
0157       \return the number of the slice found
0158       */
0159     uint findSliceAt( qreal angle, int columnCount );
0160 
0161     /**
0162       Internal method that finds the slice that is located to the left of \c slice.
0163 
0164       \param slice the slice to start the search from
0165       \return the number of the pie to the left of \c pie
0166       */
0167     uint findLeftSlice( uint slice, int columnCount );
0168 
0169     /**
0170       Internal method that finds the slice that is located to the right of \c slice.
0171 
0172       \param slice the slice to start the search from
0173       \return the number of the slice to the right of \c slice
0174       */
0175     uint findRightSlice( uint slice, int columnCount );
0176 
0177     /**
0178       * Auxiliary method returning a point to a given boundary
0179       * rectangle of the enclosed ellipse and an angle.
0180       */
0181     QPointF pointOnEllipse( const QRectF& boundingBox, qreal angle );
0182 }; // End of class KChartPieDiagram
0183 
0184 Q_DECLARE_OPERATORS_FOR_FLAGS( PieDiagram::LabelDecorations )
0185 
0186 }
0187 #endif // KCHARTPIEDIAGRAM_H