1 /*
2  * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
3  *
4  * This file is part of the KD Chart library.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "KChartAbstractAreaBase.h"
21 #include "KChartAbstractAreaBase_p.h"
22 
23 #include <KChartBackgroundAttributes.h>
24 #include <KChartFrameAttributes.h>
25 #include <KChartTextAttributes.h>
26 #include "KChartPainterSaver_p.h"
27 #include "KChartPrintingParameters.h"
28 #include "KChartMath_p.h"
29 
30 #include <QPainter>
31 #include <QPainterPath>
32 
33 
34 using namespace KChart;
35 
Private()36 AbstractAreaBase::Private::Private() :
37     visible( true )
38 {
39     init();
40 }
41 
42 
~Private()43 AbstractAreaBase::Private::~Private() {}
44 
45 
init()46 void AbstractAreaBase::Private::init()
47 {
48 }
49 
50 
AbstractAreaBase()51 AbstractAreaBase::AbstractAreaBase() :
52     _d( new Private() )
53 {
54 }
55 
~AbstractAreaBase()56 AbstractAreaBase::~AbstractAreaBase()
57 {
58     delete _d; _d = nullptr;
59 }
60 
61 
init()62 void AbstractAreaBase::init()
63 {
64 }
65 
66 
67 #define d d_func()
68 
compare(const AbstractAreaBase * other) const69 bool AbstractAreaBase::compare( const AbstractAreaBase* other ) const
70 {
71     if ( other == this ) return true;
72     if ( !other ) {
73         return false;
74     }
75     return  (frameAttributes()      == other->frameAttributes()) &&
76             (backgroundAttributes() == other->backgroundAttributes());
77 }
78 
alignToReferencePoint(const RelativePosition & position)79 void AbstractAreaBase::alignToReferencePoint( const RelativePosition& position )
80 {
81     Q_UNUSED( position );
82     // PENDING(kalle) FIXME
83     qWarning( "Sorry, not implemented: void AbstractAreaBase::alignToReferencePoint( const RelativePosition& position )" );
84 }
85 
setFrameAttributes(const FrameAttributes & a)86 void AbstractAreaBase::setFrameAttributes( const FrameAttributes &a )
87 {
88     if ( d->frameAttributes == a )
89         return;
90 
91     d->frameAttributes = a;
92     positionHasChanged();
93 }
94 
frameAttributes() const95 FrameAttributes AbstractAreaBase::frameAttributes() const
96 {
97     return d->frameAttributes;
98 }
99 
setBackgroundAttributes(const BackgroundAttributes & a)100 void AbstractAreaBase::setBackgroundAttributes( const BackgroundAttributes &a )
101 {
102     if ( d->backgroundAttributes == a )
103         return;
104 
105     d->backgroundAttributes = a;
106     positionHasChanged();
107 }
108 
backgroundAttributes() const109 BackgroundAttributes AbstractAreaBase::backgroundAttributes() const
110 {
111     return d->backgroundAttributes;
112 }
113 
114 
115 /* static */
paintBackgroundAttributes(QPainter & painter,const QRect & rect,const KChart::BackgroundAttributes & attributes)116 void AbstractAreaBase::paintBackgroundAttributes( QPainter& painter, const QRect& rect,
117     const KChart::BackgroundAttributes& attributes )
118 {
119     if ( !attributes.isVisible() ) return;
120 
121     /* first draw the brush (may contain a pixmap)*/
122     if ( Qt::NoBrush != attributes.brush().style() ) {
123         KChart::PainterSaver painterSaver( &painter );
124         painter.setPen( Qt::NoPen );
125         const QPointF newTopLeft( painter.deviceMatrix().map( rect.topLeft() ) );
126         painter.setBrushOrigin( newTopLeft );
127         painter.setBrush( attributes.brush() );
128         painter.drawRect( rect.adjusted( 0, 0, -1, -1 ) );
129     }
130     /* next draw the backPixmap over the brush */
131     if ( !attributes.pixmap().isNull() &&
132         attributes.pixmapMode() != BackgroundAttributes::BackgroundPixmapModeNone ) {
133         QPointF ol = rect.topLeft();
134         if ( BackgroundAttributes::BackgroundPixmapModeCentered == attributes.pixmapMode() )
135         {
136             ol.setX( rect.center().x() - attributes.pixmap().width() / 2 );
137             ol.setY( rect.center().y() - attributes.pixmap().height()/ 2 );
138             painter.drawPixmap( ol, attributes.pixmap() );
139         } else {
140             QMatrix m;
141             qreal zW = (qreal)rect.width()  / (qreal)attributes.pixmap().width();
142             qreal zH = (qreal)rect.height() / (qreal)attributes.pixmap().height();
143             switch ( attributes.pixmapMode() ) {
144             case BackgroundAttributes::BackgroundPixmapModeScaled:
145             {
146                 qreal z;
147                 z = qMin( zW, zH );
148                 m.scale( z, z );
149             }
150             break;
151             case BackgroundAttributes::BackgroundPixmapModeStretched:
152                 m.scale( zW, zH );
153                 break;
154             default:
155                 ; // Cannot happen, previously checked
156             }
157             QPixmap pm = attributes.pixmap().transformed( m );
158             ol.setX( rect.center().x() - pm.width() / 2 );
159             ol.setY( rect.center().y() - pm.height()/ 2 );
160             painter.drawPixmap( ol, pm );
161         }
162     }
163 }
164 
165 /* static */
paintFrameAttributes(QPainter & painter,const QRect & rect,const KChart::FrameAttributes & attributes)166 void AbstractAreaBase::paintFrameAttributes( QPainter& painter, const QRect& rect,
167     const KChart::FrameAttributes& attributes )
168 {
169 
170     if ( !attributes.isVisible() ) return;
171 
172     // Note: We set the brush to NoBrush explicitly here.
173     //       Otherwise we might get a filled rectangle, so any
174     //       previously drawn background would be overwritten by that area.
175 
176     const QPen oldPen( painter.pen() );
177     const QBrush oldBrush( painter.brush() );
178 
179     painter.setPen( PrintingParameters::scalePen( attributes.pen() ) );
180     painter.setBrush( Qt::NoBrush );
181     painter.drawRoundedRect( rect.adjusted( 0, 0, -1, -1 ), attributes.cornerRadius(), attributes.cornerRadius() );
182 
183     painter.setBrush( oldBrush );
184     painter.setPen( oldPen );
185 }
186 
paintBackground(QPainter & painter,const QRect & rect)187 void AbstractAreaBase::paintBackground( QPainter& painter, const QRect& rect )
188 {
189     Q_ASSERT_X ( d != nullptr, "AbstractAreaBase::paintBackground()",
190                 "Private class was not initialized!" );
191 
192     PainterSaver painterSaver( &painter );
193 
194     const qreal radius = d->frameAttributes.cornerRadius();
195     QPainterPath path;
196     path.addRoundedRect( rect.adjusted( 0, 0, -1, -1 ), radius, radius );
197     painter.setClipPath(path);
198 
199     paintBackgroundAttributes( painter, rect, d->backgroundAttributes );
200 }
201 
202 
paintFrame(QPainter & painter,const QRect & rect)203 void AbstractAreaBase::paintFrame( QPainter& painter, const QRect& rect )
204 {
205     Q_ASSERT_X ( d != nullptr, "AbstractAreaBase::paintFrame()",
206                 "Private class was not initialized!" );
207     paintFrameAttributes( painter, rect, d->frameAttributes );
208 }
209 
210 
getFrameLeadings(int & left,int & top,int & right,int & bottom) const211 void AbstractAreaBase::getFrameLeadings(int& left, int& top, int& right, int& bottom ) const
212 {
213     int padding = 0;
214     if ( d && d->frameAttributes.isVisible() ) {
215         padding = qMax( d->frameAttributes.padding(), 0 );
216     }
217     left = padding;
218     top = padding;
219     right = padding;
220     bottom = padding;
221 }
222 
innerRect() const223 QRect AbstractAreaBase::innerRect() const
224 {
225     int left;
226     int top;
227     int right;
228     int bottom;
229     getFrameLeadings( left, top, right, bottom );
230     return QRect ( QPoint( 0, 0 ), areaGeometry().size() ).adjusted( left, top, -right, -bottom );
231 }
232 
positionHasChanged()233 void AbstractAreaBase::positionHasChanged()
234 {
235     // this bloc left empty intentionally
236 }
237