00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_plot_legenditem.h"
00011 #include "qwt_dyngrid_layout.h"
00012 #include "qwt_scale_map.h"
00013 #include "qwt_painter.h"
00014 #include <qlayoutitem.h>
00015 #include <qpen.h>
00016 #include <qbrush.h>
00017 #include <qpainter.h>
00018 #include <qmath.h>
00019
00020 class QwtLegendLayoutItem: public QLayoutItem
00021 {
00022 public:
00023 QwtLegendLayoutItem( const QwtPlotLegendItem *, const QwtPlotItem * );
00024 virtual ~QwtLegendLayoutItem();
00025
00026 const QwtPlotItem *plotItem() const;
00027
00028 void setData( const QwtLegendData & );
00029 const QwtLegendData &data() const;
00030
00031 virtual Qt::Orientations expandingDirections() const;
00032 virtual QRect geometry() const;
00033 virtual bool hasHeightForWidth() const;
00034 virtual int heightForWidth( int w ) const;
00035 virtual bool isEmpty() const;
00036 virtual QSize maximumSize() const;
00037 virtual int minimumHeightForWidth( int w ) const;
00038 virtual QSize minimumSize() const;
00039 virtual void setGeometry( const QRect & r );
00040 virtual QSize sizeHint() const;
00041
00042 private:
00043
00044 const QwtPlotLegendItem *d_legendItem;
00045 const QwtPlotItem *d_plotItem;
00046 QwtLegendData d_data;
00047
00048 QRect d_rect;
00049 };
00050
00051 QwtLegendLayoutItem::QwtLegendLayoutItem(
00052 const QwtPlotLegendItem *legendItem, const QwtPlotItem *plotItem ):
00053 d_legendItem( legendItem ),
00054 d_plotItem( plotItem)
00055 {
00056 }
00057
00058 QwtLegendLayoutItem::~QwtLegendLayoutItem()
00059 {
00060 }
00061
00062 const QwtPlotItem *QwtLegendLayoutItem::plotItem() const
00063 {
00064 return d_plotItem;
00065 }
00066
00067 void QwtLegendLayoutItem::setData( const QwtLegendData &data )
00068 {
00069 d_data = data;
00070 }
00071
00072 const QwtLegendData &QwtLegendLayoutItem::data() const
00073 {
00074 return d_data;
00075 }
00076
00077 Qt::Orientations QwtLegendLayoutItem::expandingDirections() const
00078 {
00079 return Qt::Horizontal;
00080 }
00081
00082 bool QwtLegendLayoutItem::hasHeightForWidth() const
00083 {
00084 return !d_data.title().isEmpty();
00085 }
00086
00087 int QwtLegendLayoutItem::minimumHeightForWidth( int w ) const
00088 {
00089 return d_legendItem->heightForWidth( d_data, w );
00090 }
00091
00092 int QwtLegendLayoutItem::heightForWidth( int w ) const
00093 {
00094 return d_legendItem->heightForWidth( d_data, w );
00095 }
00096
00097 bool QwtLegendLayoutItem::isEmpty() const
00098 {
00099 return false;
00100 }
00101
00102 QSize QwtLegendLayoutItem::maximumSize() const
00103 {
00104 return QSize( QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX );
00105 }
00106
00107 QSize QwtLegendLayoutItem::minimumSize() const
00108 {
00109 return d_legendItem->minimumSize( d_data );
00110 }
00111
00112 QSize QwtLegendLayoutItem::sizeHint() const
00113 {
00114 return minimumSize();
00115 }
00116
00117 void QwtLegendLayoutItem::setGeometry( const QRect &rect )
00118 {
00119 d_rect = rect;
00120 }
00121
00122 QRect QwtLegendLayoutItem::geometry() const
00123 {
00124 return d_rect;
00125 }
00126
00127 class QwtPlotLegendItem::PrivateData
00128 {
00129 public:
00130 PrivateData():
00131 itemMargin( 4 ),
00132 itemSpacing( 4 ),
00133 borderRadius( 0.0 ),
00134 borderPen( Qt::NoPen ),
00135 backgroundBrush( Qt::NoBrush ),
00136 backgroundMode( QwtPlotLegendItem::LegendBackground ),
00137 borderDistance( 10 ),
00138 alignment( Qt::AlignRight | Qt::AlignBottom )
00139 {
00140 layout = new QwtDynGridLayout();
00141 layout->setMaxColumns( 2 );
00142
00143 layout->setSpacing( 0 );
00144 layout->setContentsMargins( 0, 0, 0, 0 );
00145 }
00146
00147 ~PrivateData()
00148 {
00149 delete layout;
00150 }
00151
00152 QFont font;
00153 QPen textPen;
00154 int itemMargin;
00155 int itemSpacing;
00156
00157 double borderRadius;
00158 QPen borderPen;
00159 QBrush backgroundBrush;
00160 QwtPlotLegendItem::BackgroundMode backgroundMode;
00161
00162 int borderDistance;
00163 Qt::Alignment alignment;
00164
00165 QMap< const QwtPlotItem *, QList<QwtLegendLayoutItem *> > map;
00166 QwtDynGridLayout *layout;
00167 };
00168
00170 QwtPlotLegendItem::QwtPlotLegendItem():
00171 QwtPlotItem( QwtText( "Legend" ) )
00172 {
00173 d_data = new PrivateData;
00174
00175 setItemInterest( QwtPlotItem::LegendInterest, true );
00176 setZ( 100.0 );
00177 }
00178
00180 QwtPlotLegendItem::~QwtPlotLegendItem()
00181 {
00182 clearLegend();
00183 delete d_data;
00184 }
00185
00187 int QwtPlotLegendItem::rtti() const
00188 {
00189 return QwtPlotItem::Rtti_PlotLegend;
00190 }
00191
00205 void QwtPlotLegendItem::setAlignment( Qt::Alignment alignment )
00206 {
00207 if ( d_data->alignment != alignment )
00208 {
00209 d_data->alignment = alignment;
00210 itemChanged();
00211 }
00212 }
00213
00218 Qt::Alignment QwtPlotLegendItem::alignment() const
00219 {
00220 return d_data->alignment;
00221 }
00222
00233 void QwtPlotLegendItem::setMaxColumns( uint maxColumns )
00234 {
00235 if ( maxColumns != d_data->layout->maxColumns() )
00236 {
00237 d_data->layout->setMaxColumns( maxColumns );
00238 itemChanged();
00239 }
00240 }
00241
00246 uint QwtPlotLegendItem::maxColumns() const
00247 {
00248 return d_data->layout->maxColumns();
00249 }
00250
00259 void QwtPlotLegendItem::setMargin( int margin )
00260 {
00261 margin = qMax( margin, 0 );
00262 if ( margin != this->margin() )
00263 {
00264 d_data->layout->setContentsMargins(
00265 margin, margin, margin, margin );
00266
00267 itemChanged();
00268 }
00269 }
00270
00275 int QwtPlotLegendItem::margin() const
00276 {
00277 int left;
00278 d_data->layout->getContentsMargins( &left, NULL, NULL, NULL );
00279
00280 return left;
00281 }
00282
00289 void QwtPlotLegendItem::setSpacing( int spacing )
00290 {
00291 spacing = qMax( spacing, 0 );
00292 if ( spacing != d_data->layout->spacing() )
00293 {
00294 d_data->layout->setSpacing( spacing );
00295 itemChanged();
00296 }
00297 }
00298
00303 int QwtPlotLegendItem::spacing() const
00304 {
00305 return d_data->layout->spacing();
00306 }
00307
00314 void QwtPlotLegendItem::setItemMargin( int margin )
00315 {
00316 margin = qMax( margin, 0 );
00317 if ( margin != d_data->itemMargin )
00318 {
00319 d_data->itemMargin = margin;
00320
00321 d_data->layout->invalidate();
00322 itemChanged();
00323 }
00324 }
00325
00330 int QwtPlotLegendItem::itemMargin() const
00331 {
00332 return d_data->itemMargin;
00333 }
00334
00341 void QwtPlotLegendItem::setItemSpacing( int spacing )
00342 {
00343 spacing = qMax( spacing, 0 );
00344 if ( spacing != d_data->itemSpacing )
00345 {
00346 d_data->itemSpacing = spacing;
00347
00348 d_data->layout->invalidate();
00349 itemChanged();
00350 }
00351
00352 }
00353
00358 int QwtPlotLegendItem::itemSpacing() const
00359 {
00360 return d_data->itemSpacing;
00361 }
00362
00369 void QwtPlotLegendItem::setFont( const QFont &font )
00370 {
00371 if ( font != d_data->font )
00372 {
00373 d_data->font = font;
00374
00375 d_data->layout->invalidate();
00376 itemChanged();
00377 }
00378 }
00379
00384 QFont QwtPlotLegendItem::font() const
00385 {
00386 return d_data->font;
00387 }
00388
00397 void QwtPlotLegendItem::setBorderDistance( int distance )
00398 {
00399 if ( distance < 0 )
00400 distance = -1;
00401
00402 if ( distance != d_data->borderDistance )
00403 {
00404 d_data->borderDistance = distance;
00405 itemChanged();
00406 }
00407 }
00408
00413 int QwtPlotLegendItem::borderDistance() const
00414 {
00415 return d_data->borderDistance;
00416 }
00417
00424 void QwtPlotLegendItem::setBorderRadius( double radius )
00425 {
00426 radius = qMax( 0.0, radius );
00427
00428 if ( radius != d_data->borderRadius )
00429 {
00430 d_data->borderRadius = radius;
00431 itemChanged();
00432 }
00433 }
00434
00439 double QwtPlotLegendItem::borderRadius() const
00440 {
00441 return d_data->borderRadius;
00442 }
00443
00450 void QwtPlotLegendItem::setBorderPen( const QPen &pen )
00451 {
00452 if ( d_data->borderPen != pen )
00453 {
00454 d_data->borderPen = pen;
00455 itemChanged();
00456 }
00457 }
00458
00463 QPen QwtPlotLegendItem::borderPen() const
00464 {
00465 return d_data->borderPen;
00466 }
00467
00476 void QwtPlotLegendItem::setBackgroundBrush( const QBrush &brush )
00477 {
00478 if ( d_data->backgroundBrush != brush )
00479 {
00480 d_data->backgroundBrush = brush;
00481 itemChanged();
00482 }
00483 }
00484
00489 QBrush QwtPlotLegendItem::backgroundBrush() const
00490 {
00491 return d_data->backgroundBrush;
00492 }
00493
00504 void QwtPlotLegendItem::setBackgroundMode( BackgroundMode mode )
00505 {
00506 if ( mode != d_data->backgroundMode )
00507 {
00508 d_data->backgroundMode = mode;
00509 itemChanged();
00510 }
00511 }
00512
00517 QwtPlotLegendItem::BackgroundMode QwtPlotLegendItem::backgroundMode() const
00518 {
00519 return d_data->backgroundMode;
00520 }
00521
00528 void QwtPlotLegendItem::setTextPen( const QPen &pen )
00529 {
00530 if ( d_data->textPen != pen )
00531 {
00532 d_data->textPen = pen;
00533 itemChanged();
00534 }
00535 }
00536
00541 QPen QwtPlotLegendItem::textPen() const
00542 {
00543 return d_data->textPen;
00544 }
00545
00554 void QwtPlotLegendItem::draw( QPainter *painter,
00555 const QwtScaleMap &xMap, const QwtScaleMap &yMap,
00556 const QRectF &canvasRect ) const
00557 {
00558 Q_UNUSED( xMap );
00559 Q_UNUSED( yMap );
00560
00561 d_data->layout->setGeometry( geometry( canvasRect ) );
00562 if ( d_data->layout->geometry().isEmpty() )
00563 {
00564
00565 return;
00566 }
00567
00568 if ( d_data->backgroundMode == QwtPlotLegendItem::LegendBackground )
00569 drawBackground( painter, d_data->layout->geometry() );
00570
00571 for ( int i = 0; i < d_data->layout->count(); i++ )
00572 {
00573 const QwtLegendLayoutItem *layoutItem =
00574 static_cast<QwtLegendLayoutItem *>( d_data->layout->itemAt( i ) );
00575
00576 if ( d_data->backgroundMode == QwtPlotLegendItem::ItemBackground )
00577 drawBackground( painter, layoutItem->geometry() );
00578
00579 painter->save();
00580
00581 drawLegendData( painter, layoutItem->plotItem(),
00582 layoutItem->data(), layoutItem->geometry() );
00583
00584 painter->restore();
00585 }
00586 }
00587
00597 void QwtPlotLegendItem::drawBackground(
00598 QPainter *painter, const QRectF &rect ) const
00599 {
00600 painter->save();
00601
00602 painter->setPen( d_data->borderPen );
00603 painter->setBrush( d_data->backgroundBrush );
00604
00605 const double radius = d_data->borderRadius;
00606 painter->drawRoundedRect( rect, radius, radius );
00607
00608 painter->restore();
00609 }
00610
00617 QRect QwtPlotLegendItem::geometry( const QRectF &canvasRect ) const
00618 {
00619 QRect rect;
00620 rect.setSize( d_data->layout->sizeHint() );
00621
00622 int margin = d_data->borderDistance;
00623 if ( d_data->alignment & Qt::AlignHCenter )
00624 {
00625 int x = qRound( canvasRect.center().x() );
00626 rect.moveCenter( QPoint( x, rect.center().y() ) );
00627 }
00628 else if ( d_data->alignment & Qt::AlignRight )
00629 {
00630 rect.moveRight( qFloor( canvasRect.right() - margin ) );
00631 }
00632 else
00633 {
00634 rect.moveLeft( qCeil( canvasRect.left() + margin ) );
00635 }
00636
00637 if ( d_data->alignment & Qt::AlignVCenter )
00638 {
00639 int y = qRound( canvasRect.center().y() );
00640 rect.moveCenter( QPoint( rect.center().x(), y ) );
00641 }
00642 else if ( d_data->alignment & Qt::AlignBottom )
00643 {
00644 rect.moveBottom( qFloor( canvasRect.bottom() - margin ) );
00645 }
00646 else
00647 {
00648 rect.moveTop( qCeil( canvasRect.top() + margin ) );
00649 }
00650
00651 return rect;
00652 }
00653
00661 void QwtPlotLegendItem::updateLegend( const QwtPlotItem *plotItem,
00662 const QList<QwtLegendData> &data )
00663 {
00664 if ( plotItem == NULL )
00665 return;
00666
00667 QList<QwtLegendLayoutItem *> layoutItems;
00668
00669 QMap<const QwtPlotItem *, QList<QwtLegendLayoutItem *> >::const_iterator it =
00670 d_data->map.constFind( plotItem );
00671 if ( it != d_data->map.constEnd() )
00672 layoutItems = it.value();
00673
00674 bool changed = false;
00675
00676 if ( data.size() != layoutItems.size() )
00677 {
00678 changed = true;
00679
00680 for ( int i = 0; i < layoutItems.size(); i++ )
00681 {
00682 d_data->layout->removeItem( layoutItems[i] );
00683 delete layoutItems[i];
00684 }
00685 layoutItems.clear();
00686
00687 if ( it != d_data->map.end() )
00688 d_data->map.remove( plotItem );
00689
00690 if ( !data.isEmpty() )
00691 {
00692 #if QT_VERSION >= 0x040700
00693 layoutItems.reserve( data.size() );
00694 #endif
00695 for ( int i = 0; i < data.size(); i++ )
00696 {
00697 QwtLegendLayoutItem *layoutItem =
00698 new QwtLegendLayoutItem( this, plotItem );
00699 d_data->layout->addItem( layoutItem );
00700 layoutItems += layoutItem;
00701 }
00702
00703 d_data->map.insert( plotItem, layoutItems );
00704 }
00705 }
00706
00707 for ( int i = 0; i < data.size(); i++ )
00708 {
00709 if ( layoutItems[i]->data().values() != data[i].values() )
00710 {
00711 layoutItems[i]->setData( data[i] );
00712 changed = true;
00713 }
00714 }
00715
00716 if ( changed )
00717 {
00718 d_data->layout->invalidate();
00719 itemChanged();
00720 }
00721 }
00722
00724 void QwtPlotLegendItem::clearLegend()
00725 {
00726 if ( !d_data->map.isEmpty() )
00727 {
00728 d_data->map.clear();
00729
00730 for ( int i = d_data->layout->count() - 1; i >= 0; i-- )
00731 delete d_data->layout->takeAt( i );
00732
00733 itemChanged();
00734 }
00735 }
00736
00745 void QwtPlotLegendItem::drawLegendData( QPainter *painter,
00746 const QwtPlotItem *plotItem, const QwtLegendData &data,
00747 const QRectF &rect ) const
00748 {
00749 Q_UNUSED( plotItem );
00750
00751 const int m = d_data->itemMargin;
00752 const QRectF r = rect.toRect().adjusted( m, m, -m, -m );
00753
00754 painter->setClipRect( r, Qt::IntersectClip );
00755
00756 int titleOff = 0;
00757
00758 const QwtGraphic graphic = data.icon();
00759 if ( !graphic.isEmpty() )
00760 {
00761 QRectF iconRect( r.topLeft(), graphic.defaultSize() );
00762
00763 iconRect.moveCenter(
00764 QPoint( iconRect.center().x(), rect.center().y() ) );
00765
00766 graphic.render( painter, iconRect, Qt::KeepAspectRatio );
00767
00768 titleOff += iconRect.width() + d_data->itemSpacing;
00769 }
00770
00771 const QwtText text = data.title();
00772 if ( !text.isEmpty() )
00773 {
00774 painter->setPen( textPen() );
00775 painter->setFont( font() );
00776
00777 const QRectF textRect = r.adjusted( titleOff, 0, 0, 0 );
00778 text.draw( painter, textRect );
00779 }
00780 }
00781
00788 QSize QwtPlotLegendItem::minimumSize( const QwtLegendData &data ) const
00789 {
00790 QSize size( 2 * d_data->itemMargin, 2 * d_data->itemMargin );
00791
00792 if ( !data.isValid() )
00793 return size;
00794
00795 const QwtGraphic graphic = data.icon();
00796 const QwtText text = data.title();
00797
00798 int w = 0;
00799 int h = 0;
00800
00801 if ( !graphic.isNull() )
00802 {
00803 w = graphic.width();
00804 h = graphic.height();
00805 }
00806
00807 if ( !text.isEmpty() )
00808 {
00809 const QSizeF sz = text.textSize( font() );
00810
00811 w += qCeil( sz.width() );
00812 h = qMax( h, qCeil( sz.height() ) );
00813 }
00814
00815 if ( graphic.width() > 0 && !text.isEmpty() )
00816 w += d_data->itemSpacing;
00817
00818 size += QSize( w, h );
00819 return size;
00820 }
00821
00827 int QwtPlotLegendItem::heightForWidth(
00828 const QwtLegendData &data, int width ) const
00829 {
00830 width -= 2 * d_data->itemMargin;
00831
00832 const QwtGraphic graphic = data.icon();
00833 const QwtText text = data.title();
00834
00835 if ( text.isEmpty() )
00836 return graphic.height();
00837
00838 if ( graphic.width() > 0 )
00839 width -= graphic.width() + d_data->itemSpacing;
00840
00841 int h = text.heightForWidth( width, font() );
00842 h += 2 * d_data->itemMargin;
00843
00844 return qMax( graphic.height(), h );
00845 }
00846
00851 QList< const QwtPlotItem * > QwtPlotLegendItem::plotItems() const
00852 {
00853 return d_data->map.keys();
00854 }
00855
00860 QList< QRect > QwtPlotLegendItem::legendGeometries(
00861 const QwtPlotItem *plotItem ) const
00862 {
00863 QList<QwtLegendLayoutItem *> layoutItems;
00864
00865 QMap<const QwtPlotItem *, QList<QwtLegendLayoutItem *> >::const_iterator it =
00866 d_data->map.constFind( plotItem );
00867 if ( it != d_data->map.constEnd() )
00868 layoutItems = it.value();
00869
00870 QList<QRect> geometries;
00871 #if QT_VERSION >= 0x040700
00872 geometries.reserve(layoutItems.size());
00873 #endif
00874
00875 for ( int i = 0; i < layoutItems.size(); i++ )
00876 geometries += layoutItems[i]->geometry();
00877
00878 return geometries;
00879 }