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 *> >::iterator it =
00670 d_data->map.find( plotItem );
00671 if ( it != d_data->map.end() )
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 for ( int i = 0; i < data.size(); i++ )
00693 {
00694 QwtLegendLayoutItem *layoutItem =
00695 new QwtLegendLayoutItem( this, plotItem );
00696 d_data->layout->addItem( layoutItem );
00697 layoutItems += layoutItem;
00698 }
00699
00700 d_data->map.insert( plotItem, layoutItems );
00701 }
00702 }
00703
00704 for ( int i = 0; i < data.size(); i++ )
00705 {
00706 if ( layoutItems[i]->data().values() != data[i].values() )
00707 {
00708 layoutItems[i]->setData( data[i] );
00709 changed = true;
00710 }
00711 }
00712
00713 if ( changed )
00714 {
00715 d_data->layout->invalidate();
00716 itemChanged();
00717 }
00718 }
00719
00721 void QwtPlotLegendItem::clearLegend()
00722 {
00723 if ( !d_data->map.isEmpty() )
00724 {
00725 d_data->map.clear();
00726
00727 for ( int i = d_data->layout->count() - 1; i >= 0; i-- )
00728 delete d_data->layout->takeAt( i );
00729
00730 itemChanged();
00731 }
00732 }
00733
00742 void QwtPlotLegendItem::drawLegendData( QPainter *painter,
00743 const QwtPlotItem *plotItem, const QwtLegendData &data,
00744 const QRectF &rect ) const
00745 {
00746 Q_UNUSED( plotItem );
00747
00748 const int m = d_data->itemMargin;
00749 const QRectF r = rect.toRect().adjusted( m, m, -m, -m );
00750
00751 painter->setClipRect( r, Qt::IntersectClip );
00752
00753 int titleOff = 0;
00754
00755 const QwtGraphic graphic = data.icon();
00756 if ( !graphic.isEmpty() )
00757 {
00758 QRectF iconRect( r.topLeft(), graphic.defaultSize() );
00759
00760 iconRect.moveCenter(
00761 QPoint( iconRect.center().x(), rect.center().y() ) );
00762
00763 graphic.render( painter, iconRect, Qt::KeepAspectRatio );
00764
00765 titleOff += iconRect.width() + d_data->itemSpacing;
00766 }
00767
00768 const QwtText text = data.title();
00769 if ( !text.isEmpty() )
00770 {
00771 painter->setPen( textPen() );
00772 painter->setFont( font() );
00773
00774 const QRectF textRect = r.adjusted( titleOff, 0, 0, 0 );
00775 text.draw( painter, textRect );
00776 }
00777 }
00778
00785 QSize QwtPlotLegendItem::minimumSize( const QwtLegendData &data ) const
00786 {
00787 QSize size( 2 * d_data->itemMargin, 2 * d_data->itemMargin );
00788
00789 if ( !data.isValid() )
00790 return size;
00791
00792 const QwtGraphic graphic = data.icon();
00793 const QwtText text = data.title();
00794
00795 int w = 0;
00796 int h = 0;
00797
00798 if ( !graphic.isNull() )
00799 {
00800 w = graphic.width();
00801 h = graphic.height();
00802 }
00803
00804 if ( !text.isEmpty() )
00805 {
00806 const QSizeF sz = text.textSize( font() );
00807
00808 w += qCeil( sz.width() );
00809 h = qMax( h, qCeil( sz.height() ) );
00810 }
00811
00812 if ( graphic.width() > 0 && !text.isEmpty() )
00813 w += d_data->itemSpacing;
00814
00815 size += QSize( w, h );
00816 return size;
00817 }
00818
00824 int QwtPlotLegendItem::heightForWidth(
00825 const QwtLegendData &data, int width ) const
00826 {
00827 width -= 2 * d_data->itemMargin;
00828
00829 const QwtGraphic graphic = data.icon();
00830 const QwtText text = data.title();
00831
00832 if ( text.isEmpty() )
00833 return graphic.height();
00834
00835 if ( graphic.width() > 0 )
00836 width -= graphic.width() + d_data->itemSpacing;
00837
00838 int h = text.heightForWidth( width, font() );
00839 h += 2 * d_data->itemMargin;
00840
00841 return qMax( graphic.height(), h );
00842 }
00843
00848 QList< const QwtPlotItem * > QwtPlotLegendItem::plotItems() const
00849 {
00850 return d_data->map.keys();
00851 }
00852
00857 QList< QRect > QwtPlotLegendItem::legendGeometries(
00858 const QwtPlotItem *plotItem ) const
00859 {
00860 QList<QwtLegendLayoutItem *> layoutItems;
00861
00862 QMap<const QwtPlotItem *, QList<QwtLegendLayoutItem *> >::iterator it =
00863 d_data->map.find( plotItem );
00864 if ( it != d_data->map.end() )
00865 layoutItems = it.value();
00866
00867 QList<QRect> geometries;
00868 for ( int i = 0; i < layoutItems.size(); i++ )
00869 geometries += layoutItems[i]->geometry();
00870
00871 return geometries;
00872 }