KDChartLayoutItems.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002  ** Copyright (C) 2007 Klar�vdalens Datakonsult AB.  All rights reserved.
00003  **
00004  ** This file is part of the KD Chart library.
00005  **
00006  ** This file may be distributed and/or modified under the terms of the
00007  ** GNU General Public License version 2 as published by the Free Software
00008  ** Foundation and appearing in the file LICENSE.GPL included in the
00009  ** packaging of this file.
00010  **
00011  ** Licensees holding valid commercial KD Chart licenses may use this file in
00012  ** accordance with the KD Chart Commercial License Agreement provided with
00013  ** the Software.
00014  **
00015  ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00016  ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00017  **
00018  ** See http://www.kdab.net/kdchart for
00019  **   information about KDChart Commercial License Agreements.
00020  **
00021  ** Contact info@kdab.net if any conditions of this
00022  ** licensing are not clear to you.
00023  **
00024  **********************************************************************/
00025 
00026 #include "KDChartLayoutItems.h"
00027 #include "KDTextDocument.h"
00028 #include "KDChartAbstractArea.h"
00029 #include "KDChartAbstractDiagram.h"
00030 #include "KDChartBackgroundAttributes.h"
00031 #include "KDChartFrameAttributes.h"
00032 #include "KDChartPaintContext.h"
00033 #include "KDChartPainterSaver_p.h"
00034 #include <QTextCursor>
00035 #include <QTextBlockFormat>
00036 #include <QTextDocumentFragment>
00037 #include <QAbstractTextDocumentLayout>
00038 #include <QLayout>
00039 #include <QPainter>
00040 #include <QDebug>
00041 #include <QCoreApplication>
00042 #include <QApplication>
00043 #include <QStringList>
00044 #include <QStyle>
00045 
00046 #include <KDABLibFakes>
00047 
00048 #include <math.h>
00049 
00050 #define PI 3.141592653589793
00051 
00052 
00053 
00054 //#define DEBUG_ITEMS_PAINT
00055 
00064 void KDChart::AbstractLayoutItem::setParentWidget( QWidget* widget )
00065 {
00066     mParent = widget;
00067 }
00068 
00069 void KDChart::AbstractLayoutItem::paintAll( QPainter& painter )
00070 {
00071     paint( &painter );
00072 }
00073 
00077 void KDChart::AbstractLayoutItem::paintCtx( PaintContext* context )
00078 {
00079     if( context )
00080         paint( context->painter() );
00081 }
00082 
00086 void KDChart::AbstractLayoutItem::sizeHintChanged()const
00087 {
00088     // This is exactly like what QWidget::updateGeometry does.
00089 //  qDebug("KDChart::AbstractLayoutItem::sizeHintChanged() called");
00090     if( mParent ) {
00091         if ( mParent->layout() )
00092             mParent->layout()->invalidate();
00093         else
00094             QApplication::postEvent( mParent, new QEvent( QEvent::LayoutRequest ) );
00095     }
00096 }
00097 
00098 
00099 KDChart::TextLayoutItem::TextLayoutItem( const QString& text,
00100                                          const KDChart::TextAttributes& attributes,
00101                                          const QObject* area,
00102                                          KDChartEnums::MeasureOrientation orientation,
00103                                          Qt::Alignment alignment )
00104     : AbstractLayoutItem( alignment )
00105     , mText( text )
00106     , mAttributes( attributes )
00107     , mAutoReferenceArea( area )
00108     , mAutoReferenceOrientation( orientation )
00109     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00110     , cachedFontSize( 0.0 )
00111     , cachedFont( mAttributes.font() )
00112 {
00113 }
00114 
00115 KDChart::TextLayoutItem::TextLayoutItem()
00116     : AbstractLayoutItem( Qt::AlignLeft )
00117     , mText()
00118     , mAttributes()
00119     , mAutoReferenceArea( 0 )
00120     , mAutoReferenceOrientation( KDChartEnums::MeasureOrientationHorizontal )
00121     , cachedSizeHint() // default this to invalid to force just-in-time calculation before first use of sizeHint()
00122     , cachedFontSize( 0.0 )
00123     , cachedFont( mAttributes.font() )
00124 {
00125 
00126 }
00127 
00128 void KDChart::TextLayoutItem::setAutoReferenceArea( const QObject* area )
00129 {
00130     mAutoReferenceArea = area;
00131     cachedSizeHint = QSize();
00132     sizeHint();
00133 }
00134 
00135 const QObject* KDChart::TextLayoutItem::autoReferenceArea() const
00136 {
00137     return mAutoReferenceArea;
00138 }
00139 
00140 void KDChart::TextLayoutItem::setText(const QString & text)
00141 {
00142     mText = text;
00143     cachedSizeHint = QSize();
00144     sizeHint();
00145     if( mParent )
00146         mParent->update();
00147 }
00148 
00149 QString KDChart::TextLayoutItem::text() const
00150 {
00151     return mText;
00152 }
00153 
00159 void KDChart::TextLayoutItem::setTextAttributes( const TextAttributes &a )
00160 {
00161     mAttributes = a;
00162     cachedSizeHint = QSize(); // invalidate size hint
00163     sizeHint();
00164     if( mParent )
00165         mParent->update();
00166 }
00167 
00173 KDChart::TextAttributes KDChart::TextLayoutItem::textAttributes() const
00174 {
00175     return mAttributes;
00176 }
00177 
00178 
00179 Qt::Orientations KDChart::TextLayoutItem::expandingDirections() const
00180 {
00181     return 0; // Grow neither vertically nor horizontally
00182 }
00183 
00184 QRect KDChart::TextLayoutItem::geometry() const
00185 {
00186     return mRect;
00187 }
00188 
00189 bool KDChart::TextLayoutItem::isEmpty() const
00190 {
00191     return false; // never empty, otherwise the layout item would not exist
00192 }
00193 
00194 QSize KDChart::TextLayoutItem::maximumSize() const
00195 {
00196     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00197 }
00198 
00199 QSize KDChart::TextLayoutItem::minimumSize() const
00200 {
00201     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00202 }
00203 
00204 void KDChart::TextLayoutItem::setGeometry( const QRect& r )
00205 {
00206     mRect = r;
00207 }
00208 
00209 
00210 qreal KDChart::TextLayoutItem::realFontSize() const
00211 {
00212     return mAttributes.calculatedFontSize( mAutoReferenceArea, mAutoReferenceOrientation );
00213 }
00214 
00215 
00216 bool KDChart::TextLayoutItem::realFontWasRecalculated() const
00217 {
00218     const qreal fntSiz = realFontSize();
00219     const bool bRecalcDone =
00220         ( ( ! cachedSizeHint.isValid() ) || ( cachedFontSize != fntSiz   ) );
00221 
00222     if( bRecalcDone && fntSiz > 0.0 ){
00223         cachedFontSize = fntSiz;
00224         cachedFont.setPointSizeF( fntSiz );
00225     }
00226     return bRecalcDone;
00227 }
00228 
00229 
00230 QFont KDChart::TextLayoutItem::realFont() const
00231 {
00232     realFontWasRecalculated(); // we can safely ignore the boolean return value
00233     return cachedFont;
00234 }
00235 
00236 QPolygon KDChart::TextLayoutItem::rotatedCorners() const
00237 {
00238     // the angle in rad
00239     const qreal angle = mAttributes.rotation() * PI / 180.0;
00240     QSize size = unrotatedSizeHint();
00241 
00242     // my P1 - P4 (the four points of the rotated area)
00243     QPointF P1( size.height() * sin( angle ), 0 );
00244     QPointF P2( size.height() * sin( angle ) + size.width() * cos( angle ), size.width() * sin( angle ) );
00245     QPointF P3( size.width() * cos( angle ), size.width() * sin( angle ) + size.height() * cos( angle ) );
00246     QPointF P4( 0, size.height() * cos( angle ) );
00247 
00248     QPolygon result;
00249     result << P1.toPoint() << P2.toPoint() << P3.toPoint() << P4.toPoint();
00250     return result;
00251 }
00252 
00253 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPointF& myPos, const QPointF& otherPos ) const
00254 {
00255     return intersects( other, myPos.toPoint(), otherPos.toPoint() );
00256 }
00257 
00258 bool KDChart::TextLayoutItem::intersects( const TextLayoutItem& other, const QPoint& myPos, const QPoint& otherPos ) const
00259 {
00260     if ( mAttributes.rotation() != other.mAttributes.rotation() )
00261     {
00262         // that's the code for the common case: the rotation angles don't need to match here
00263         QPolygon myPolygon(          rotatedCorners() );
00264         QPolygon otherPolygon( other.rotatedCorners() );
00265 
00266         // move the polygons to their positions
00267         myPolygon.translate( myPos );
00268         otherPolygon.translate( otherPos );
00269 
00270         // create regions out of it
00271         QRegion myRegion( myPolygon );
00272         QRegion otherRegion( otherPolygon );
00273 
00274         // now the question - do they intersect or not?
00275         return ! myRegion.intersect( otherRegion ).isEmpty();
00276 
00277     } else {
00278         // and that's the code for the special case: the rotation angles match, which is less time consuming in calculation
00279         const qreal angle = mAttributes.rotation() * PI / 180.0;
00280         // both sizes
00281         const QSizeF mySize(          unrotatedSizeHint() );
00282         const QSizeF otherSize( other.unrotatedSizeHint() );
00283 
00284         // that's myP1 relative to myPos
00285         QPointF myP1( mySize.height() * sin( angle ), 0.0 );
00286         // that's otherP1 to myPos
00287         QPointF otherP1 = QPointF( otherSize.height() * sin( angle ), 0.0 ) + otherPos - myPos;
00288 
00289         // now rotate both points the negative angle around myPos
00290         myP1 = QPointF( myP1.x() * cos( -angle ), myP1.x() * sin( -angle ) );
00291         qreal r = sqrt( otherP1.x() * otherP1.x() + otherP1.y() * otherP1.y() );
00292         otherP1 = QPointF( r * cos( -angle ), r * sin( -angle ) );
00293 
00294         // finally we look, whether both rectangles intersect or even not
00295         return QRectF( myP1, mySize ).intersects( QRectF( otherP1, otherSize ) );
00296     }
00297 }
00298 
00299 QSize KDChart::TextLayoutItem::sizeHint() const
00300 {
00301     if( realFontWasRecalculated() )
00302     {
00303         const QSize newSizeHint( calcSizeHint( cachedFont ) );
00304         if( newSizeHint != cachedSizeHint ){
00305             cachedSizeHint = newSizeHint;
00306             sizeHintChanged();
00307         }
00308     }
00309     //qDebug() << "-------- KDChart::TextLayoutItem::sizeHint() returns:"<<cachedSizeHint<<" ----------";
00310     return cachedSizeHint;
00311 }
00312 
00313 
00314 // PENDING(kalle) Support auto shrink
00315 
00316 
00317 QSize KDChart::TextLayoutItem::unrotatedSizeHint( QFont fnt ) const
00318 {
00319     if ( fnt == QFont() )
00320         fnt = cachedFont;
00321 
00322     const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
00323     QSize ret(0, 0);
00324     // note: boundingRect() does NOT take any newlines into account
00325     //       so we need to calculate the size by combining several
00326     //       rectangles: one per line.  This fixes bugz issue #3720.
00327     //       (khz, 2007 04 14)
00328     QStringList lines = mText.split(QString::fromAscii("\n"));
00329     for (int i = 0; i < lines.size(); ++i){
00330         const QSize lSize = met.boundingRect(lines.at(i) ).toRect().size();
00331         ret.setWidth(qMax( ret.width(), lSize.width() ));
00332         ret.rheight() += lSize.height();
00333     }
00334 
00335     int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
00336     // fine-tuning for small font sizes: the frame must not be so big, if the font is tiny
00337     frame = qMin( frame, ret.height() * 2 / 3 );
00338     //qDebug() << "frame:"<< frame;
00339     ret += QSize( frame, frame );
00340     return ret;
00341     //const QFontMetricsF met( fnt, GlobalMeasureScaling::paintDevice() );
00342     //const int frame = QApplication::style()->pixelMetric( QStyle::PM_ButtonMargin, 0, 0 );
00343     //return
00344     //    met.boundingRect( mText ).size().toSize() + QSize( frame, frame );
00345 }
00346 
00347 
00348 QSize KDChart::TextLayoutItem::calcSizeHint( QFont fnt ) const
00349 {
00350     QSize ret = unrotatedSizeHint( fnt );
00351     //qDebug() << "-------- "<<ret.width();
00352     const qreal angle = PI * mAttributes.rotation() / 180.0;
00353     const qreal cosAngle = cos( angle );
00354     const qreal sinAngle = sin( angle );
00355     QSize rotated( qAbs(static_cast<int>( cosAngle * ret.width()  + sinAngle * ret.height() )),
00356                    qAbs(static_cast<int>( cosAngle * ret.height() + sinAngle * ret.width()  )) );
00357     //qDebug() << "-------- KDChart::TextLayoutItem::calcSizeHint() returns:"<<rotated<<" ----------";
00358     return rotated;
00359 }
00360 
00361 static QPointF rotatedPoint( const QPointF& pt, qreal rotation )
00362 {
00363     const qreal angle = PI * rotation / 180.0;
00364     const qreal cosAngle = cos( angle );
00365     const qreal sinAngle = sin( angle );
00366     return QPointF(
00367             (cosAngle * pt.x() + sinAngle * pt.y() ),
00368             (cosAngle * pt.y() + sinAngle * pt.x() ) );
00369 }
00370 
00371 static QRectF rotatedRect( const QRectF& rect, qreal angle )
00372 {
00373     const QPointF topLeft(  rotatedPoint( rect.topLeft(),  angle ) );
00374     //const QPointF topRight( rotatedPoint( rect.topRight(), angle ) );
00375     //const QPointF bottomLeft(  rotatedPoint( rect.bottomLeft(),  angle ) );
00376     //const QPointF bottomRight( rotatedPoint( rect.bottomRight(), angle ) );
00377     const QPointF siz( rotatedPoint( QPointF( rect.size().width(), rect.size().height() ), angle ) );
00378     const QRectF result(
00379             topLeft,
00380             QSizeF( siz.x(), //bottomRight.x() - topLeft.x(),
00381                     siz.y() ) ); //bottomRight.y() - topLeft.y() ) );
00382     //qDebug() << "angle" << angle << "\nbefore:" << rect << "\n after:" << result;
00383     return result;
00384 }
00385 
00386 void KDChart::TextLayoutItem::paint( QPainter* painter )
00387 {
00388     // make sure, cached font is updated, if needed:
00389     // sizeHint();
00390 
00391     if( !mRect.isValid() )
00392         return;
00393 
00394     PainterSaver painterSaver( painter );
00395     painter->setFont( cachedFont );
00396     QRectF rect( geometry() );
00397 
00398 // #ifdef DEBUG_ITEMS_PAINT
00399 //     painter->setPen( Qt::black );
00400 //     painter->drawRect( rect );
00401 // #endif
00402     painter->translate( rect.center() );
00403     rect.moveTopLeft( QPointF( - rect.width() / 2, - rect.height() / 2 ) );
00404 #ifdef DEBUG_ITEMS_PAINT
00405     painter->setPen( Qt::blue );
00406     painter->drawRect( rect );
00407 #endif
00408     painter->rotate( mAttributes.rotation() );
00409     rect = rotatedRect( rect, mAttributes.rotation() );
00410 #ifdef DEBUG_ITEMS_PAINT
00411     painter->setPen( Qt::red );
00412     painter->drawRect( rect );
00413 #endif
00414     painter->setPen( mAttributes.pen() );
00415     painter->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, mText );
00416 //    if (  calcSizeHint( cachedFont ).width() > rect.width() )
00417 //        qDebug() << "rect.width()" << rect.width() << "text.width()" << calcSizeHint( cachedFont ).width();
00418 //
00419 //    //painter->drawText( rect, Qt::AlignHCenter | Qt::AlignVCenter, mText );
00420 }
00421 
00422 KDChart::HorizontalLineLayoutItem::HorizontalLineLayoutItem()
00423     : AbstractLayoutItem( Qt::AlignCenter )
00424 {
00425 }
00426 
00427 Qt::Orientations KDChart::HorizontalLineLayoutItem::expandingDirections() const
00428 {
00429     return Qt::Vertical|Qt::Horizontal; // Grow both vertically, and horizontally
00430 }
00431 
00432 QRect KDChart::HorizontalLineLayoutItem::geometry() const
00433 {
00434     return mRect;
00435 }
00436 
00437 bool KDChart::HorizontalLineLayoutItem::isEmpty() const
00438 {
00439     return false; // never empty, otherwise the layout item would not exist
00440 }
00441 
00442 QSize KDChart::HorizontalLineLayoutItem::maximumSize() const
00443 {
00444     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00445 }
00446 
00447 QSize KDChart::HorizontalLineLayoutItem::minimumSize() const
00448 {
00449     return QSize( 0, 0 );
00450 }
00451 
00452 void KDChart::HorizontalLineLayoutItem::setGeometry( const QRect& r )
00453 {
00454     mRect = r;
00455 }
00456 
00457 QSize KDChart::HorizontalLineLayoutItem::sizeHint() const
00458 {
00459     return QSize( -1, 3 ); // see qframe.cpp
00460 }
00461 
00462 
00463 void KDChart::HorizontalLineLayoutItem::paint( QPainter* painter )
00464 {
00465     if( !mRect.isValid() )
00466         return;
00467 
00468     painter->drawLine( QPointF( mRect.left(), mRect.center().y() ),
00469                        QPointF( mRect.right(), mRect.center().y() ) );
00470 }
00471 
00472 
00473 KDChart::VerticalLineLayoutItem::VerticalLineLayoutItem()
00474     : AbstractLayoutItem( Qt::AlignCenter )
00475 {
00476 }
00477 
00478 Qt::Orientations KDChart::VerticalLineLayoutItem::expandingDirections() const
00479 {
00480     return Qt::Vertical|Qt::Vertical; // Grow both vertically, and horizontally
00481 }
00482 
00483 QRect KDChart::VerticalLineLayoutItem::geometry() const
00484 {
00485     return mRect;
00486 }
00487 
00488 bool KDChart::VerticalLineLayoutItem::isEmpty() const
00489 {
00490     return false; // never empty, otherwise the layout item would not exist
00491 }
00492 
00493 QSize KDChart::VerticalLineLayoutItem::maximumSize() const
00494 {
00495     return QSize( QWIDGETSIZE_MAX, QWIDGETSIZE_MAX );
00496 }
00497 
00498 QSize KDChart::VerticalLineLayoutItem::minimumSize() const
00499 {
00500     return QSize( 0, 0 );
00501 }
00502 
00503 void KDChart::VerticalLineLayoutItem::setGeometry( const QRect& r )
00504 {
00505     mRect = r;
00506 }
00507 
00508 QSize KDChart::VerticalLineLayoutItem::sizeHint() const
00509 {
00510     return QSize( 3, -1 ); // see qframe.cpp
00511 }
00512 
00513 
00514 void KDChart::VerticalLineLayoutItem::paint( QPainter* painter )
00515 {
00516     if( !mRect.isValid() )
00517         return;
00518 
00519     painter->drawLine( QPointF( mRect.center().x(), mRect.top() ),
00520                        QPointF( mRect.center().x(), mRect.bottom() ) );
00521 }
00522 
00523 
00524 
00525 KDChart::MarkerLayoutItem::MarkerLayoutItem( KDChart::AbstractDiagram* diagram,
00526                                              const MarkerAttributes& marker,
00527                                              const QBrush& brush, const QPen& pen,
00528                                              Qt::Alignment alignment )
00529     : AbstractLayoutItem( alignment )
00530     , mDiagram( diagram )
00531     , mMarker( marker )
00532     , mBrush( brush )
00533     , mPen( pen )
00534 {
00535 }
00536 
00537 Qt::Orientations KDChart::MarkerLayoutItem::expandingDirections() const
00538 {
00539     return 0; // Grow neither vertically nor horizontally
00540 }
00541 
00542 QRect KDChart::MarkerLayoutItem::geometry() const
00543 {
00544     return mRect;
00545 }
00546 
00547 bool KDChart::MarkerLayoutItem::isEmpty() const
00548 {
00549     return false; // never empty, otherwise the layout item would not exist
00550 }
00551 
00552 QSize KDChart::MarkerLayoutItem::maximumSize() const
00553 {
00554     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00555 }
00556 
00557 QSize KDChart::MarkerLayoutItem::minimumSize() const
00558 {
00559     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00560 }
00561 
00562 void KDChart::MarkerLayoutItem::setGeometry( const QRect& r )
00563 {
00564     mRect = r;
00565 }
00566 
00567 QSize KDChart::MarkerLayoutItem::sizeHint() const
00568 {
00569     //qDebug() << "KDChart::MarkerLayoutItem::sizeHint() returns:"<<mMarker.markerSize().toSize();
00570     return mMarker.markerSize().toSize();
00571 }
00572 
00573 void KDChart::MarkerLayoutItem::paint( QPainter* painter )
00574 {
00575     paintIntoRect( painter, mRect, mDiagram, mMarker, mBrush, mPen );
00576 }
00577 
00578 void KDChart::MarkerLayoutItem::paintIntoRect(
00579         QPainter* painter,
00580         const QRect& rect,
00581         AbstractDiagram* diagram,
00582         const MarkerAttributes& marker,
00583         const QBrush& brush,
00584         const QPen& pen )
00585 {
00586     if( ! rect.isValid() )
00587         return;
00588 
00589     // The layout management may assign a larger rect than what we
00590     // wanted. We need to adjust the position.
00591     const QSize siz = marker.markerSize().toSize();
00592     QPointF pos = rect.topLeft();
00593     pos += QPointF( static_cast<qreal>(( rect.width()  - siz.width()) / 2.0 ),
00594                     static_cast<qreal>(( rect.height() - siz.height()) / 2.0 ) );
00595 
00596 #ifdef DEBUG_ITEMS_PAINT
00597     QPointF oldPos = pos;
00598 #endif
00599 
00600 // And finally, drawMarker() assumes the position to be the center
00601     // of the marker, adjust again.
00602     pos += QPointF( static_cast<qreal>( siz.width() ) / 2.0,
00603                     static_cast<qreal>( siz.height() )/ 2.0 );
00604 
00605     diagram->paintMarker( painter, marker, brush, pen, pos.toPoint(), siz );
00606 
00607 #ifdef DEBUG_ITEMS_PAINT
00608     const QPen oldPen( painter->pen() );
00609     painter->setPen( Qt::red );
00610     painter->drawRect( QRect(oldPos.toPoint(), siz) );
00611     painter->setPen( oldPen );
00612 #endif
00613 }
00614 
00615 
00616 KDChart::LineLayoutItem::LineLayoutItem( KDChart::AbstractDiagram* diagram,
00617                                          int length,
00618                                          const QPen& pen,
00619                                          Qt::Alignment alignment )
00620     : AbstractLayoutItem( alignment )
00621     , mDiagram( diagram )
00622     , mLength( length )
00623     , mPen( pen )
00624 {
00625     //have a mini pen width
00626     if ( pen.width() < 2 )
00627         mPen.setWidth( 2 );
00628 }
00629 
00630 Qt::Orientations KDChart::LineLayoutItem::expandingDirections() const
00631 {
00632     return 0; // Grow neither vertically nor horizontally
00633 }
00634 
00635 QRect KDChart::LineLayoutItem::geometry() const
00636 {
00637     return mRect;
00638 }
00639 
00640 bool KDChart::LineLayoutItem::isEmpty() const
00641 {
00642     return false; // never empty, otherwise the layout item would not exist
00643 }
00644 
00645 QSize KDChart::LineLayoutItem::maximumSize() const
00646 {
00647     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00648 }
00649 
00650 QSize KDChart::LineLayoutItem::minimumSize() const
00651 {
00652     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00653 }
00654 
00655 void KDChart::LineLayoutItem::setGeometry( const QRect& r )
00656 {
00657     mRect = r;
00658 }
00659 
00660 QSize KDChart::LineLayoutItem::sizeHint() const
00661 {
00662     return QSize( mLength, mPen.width()+2 );
00663 }
00664 
00665 void KDChart::LineLayoutItem::paint( QPainter* painter )
00666 {
00667     paintIntoRect( painter, mRect, mPen );
00668 }
00669 
00670 void KDChart::LineLayoutItem::paintIntoRect(
00671         QPainter* painter,
00672         const QRect& rect,
00673         const QPen& pen )
00674 {
00675     if( ! rect.isValid() )
00676         return;
00677 
00678     const QPen oldPen = painter->pen();
00679     painter->setPen( pen );
00680     const qreal y = rect.center().y();
00681     painter->drawLine( QPointF( rect.left(), y ),
00682                        QPointF( rect.right(), y ) );
00683     painter->setPen( oldPen );
00684 }
00685 
00686 
00687 KDChart::LineWithMarkerLayoutItem::LineWithMarkerLayoutItem(
00688         KDChart::AbstractDiagram* diagram,
00689         int lineLength,
00690         const QPen& linePen,
00691         int markerOffs,
00692         const MarkerAttributes& marker,
00693         const QBrush& markerBrush,
00694         const QPen& markerPen,
00695         Qt::Alignment alignment )
00696     : AbstractLayoutItem( alignment )
00697     , mDiagram(     diagram )
00698     , mLineLength(  lineLength )
00699     , mLinePen(     linePen )
00700     , mMarkerOffs(  markerOffs )
00701     , mMarker(      marker )
00702     , mMarkerBrush( markerBrush )
00703     , mMarkerPen(   markerPen )
00704 {
00705 }
00706 
00707 Qt::Orientations KDChart::LineWithMarkerLayoutItem::expandingDirections() const
00708 {
00709     return 0; // Grow neither vertically nor horizontally
00710 }
00711 
00712 QRect KDChart::LineWithMarkerLayoutItem::geometry() const
00713 {
00714     return mRect;
00715 }
00716 
00717 bool KDChart::LineWithMarkerLayoutItem::isEmpty() const
00718 {
00719     return false; // never empty, otherwise the layout item would not exist
00720 }
00721 
00722 QSize KDChart::LineWithMarkerLayoutItem::maximumSize() const
00723 {
00724     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00725 }
00726 
00727 QSize KDChart::LineWithMarkerLayoutItem::minimumSize() const
00728 {
00729     return sizeHint(); // PENDING(kalle) Review, quite inflexible
00730 }
00731 
00732 void KDChart::LineWithMarkerLayoutItem::setGeometry( const QRect& r )
00733 {
00734     mRect = r;
00735 }
00736 
00737 QSize KDChart::LineWithMarkerLayoutItem::sizeHint() const
00738 {
00739     const QSize sizeM = mMarker.markerSize().toSize();
00740     const QSize sizeL = QSize( mLineLength, mLinePen.width()+2 );
00741     return QSize( qMax(sizeM.width(),  sizeL.width()),
00742                   qMax(sizeM.height(), sizeL.height()) );
00743 }
00744 
00745 void KDChart::LineWithMarkerLayoutItem::paint( QPainter* painter )
00746 {
00747     // paint the line over the full width, into the vertical middle of the rect
00748     LineLayoutItem::paintIntoRect( painter, mRect, mLinePen );
00749 
00750     // paint the marker with the given offset from the left side of the line
00751     const QRect r(
00752             QPoint( mRect.x()+mMarkerOffs, mRect.y() ),
00753             QSize( mMarker.markerSize().toSize().width(), mRect.height() ) );
00754     MarkerLayoutItem::paintIntoRect(
00755             painter, r, mDiagram, mMarker, mMarkerBrush, mMarkerPen );
00756 }
00757 
00758 
00759 
00760 KDChart::AutoSpacerLayoutItem::AutoSpacerLayoutItem(
00761         bool layoutIsAtTopPosition, QHBoxLayout *rightLeftLayout,
00762         bool layoutIsAtLeftPosition, QVBoxLayout *topBottomLayout )
00763     : AbstractLayoutItem( Qt::AlignCenter )
00764     , mLayoutIsAtTopPosition(  layoutIsAtTopPosition )
00765     , mRightLeftLayout( rightLeftLayout )
00766     , mLayoutIsAtLeftPosition( layoutIsAtLeftPosition )
00767     , mTopBottomLayout( topBottomLayout )
00768 {
00769 }
00770 
00771 Qt::Orientations KDChart::AutoSpacerLayoutItem::expandingDirections() const
00772 {
00773     return 0; // Grow neither vertically nor horizontally
00774 }
00775 
00776 QRect KDChart::AutoSpacerLayoutItem::geometry() const
00777 {
00778     return mRect;
00779 }
00780 
00781 bool KDChart::AutoSpacerLayoutItem::isEmpty() const
00782 {
00783     return true; // never empty, otherwise the layout item would not exist
00784 }
00785 
00786 QSize KDChart::AutoSpacerLayoutItem::maximumSize() const
00787 {
00788     return sizeHint();
00789 }
00790 
00791 QSize KDChart::AutoSpacerLayoutItem::minimumSize() const
00792 {
00793     return sizeHint();
00794 }
00795 
00796 void KDChart::AutoSpacerLayoutItem::setGeometry( const QRect& r )
00797 {
00798     mRect = r;
00799 }
00800 
00801 
00802 static void updateCommonBrush( QBrush& commonBrush, bool& bStart, const KDChart::AbstractArea& area )
00803 {
00804     const KDChart::BackgroundAttributes ba( area.backgroundAttributes() );
00805     const bool hasSimpleBrush = (
00806             ! area.frameAttributes().isVisible() &&
00807             ba.isVisible() &&
00808             ba.pixmapMode() == KDChart::BackgroundAttributes::BackgroundPixmapModeNone &&
00809             ba.brush().gradient() == 0 );
00810     if( bStart ){
00811         bStart = false;
00812         commonBrush = hasSimpleBrush ? ba.brush() : QBrush();
00813     }else{
00814         if( ! hasSimpleBrush || ba.brush() != commonBrush )
00815         {
00816             commonBrush = QBrush();
00817         }
00818     }
00819 }
00820 
00821 QSize KDChart::AutoSpacerLayoutItem::sizeHint() const
00822 {
00823     QBrush commonBrush;
00824     bool bStart=true;
00825     // calculate the maximal overlap of the top/bottom axes:
00826     int topBottomOverlap = 0;
00827     if( mTopBottomLayout ){
00828         for (int i = 0; i < mTopBottomLayout->count(); ++i){
00829             AbstractArea* area = dynamic_cast<AbstractArea*>(mTopBottomLayout->itemAt(i));
00830             if( area ){
00831                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
00832                 topBottomOverlap =
00833                     mLayoutIsAtLeftPosition
00834                     ? qMax( topBottomOverlap, area->rightOverlap() )
00835                     : qMax( topBottomOverlap, area->leftOverlap() );
00836                 updateCommonBrush( commonBrush, bStart, *area );
00837             }
00838         }
00839     }
00840     // calculate the maximal overlap of the left/right axes:
00841     int leftRightOverlap = 0;
00842     if( mRightLeftLayout ){
00843         for (int i = 0; i < mRightLeftLayout->count(); ++i){
00844             AbstractArea* area = dynamic_cast<AbstractArea*>(mRightLeftLayout->itemAt(i));
00845             if( area ){
00846                 //qDebug() << "AutoSpacerLayoutItem testing" << area;
00847                 leftRightOverlap =
00848                         mLayoutIsAtTopPosition
00849                         ? qMax( leftRightOverlap, area->bottomOverlap() )
00850                         : qMax( leftRightOverlap, area->topOverlap() );
00851                 updateCommonBrush( commonBrush, bStart, *area );
00852             }
00853         }
00854     }
00855     if( topBottomOverlap > 0 && leftRightOverlap > 0 )
00856         mCommonBrush = commonBrush;
00857     else
00858         mCommonBrush = QBrush();
00859     mCachedSize = QSize( topBottomOverlap, leftRightOverlap );
00860     //qDebug() << mCachedSize;
00861     return mCachedSize;
00862 }
00863 
00864 
00865 void KDChart::AutoSpacerLayoutItem::paint( QPainter* painter )
00866 {
00867     if( mParentLayout && mRect.isValid() && mCachedSize.isValid() &&
00868         mCommonBrush.style() != Qt::NoBrush )
00869     {
00870         QPoint p1( mRect.topLeft() );
00871         QPoint p2( mRect.bottomRight() );
00872         if( mLayoutIsAtLeftPosition )
00873             p1.rx() += mCachedSize.width() - mParentLayout->spacing();
00874         else
00875             p2.rx() -= mCachedSize.width() - mParentLayout->spacing();
00876         if( mLayoutIsAtTopPosition ){
00877             p1.ry() += mCachedSize.height() - mParentLayout->spacing() - 1;
00878             p2.ry() -= 1;
00879         }else
00880             p2.ry() -= mCachedSize.height() - mParentLayout->spacing() - 1;
00881         //qDebug() << mLayoutIsAtTopPosition << mLayoutIsAtLeftPosition;
00882         //qDebug() << mRect;
00883         //qDebug() << mParentLayout->margin();
00884         //qDebug() << QRect( p1, p2 );
00885         const QPoint oldBrushOrigin( painter->brushOrigin() );
00886         const QBrush oldBrush( painter->brush() );
00887         const QPen   oldPen(   painter->pen() );
00888         const QPointF newTopLeft( painter->deviceMatrix().map( p1 ) );
00889         painter->setBrushOrigin( newTopLeft );
00890         painter->setBrush( mCommonBrush );
00891         painter->setPen( Qt::NoPen );
00892         painter->drawRect( QRect( p1, p2 ) );
00893         painter->setBrushOrigin( oldBrushOrigin );
00894         painter->setBrush( oldBrush );
00895         painter->setPen( oldPen );
00896     }
00897     // debug code:
00898 #if 0
00899     //qDebug() << "KDChart::AutoSpacerLayoutItem::paint()";
00900     if( !mRect.isValid() )
00901         return;
00902 
00903     painter->drawRect( mRect );
00904     painter->drawLine( QPointF( mRect.x(), mRect.top() ),
00905                        QPointF( mRect.right(), mRect.bottom() ) );
00906     painter->drawLine( QPointF( mRect.right(), mRect.top() ),
00907                        QPointF( mRect.x(), mRect.bottom() ) );
00908 #endif
00909 }

Generated on Mon Sep 17 16:16:50 2007 for KD Chart 2 by  doxygen 1.5.1