File indexing completed on 2024-12-15 04:02:36

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 "KChartTernaryAxis.h"
0010 
0011 #include <QPainter>
0012 
0013 #include <KChartChart.h>
0014 #include <KChartPaintContext.h>
0015 
0016 #include "TernaryConstants.h"
0017 #include "KChartTernaryCoordinatePlane.h"
0018 #include "KChartAbstractTernaryDiagram.h"
0019 
0020 
0021 #include "KChartLayoutItems.h"
0022 #include "KChartTextLabelCache.h"
0023 
0024 using namespace KChart;
0025 
0026 // m_label and m_fifty do not have to be pointers, once the class is
0027 // pimpled (PrerenderedLabel is not published API)
0028 
0029 TernaryAxis::TernaryAxis ( AbstractTernaryDiagram* diagram)
0030     : AbstractAxis( diagram )
0031     , m_position( KChartEnums::PositionUnknown )
0032     , m_label( new PrerenderedLabel )
0033     , m_fifty( new PrerenderedLabel )
0034 {
0035     resetTitleTextAttributes();
0036     setPosition( KChartEnums::PositionSouth ); // arbitrary
0037     m_fifty->setText( QObject::tr( "50%" ) ); // const
0038     // FIXME is this consistent with other diagram/axis/plane implementations?
0039     diagram->addAxis( this );
0040 }
0041 
0042 TernaryAxis::~TernaryAxis()
0043 {
0044     delete m_label; m_label = nullptr;
0045     delete m_fifty; m_fifty = nullptr;
0046 }
0047 
0048 void  TernaryAxis::paintAll (QPainter &)
0049 {
0050     // not used
0051 }
0052 
0053 void  TernaryAxis::paint (QPainter *)
0054 {
0055     // not used
0056 }
0057 
0058 void  TernaryAxis::paintCtx (PaintContext * paintContext)
0059 {
0060     QPainter* p = paintContext->painter();
0061     TernaryCoordinatePlane* plane =
0062         (TernaryCoordinatePlane*) paintContext->coordinatePlane();
0063     // QObject* refArea = plane->parent();
0064 
0065     // paint the axis label (across the triangle, that one):
0066     QList<PrerenderedLabel*> labels;
0067     labels << m_label << m_fifty;
0068     for ( PrerenderedLabel* label : qAsConst(labels) ) {
0069         const QPixmap& pixmap = label->pixmap();
0070         const QPointF point = plane->translate( label->position() )
0071                         - label->referencePointLocation();
0072         p->drawPixmap( point, pixmap );
0073     }
0074 }
0075 
0076 bool TernaryAxis::isEmpty() const
0077 {
0078     // todo: what's this method for?
0079     return false;
0080 }
0081 
0082 QRect TernaryAxis::geometry () const
0083 {
0084     return m_geometry;
0085 }
0086 
0087 void TernaryAxis::setGeometry (const QRect &rect)
0088 {
0089     m_geometry = rect;
0090 }
0091 
0092 QSize  TernaryAxis::minimumSize () const
0093 {
0094     // todo: return realistic sizes
0095     return QSize( 100, 100 );
0096 }
0097 
0098 QSize  TernaryAxis::maximumSize () const
0099 {
0100     return QSize( 300, 200 );
0101 }
0102 
0103 QSize  TernaryAxis::sizeHint () const
0104 {
0105     return QSize( 150, 100 );
0106 }
0107 
0108 Qt::Orientations TernaryAxis::expandingDirections () const
0109 {
0110     return Qt::Vertical | Qt::Horizontal;
0111 }
0112 
0113 const Position TernaryAxis::position () const
0114 {
0115     return m_position;
0116 }
0117 
0118 void  TernaryAxis::setPosition (Position p)
0119 {
0120     if ( p == position() ) return;
0121 
0122     if ( p != KChartEnums::PositionWest
0123          && p != KChartEnums::PositionEast
0124          && p != KChartEnums::PositionSouth )
0125     {
0126         qDebug() << "TernaryAxis::setPosition: only south, east and west are supported "
0127             "positions for ternary axes.";
0128         return;
0129     }
0130 
0131     if ( m_title.isEmpty() )
0132         switch ( p.value() ) {
0133         case KChartEnums::PositionSouth:
0134             m_label->setText( tr( "A" ) );
0135             break;
0136         case KChartEnums::PositionWest:
0137             m_label->setText( tr( "C" ) );
0138             break;
0139         case KChartEnums::PositionEast:
0140             m_label->setText( tr( "B" ) );
0141             break;
0142         default:
0143             break;
0144         }
0145 
0146     m_position = p;
0147     updatePrerenderedLabels(); // position has changed
0148 }
0149 
0150 void TernaryAxis::setTitleText( const QString& text )
0151 {
0152     m_title = text; // do not remove
0153     m_label->setText( text );
0154 }
0155 
0156 QString TernaryAxis::titleText() const
0157 {
0158     return m_label->text();
0159 }
0160 
0161 void TernaryAxis::setTitleTextAttributes( const TextAttributes &a )
0162 {
0163     m_titleAttributes = a;
0164     updatePrerenderedLabels();
0165 }
0166 
0167 TextAttributes TernaryAxis::titleTextAttributes() const
0168 {
0169     return m_titleAttributes;
0170 }
0171 
0172 void TernaryAxis::resetTitleTextAttributes()
0173 {
0174     TextAttributes a;
0175     m_titleAttributes = a;
0176     updatePrerenderedLabels();
0177 }
0178 
0179 bool TernaryAxis::hasDefaultTitleTextAttributes() const
0180 {
0181     TextAttributes a;
0182     return m_titleAttributes == a;
0183 }
0184 
0185 void TernaryAxis::updatePrerenderedLabels()
0186 {
0187     TextAttributes attributes = titleTextAttributes();
0188     qreal axisLabelAngle = 0.0;
0189     qreal fiftyMarkAngle = 0.0;
0190     QPointF axisLabelPosition;
0191     QPointF fiftyMarkPosition;
0192     KChartEnums::PositionValue fiftyMarkReferencePoint = KChartEnums::PositionUnknown;
0193 
0194     switch ( position().value() ) {
0195     case KChartEnums::PositionSouth:
0196         // this is the axis on the other side of A
0197         axisLabelAngle = 0.0;
0198         fiftyMarkAngle = 0.0;
0199         axisLabelPosition = TriangleTop;
0200         fiftyMarkPosition = 0.5 * AxisVector_B_C - RelMarkerLength * Norm_B_C;
0201         fiftyMarkReferencePoint = KChartEnums::PositionNorth;
0202         break;
0203     case KChartEnums::PositionEast:
0204         // this is the axis on the other side of B
0205         axisLabelAngle = 240.0;
0206         fiftyMarkAngle = 60;
0207         axisLabelPosition = TriangleBottomLeft;
0208         fiftyMarkPosition = AxisVector_B_C + 0.5 * AxisVector_C_A - RelMarkerLength * Norm_C_A;
0209         fiftyMarkReferencePoint = KChartEnums::PositionSouth;
0210         break;
0211     case KChartEnums::PositionWest:
0212         // this is the axis on the other side of C
0213         axisLabelAngle = 120.0;
0214         fiftyMarkAngle = 300.0;
0215         axisLabelPosition = TriangleBottomRight;
0216         fiftyMarkPosition = 0.5 * AxisVector_B_A + RelMarkerLength * Norm_B_A;
0217         fiftyMarkReferencePoint = KChartEnums::PositionSouth;
0218         break;
0219     case KChartEnums::PositionUnknown:
0220         break; // initial value
0221     default:
0222         qDebug() << "TernaryAxis::updatePrerenderedLabel: unknown location";
0223     };
0224 
0225     m_label->setFont( attributes.font() );
0226     // m_label->setText( titleText() ); // done by setTitleText()
0227     m_label->setAngle( axisLabelAngle );
0228     m_label->setPosition( axisLabelPosition );
0229     m_label->setReferencePoint( KChartEnums::PositionSouth );
0230     QFont font = attributes.font();
0231     font.setPointSizeF( 0.85 * font.pointSizeF() );
0232     m_fifty->setFont( font );
0233     m_fifty->setAngle( fiftyMarkAngle );
0234     m_fifty->setPosition( fiftyMarkPosition );
0235     m_fifty->setReferencePoint( fiftyMarkReferencePoint );
0236 }
0237 
0238 QPair<QSizeF, QSizeF> TernaryAxis::requiredMargins() const
0239 {
0240     QSizeF topleft( 0.0, 0.0 );
0241     QSizeF bottomRight( 0.0, 0.0 );
0242 
0243     switch ( position().value() ) {
0244     case KChartEnums::PositionSouth:
0245         // the label of the south axis is, in fact, up north.
0246         topleft.setHeight( m_label->pixmap().height() );
0247         bottomRight.setHeight( m_fifty->pixmap().height() );
0248         break;
0249     case KChartEnums::PositionWest:
0250         bottomRight.setWidth( m_label->pixmap().width()
0251                               - m_label->referencePointLocation().x() );
0252         bottomRight.setHeight( m_label->pixmap().height()
0253                                - m_label->referencePointLocation().y() );
0254         break;
0255     case KChartEnums::PositionEast:
0256         topleft.setWidth( m_label->pixmap().width()
0257                           - ( m_label->pixmap().width()
0258                               - m_label->referencePointLocation().x() ) );
0259         bottomRight.setHeight( m_label->pixmap().height()
0260                                - ( m_label->pixmap().height()
0261                                    - m_label->referencePointLocation().y() ) );
0262         break;
0263     default:
0264         qDebug() << "TernaryAxis::requiredMargins: unknown location";
0265     }
0266 //     qDebug() << "TernaryAxis::requiredMargins:" << topleft << bottomRight;
0267     return QPair<QSizeF, QSizeF>( topleft, bottomRight );
0268 }