Changeset 8127 in ntrip for trunk/BNC/qwt/qwt_plot.cpp


Ignore:
Timestamp:
May 10, 2017, 3:20:54 PM (7 years ago)
Author:
stoecker
Message:

update qwt and qwtpolar, many QT5 fixes (unfinished)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/BNC/qwt/qwt_plot.cpp

    r4271 r8127  
    1515#include "qwt_text_label.h"
    1616#include "qwt_legend.h"
    17 #include "qwt_dyngrid_layout.h"
     17#include "qwt_legend_data.h"
    1818#include "qwt_plot_canvas.h"
     19#include <qmath.h>
    1920#include <qpainter.h>
    2021#include <qpointer.h>
     
    2324#include <qevent.h>
    2425
     26static inline void qwtEnableLegendItems( QwtPlot *plot, bool on )
     27{
     28    if ( on )
     29    {
     30        QObject::connect(
     31            plot, SIGNAL( legendDataChanged(
     32                const QVariant &, const QList<QwtLegendData> & ) ),
     33            plot, SLOT( updateLegendItems(
     34                const QVariant &, const QList<QwtLegendData> & ) ) );
     35    }
     36    else
     37    {
     38        QObject::disconnect(
     39            plot, SIGNAL( legendDataChanged(
     40                const QVariant &, const QList<QwtLegendData> & ) ),
     41            plot, SLOT( updateLegendItems(
     42                const QVariant &, const QList<QwtLegendData> & ) ) );
     43    }
     44}
     45
     46static void qwtSetTabOrder(
     47    QWidget *first, QWidget *second, bool withChildren )
     48{
     49    QList<QWidget *> tabChain;
     50    tabChain += first;
     51    tabChain += second;
     52
     53    if ( withChildren )
     54    {
     55        QList<QWidget *> children = second->findChildren<QWidget *>();
     56
     57        QWidget *w = second->nextInFocusChain();
     58        while ( children.contains( w ) )
     59        {
     60            children.removeAll( w );
     61
     62            tabChain += w;
     63            w = w->nextInFocusChain();
     64        }
     65    }
     66
     67    for ( int i = 0; i < tabChain.size() - 1; i++ )
     68    {
     69        QWidget *from = tabChain[i];
     70        QWidget *to = tabChain[i+1];
     71
     72        const Qt::FocusPolicy policy1 = from->focusPolicy();
     73        const Qt::FocusPolicy policy2 = to->focusPolicy();
     74
     75        QWidget *proxy1 = from->focusProxy();
     76        QWidget *proxy2 = to->focusProxy();
     77
     78        from->setFocusPolicy( Qt::TabFocus );
     79        from->setFocusProxy( NULL);
     80
     81        to->setFocusPolicy( Qt::TabFocus );
     82        to->setFocusProxy( NULL);
     83
     84        QWidget::setTabOrder( from, to );
     85
     86        from->setFocusPolicy( policy1 );
     87        from->setFocusProxy( proxy1);
     88
     89        to->setFocusPolicy( policy2 );
     90        to->setFocusProxy( proxy2 );
     91    }
     92}
     93
    2594class QwtPlot::PrivateData
    2695{
    2796public:
    28     QPointer<QwtTextLabel> lblTitle;
    29     QPointer<QwtPlotCanvas> canvas;
    30     QPointer<QwtLegend> legend;
     97    QPointer<QwtTextLabel> titleLabel;
     98    QPointer<QwtTextLabel> footerLabel;
     99    QPointer<QWidget> canvas;
     100    QPointer<QwtAbstractLegend> legend;
    31101    QwtPlotLayout *layout;
    32102
     
    58128QwtPlot::~QwtPlot()
    59129{
     130    setAutoReplot( false );
    60131    detachItems( QwtPlotItem::Rtti_PlotItem, autoDelete() );
    61132
     
    76147    d_data->autoReplot = false;
    77148
    78     d_data->lblTitle = new QwtTextLabel( title, this );
    79     d_data->lblTitle->setObjectName( "QwtPlotTitle" );
    80 
    81     d_data->lblTitle->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) );
     149    // title
     150    d_data->titleLabel = new QwtTextLabel( this );
     151    d_data->titleLabel->setObjectName( "QwtPlotTitle" );
     152    d_data->titleLabel->setFont( QFont( fontInfo().family(), 14, QFont::Bold ) );
    82153
    83154    QwtText text( title );
    84155    text.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap );
    85     d_data->lblTitle->setText( text );
    86 
     156    d_data->titleLabel->setText( text );
     157
     158    // footer
     159    d_data->footerLabel = new QwtTextLabel( this );
     160    d_data->footerLabel->setObjectName( "QwtPlotFooter" );
     161
     162    QwtText footer;
     163    footer.setRenderFlags( Qt::AlignCenter | Qt::TextWordWrap );
     164    d_data->footerLabel->setText( footer );
     165
     166    // legend
    87167    d_data->legend = NULL;
    88168
     169    // axis
    89170    initAxesData();
    90171
     172    // canvas
    91173    d_data->canvas = new QwtPlotCanvas( this );
    92174    d_data->canvas->setObjectName( "QwtPlotCanvas" );
    93     d_data->canvas->setFrameStyle( QFrame::Panel | QFrame::Sunken );
    94     d_data->canvas->setLineWidth( 2 );
    95 
    96     updateTabOrder();
     175    d_data->canvas->installEventFilter( this );
    97176
    98177    setSizePolicy( QSizePolicy::MinimumExpanding,
     
    100179
    101180    resize( 200, 200 );
     181
     182    QList<QWidget *> focusChain;
     183    focusChain << this << d_data->titleLabel << axisWidget( xTop )
     184        << axisWidget( yLeft ) << d_data->canvas << axisWidget( yRight )
     185        << axisWidget( xBottom ) << d_data->footerLabel;
     186
     187    for ( int i = 0; i < focusChain.size() - 1; i++ )
     188        qwtSetTabOrder( focusChain[i], focusChain[i+1], false );
     189
     190    qwtEnableLegendItems( this, true );
     191}
     192
     193/*!
     194  \brief Set the drawing canvas of the plot widget
     195
     196  QwtPlot invokes methods of the canvas as meta methods ( see QMetaObject ).
     197  In opposite to using conventional C++ techniques like virtual methods
     198  they allow to use canvas implementations that are derived from
     199  QWidget or QGLWidget.
     200
     201  The following meta methods could be implemented:
     202
     203  - replot()
     204    When the canvas doesn't offer a replot method, QwtPlot calls
     205    update() instead.
     206
     207  - borderPath()
     208    The border path is necessary to clip the content of the canvas
     209    When the canvas doesn't have any special border ( f.e rounded corners )
     210    it is o.k. not to implement this method.
     211
     212  The default canvas is a QwtPlotCanvas
     213
     214  \param canvas Canvas Widget
     215  \sa canvas()
     216 */
     217void QwtPlot::setCanvas( QWidget *canvas )
     218{
     219    if ( canvas == d_data->canvas )
     220        return;
     221
     222    delete d_data->canvas;
     223    d_data->canvas = canvas;
     224
     225    if ( canvas )
     226    {
     227        canvas->setParent( this );
     228        canvas->installEventFilter( this );
     229
     230        if ( isVisible() )
     231            canvas->show();
     232    }
    102233}
    103234
     
    105236  \brief Adds handling of layout requests
    106237  \param event Event
     238
     239  \return See QFrame::event()
    107240*/
    108241bool QwtPlot::event( QEvent *event )
     
    122255}
    123256
     257/*!
     258  \brief Event filter
     259
     260  The plot handles the following events for the canvas:
     261
     262  - QEvent::Resize
     263    The canvas margins might depend on its size
     264
     265  - QEvent::ContentsRectChange
     266    The layout needs to be recalculated
     267
     268  \param object Object to be filtered
     269  \param event Event
     270
     271  \return See QFrame::eventFilter()
     272
     273  \sa updateCanvasMargins(), updateLayout()
     274*/
     275bool QwtPlot::eventFilter( QObject *object, QEvent *event )
     276{
     277    if ( object == d_data->canvas )
     278    {
     279        if ( event->type() == QEvent::Resize )
     280        {
     281            updateCanvasMargins();
     282        }
     283        else if ( event->type() == QEvent::ContentsRectChange )
     284        {
     285            updateLayout();
     286        }
     287    }
     288
     289    return QFrame::eventFilter( object, event );
     290}
     291
    124292//! Replots the plot if autoReplot() is \c true.
    125293void QwtPlot::autoRefresh()
     
    164332void QwtPlot::setTitle( const QString &title )
    165333{
    166     if ( title != d_data->lblTitle->text().text() )
    167     {
    168         d_data->lblTitle->setText( title );
     334    if ( title != d_data->titleLabel->text().text() )
     335    {
     336        d_data->titleLabel->setText( title );
    169337        updateLayout();
    170338    }
     
    177345void QwtPlot::setTitle( const QwtText &title )
    178346{
    179     if ( title != d_data->lblTitle->text() )
    180     {
    181         d_data->lblTitle->setText( title );
     347    if ( title != d_data->titleLabel->text() )
     348    {
     349        d_data->titleLabel->setText( title );
    182350        updateLayout();
    183351    }
    184352}
    185353
    186 //! \return the plot's title
     354//! \return Title of the plot
    187355QwtText QwtPlot::title() const
    188356{
    189     return d_data->lblTitle->text();
    190 }
    191 
    192 //! \return the plot's title
     357    return d_data->titleLabel->text();
     358}
     359
     360//! \return Title label widget.
     361QwtTextLabel *QwtPlot::titleLabel()
     362{
     363    return d_data->titleLabel;
     364}
     365
     366//! \return Title label widget.
     367const QwtTextLabel *QwtPlot::titleLabel() const
     368{
     369    return d_data->titleLabel;
     370}
     371
     372/*!
     373  Change the text the footer
     374  \param text New text of the footer
     375*/
     376void QwtPlot::setFooter( const QString &text )
     377{
     378    if ( text != d_data->footerLabel->text().text() )
     379    {
     380        d_data->footerLabel->setText( text );
     381        updateLayout();
     382    }
     383}
     384
     385/*!
     386  Change the text the footer
     387  \param text New text of the footer
     388*/
     389void QwtPlot::setFooter( const QwtText &text )
     390{
     391    if ( text != d_data->footerLabel->text() )
     392    {
     393        d_data->footerLabel->setText( text );
     394        updateLayout();
     395    }
     396}
     397
     398//! \return Text of the footer
     399QwtText QwtPlot::footer() const
     400{
     401    return d_data->footerLabel->text();
     402}
     403
     404//! \return Footer label widget.
     405QwtTextLabel *QwtPlot::footerLabel()
     406{
     407    return d_data->footerLabel;
     408}
     409
     410//! \return Footer label widget.
     411const QwtTextLabel *QwtPlot::footerLabel() const
     412{
     413    return d_data->footerLabel;
     414}
     415
     416/*!
     417   \brief Assign a new plot layout
     418
     419   \param layout Layout()
     420   \sa plotLayout()
     421 */
     422void QwtPlot::setPlotLayout( QwtPlotLayout *layout )
     423{
     424    if ( layout != d_data->layout )
     425    {
     426        delete d_data->layout;
     427        d_data->layout = layout;
     428
     429        updateLayout();
     430    }
     431}
     432
     433//! \return the plot's layout
    193434QwtPlotLayout *QwtPlot::plotLayout()
    194435{
     
    196437}
    197438
    198 //! \return the plot's titel label.
     439//! \return the plot's layout
    199440const QwtPlotLayout *QwtPlot::plotLayout() const
    200441{
    201442    return d_data->layout;
    202 }
    203 
    204 //! \return the plot's titel label.
    205 QwtTextLabel *QwtPlot::titleLabel()
    206 {
    207     return d_data->lblTitle;
    208 }
    209 
    210 /*!
    211   \return the plot's titel label.
    212 */
    213 const QwtTextLabel *QwtPlot::titleLabel() const
    214 {
    215     return d_data->lblTitle;
    216443}
    217444
     
    220447  \sa insertLegend()
    221448*/
    222 QwtLegend *QwtPlot::legend()
     449QwtAbstractLegend *QwtPlot::legend()
    223450{
    224451    return d_data->legend;
     
    229456  \sa insertLegend()
    230457*/
    231 const QwtLegend *QwtPlot::legend() const
     458const QwtAbstractLegend *QwtPlot::legend() const
    232459{
    233460    return d_data->legend;
     
    238465  \return the plot's canvas
    239466*/
    240 QwtPlotCanvas *QwtPlot::canvas()
     467QWidget *QwtPlot::canvas()
    241468{
    242469    return d_data->canvas;
     
    246473  \return the plot's canvas
    247474*/
    248 const QwtPlotCanvas *QwtPlot::canvas() const
     475const QWidget *QwtPlot::canvas() const
    249476{
    250477    return d_data->canvas;
     
    252479
    253480/*!
    254   Return sizeHint
     481  \return Size hint for the plot widget
    255482  \sa minimumSizeHint()
    256483*/
    257 
    258484QSize QwtPlot::sizeHint() const
    259485{
     
    316542  be refreshed explicitly in order to make changes visible.
    317543
    318   \sa setAutoReplot()
    319   \warning Calls canvas()->repaint, take care of infinite recursions
     544  \sa updateAxes(), setAutoReplot()
    320545*/
    321546void QwtPlot::replot()
     
    333558    QApplication::sendPostedEvents( this, QEvent::LayoutRequest );
    334559
    335     d_data->canvas->replot();
     560    if ( d_data->canvas )
     561    {
     562        const bool ok = QMetaObject::invokeMethod(
     563            d_data->canvas, "replot", Qt::DirectConnection );
     564        if ( !ok )
     565        {
     566            // fallback, when canvas has no a replot method
     567            d_data->canvas->update( d_data->canvas->contentsRect() );
     568        }
     569    }
    336570
    337571    setAutoReplot( doAutoReplot );
     
    347581
    348582    QRect titleRect = d_data->layout->titleRect().toRect();
     583    QRect footerRect = d_data->layout->footerRect().toRect();
    349584    QRect scaleRect[QwtPlot::axisCnt];
    350585    for ( int axisId = 0; axisId < axisCnt; axisId++ )
     
    353588    QRect canvasRect = d_data->layout->canvasRect().toRect();
    354589
    355     //
    356590    // resize and show the visible widgets
    357     //
    358     if ( !d_data->lblTitle->text().isEmpty() )
    359     {
    360         d_data->lblTitle->setGeometry( titleRect );
    361         if ( !d_data->lblTitle->isVisibleTo( this ) )
    362             d_data->lblTitle->show();
     591
     592    if ( !d_data->titleLabel->text().isEmpty() )
     593    {
     594        d_data->titleLabel->setGeometry( titleRect );
     595        if ( !d_data->titleLabel->isVisibleTo( this ) )
     596            d_data->titleLabel->show();
    363597    }
    364598    else
    365         d_data->lblTitle->hide();
     599        d_data->titleLabel->hide();
     600
     601    if ( !d_data->footerLabel->text().isEmpty() )
     602    {
     603        d_data->footerLabel->setGeometry( footerRect );
     604        if ( !d_data->footerLabel->isVisibleTo( this ) )
     605            d_data->footerLabel->show();
     606    }
     607    else
     608    {
     609        d_data->footerLabel->hide();
     610    }
    366611
    367612    for ( int axisId = 0; axisId < axisCnt; axisId++ )
    368613    {
     614        QwtScaleWidget* scaleWidget = axisWidget( axisId );
     615
    369616        if ( axisEnabled( axisId ) )
    370617        {
    371             axisWidget( axisId )->setGeometry( scaleRect[axisId] );
    372 
     618            if ( scaleRect[axisId] != scaleWidget->geometry() )
     619            {
     620                scaleWidget->setGeometry( scaleRect[axisId] );
     621
     622                int startDist, endDist;
     623                scaleWidget->getBorderDistHint( startDist, endDist );
     624                scaleWidget->setBorderDist( startDist, endDist );
     625            }
     626
     627#if 1
    373628            if ( axisId == xBottom || axisId == xTop )
    374629            {
     630                // do we need this code any longer ???
     631
    375632                QRegion r( scaleRect[axisId] );
    376633                if ( axisEnabled( yLeft ) )
    377                     r = r.subtract( QRegion( scaleRect[yLeft] ) );
     634                    r = r.subtracted( QRegion( scaleRect[yLeft] ) );
    378635                if ( axisEnabled( yRight ) )
    379                     r = r.subtract( QRegion( scaleRect[yRight] ) );
    380                 r.translate( -d_data->layout->scaleRect( axisId ).x(),
     636                    r = r.subtracted( QRegion( scaleRect[yRight] ) );
     637                r.translate( -scaleRect[ axisId ].x(),
    381638                    -scaleRect[axisId].y() );
    382639
    383                 axisWidget( axisId )->setMask( r );
     640                scaleWidget->setMask( r );
    384641            }
    385             if ( !axisWidget( axisId )->isVisibleTo( this ) )
    386                 axisWidget( axisId )->show();
     642#endif
     643            if ( !scaleWidget->isVisibleTo( this ) )
     644                scaleWidget->show();
    387645        }
    388646        else
    389             axisWidget( axisId )->hide();
    390     }
    391 
    392     if ( d_data->legend &&
    393         d_data->layout->legendPosition() != ExternalLegend )
    394     {
    395         if ( d_data->legend->itemCount() > 0 )
     647        {
     648            scaleWidget->hide();
     649        }
     650    }
     651
     652    if ( d_data->legend )
     653    {
     654        if ( d_data->legend->isEmpty() )
     655        {
     656            d_data->legend->hide();
     657        }
     658        else
    396659        {
    397660            d_data->legend->setGeometry( legendRect );
    398661            d_data->legend->show();
    399662        }
    400         else
    401             d_data->legend->hide();
    402663    }
    403664
     
    406667
    407668/*!
    408    Update the focus tab order
    409 
    410    The order is changed so that the canvas will be in front of the
    411    first legend item, or behind the last legend item - depending
    412    on the position of the legend.
    413 */
    414 
    415 void QwtPlot::updateTabOrder()
    416 {
    417     if ( d_data->canvas->focusPolicy() == Qt::NoFocus )
    418         return;
    419     if ( d_data->legend.isNull()
    420         || d_data->layout->legendPosition() == ExternalLegend
    421         || d_data->legend->legendItems().count() == 0 )
    422     {
    423         return;
    424     }
    425 
    426     // Depending on the position of the legend the
    427     // tab order will be changed that the canvas is
    428     // next to the last legend item, or before
    429     // the first one.
    430 
    431     const bool canvasFirst =
    432         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
    433         d_data->layout->legendPosition() == QwtPlot::RightLegend;
    434 
    435     QWidget *previous = NULL;
    436 
    437     QWidget *w = d_data->canvas;
    438     while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
    439     {
    440         bool isLegendItem = false;
    441         if ( w->focusPolicy() != Qt::NoFocus
    442             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
    443         {
    444             isLegendItem = true;
    445         }
    446 
    447         if ( canvasFirst )
    448         {
    449             if ( isLegendItem )
    450                 break;
    451 
    452             previous = w;
    453         }
    454         else
    455         {
    456             if ( isLegendItem )
    457                 previous = w;
    458             else
    459             {
    460                 if ( previous )
    461                     break;
    462             }
    463         }
    464     }
    465 
    466     if ( previous && previous != d_data->canvas )
    467         setTabOrder( previous, d_data->canvas );
     669  \brief Calculate the canvas margins
     670
     671  \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
     672  \param canvasRect Bounding rectangle where to paint
     673  \param left Return parameter for the left margin
     674  \param top Return parameter for the top margin
     675  \param right Return parameter for the right margin
     676  \param bottom Return parameter for the bottom margin
     677
     678  Plot items might indicate, that they need some extra space
     679  at the borders of the canvas by the QwtPlotItem::Margins flag.
     680
     681  updateCanvasMargins(), QwtPlotItem::getCanvasMarginHint()
     682 */
     683void QwtPlot::getCanvasMarginsHint(
     684    const QwtScaleMap maps[], const QRectF &canvasRect,
     685    double &left, double &top, double &right, double &bottom) const
     686{
     687    left = top = right = bottom = -1.0;
     688
     689    const QwtPlotItemList& itmList = itemList();
     690    for ( QwtPlotItemIterator it = itmList.begin();
     691        it != itmList.end(); ++it )
     692    {
     693        const QwtPlotItem *item = *it;
     694        if ( item->testItemAttribute( QwtPlotItem::Margins ) )
     695        {
     696            double m[ QwtPlot::axisCnt ];
     697            item->getCanvasMarginHint(
     698                maps[ item->xAxis() ], maps[ item->yAxis() ],
     699                canvasRect, m[yLeft], m[xTop], m[yRight], m[xBottom] );
     700
     701            left = qMax( left, m[yLeft] );
     702            top = qMax( top, m[xTop] );
     703            right = qMax( right, m[yRight] );
     704            bottom = qMax( bottom, m[xBottom] );
     705        }
     706    }
     707}
     708
     709/*!
     710  \brief Update the canvas margins
     711
     712  Plot items might indicate, that they need some extra space
     713  at the borders of the canvas by the QwtPlotItem::Margins flag.
     714
     715  getCanvasMarginsHint(), QwtPlotItem::getCanvasMarginHint()
     716 */
     717void QwtPlot::updateCanvasMargins()
     718{
     719    QwtScaleMap maps[axisCnt];
     720    for ( int axisId = 0; axisId < axisCnt; axisId++ )
     721        maps[axisId] = canvasMap( axisId );
     722
     723    double margins[axisCnt];
     724    getCanvasMarginsHint( maps, canvas()->contentsRect(),
     725        margins[yLeft], margins[xTop], margins[yRight], margins[xBottom] );
     726   
     727    bool doUpdate = false;
     728    for ( int axisId = 0; axisId < axisCnt; axisId++ )
     729    {
     730        if ( margins[axisId] >= 0.0 )
     731        {
     732            const int m = qCeil( margins[axisId] );
     733            plotLayout()->setCanvasMargin( m, axisId);
     734            doUpdate = true;
     735        }
     736    }
     737
     738    if ( doUpdate )
     739        updateLayout();
    468740}
    469741
     
    488760/*!
    489761  Redraw the canvas items.
     762
    490763  \param painter Painter used for drawing
    491764  \param canvasRect Bounding rectangle where to paint
    492   \param map QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
     765  \param maps QwtPlot::axisCnt maps, mapping between plot and paint device coordinates
     766
     767  \note Usually canvasRect is contentsRect() of the plot canvas.
     768        Due to a bug in Qt this rectangle might be wrong for certain
     769        frame styles ( f.e QFrame::Box ) and it might be necessary to
     770        fix the margins manually using QWidget::setContentsMargins()
    493771*/
    494772
    495773void QwtPlot::drawItems( QPainter *painter, const QRectF &canvasRect,
    496         const QwtScaleMap map[axisCnt] ) const
     774        const QwtScaleMap maps[axisCnt] ) const
    497775{
    498776    const QwtPlotItemList& itmList = itemList();
     
    507785            painter->setRenderHint( QPainter::Antialiasing,
    508786                item->testRenderHint( QwtPlotItem::RenderAntialiased ) );
     787            painter->setRenderHint( QPainter::HighQualityAntialiasing,
     788                item->testRenderHint( QwtPlotItem::RenderAntialiased ) );
    509789
    510790            item->draw( painter,
    511                 map[item->xAxis()], map[item->yAxis()],
     791                maps[item->xAxis()], maps[item->yAxis()],
    512792                canvasRect );
    513793
     
    532812    map.setTransformation( axisScaleEngine( axisId )->transformation() );
    533813
    534     const QwtScaleDiv *sd = axisScaleDiv( axisId );
    535     map.setScaleInterval( sd->lowerBound(), sd->upperBound() );
     814    const QwtScaleDiv &sd = axisScaleDiv( axisId );
     815    map.setScaleInterval( sd.lowerBound(), sd.upperBound() );
    536816
    537817    if ( axisEnabled( axisId ) )
     
    553833    else
    554834    {
    555         int margin = 0;
    556         if ( !plotLayout()->alignCanvasToScales() )
    557             margin = plotLayout()->canvasMargin( axisId );
    558 
    559835        const QRect &canvasRect = d_data->canvas->contentsRect();
    560836        if ( axisId == yLeft || axisId == yRight )
    561837        {
    562             map.setPaintInterval( canvasRect.bottom() - margin,
    563                 canvasRect.top() + margin );
     838            int top = 0;
     839            if ( !plotLayout()->alignCanvasToScale( xTop ) )
     840                top = plotLayout()->canvasMargin( xTop );
     841
     842            int bottom = 0;
     843            if ( !plotLayout()->alignCanvasToScale( xBottom ) )
     844                bottom = plotLayout()->canvasMargin( xBottom );
     845
     846            map.setPaintInterval( canvasRect.bottom() - bottom,
     847                canvasRect.top() + top );
    564848        }
    565849        else
    566850        {
    567             map.setPaintInterval( canvasRect.left() + margin,
    568                 canvasRect.right() - margin );
    569         }
    570     }
     851            int left = 0;
     852            if ( !plotLayout()->alignCanvasToScale( yLeft ) )
     853                left = plotLayout()->canvasMargin( yLeft );
     854
     855            int right = 0;
     856            if ( !plotLayout()->alignCanvasToScale( yRight ) )
     857                right = plotLayout()->canvasMargin( yRight );
     858
     859            map.setPaintInterval( canvasRect.left() + left,
     860                canvasRect.right() - right );
     861        }
     862    }
     863
    571864    return map;
    572865}
     
    575868  \brief Change the background of the plotting area
    576869
    577   Sets brush to QPalette::Window of all colorgroups of
     870  Sets brush to QPalette::Window of all color groups of
    578871  the palette of the canvas. Using canvas()->setPalette()
    579872  is a more powerful way to set these colors.
     
    585878{
    586879    QPalette pal = d_data->canvas->palette();
    587 
    588     for ( int i = 0; i < QPalette::NColorGroups; i++ )
    589         pal.setBrush( ( QPalette::ColorGroup )i, QPalette::Window, brush );
     880    pal.setBrush( QPalette::Window, brush );
    590881
    591882    canvas()->setPalette( pal );
     
    606897
    607898/*!
    608   \brief Change the border width of the plotting area
    609 
    610   Nothing else than canvas()->setLineWidth(w),
    611   left for compatibility only.
    612 
    613   \param width New border width
    614 */
    615 void QwtPlot::setCanvasLineWidth( int width )
    616 {
    617     canvas()->setLineWidth( width );
    618     updateLayout();
    619 }
    620 
    621 /*!
    622   Nothing else than: canvas()->lineWidth(),
    623   left for compatibility only.
    624 
    625   \return the border width of the plotting area
    626 */
    627 int QwtPlot::canvasLineWidth() const
    628 {
    629     return canvas()->lineWidth();
    630 }
    631 
    632 /*!
    633899  \return \c true if the specified axis exists, otherwise \c false
    634900  \param axisId axis index
     
    637903{
    638904    return ( ( axisId >= QwtPlot::yLeft ) && ( axisId < QwtPlot::axisCnt ) );
    639 }
    640 
    641 /*!
    642   Called internally when the legend has been clicked on.
    643   Emits a legendClicked() signal.
    644 */
    645 void QwtPlot::legendItemClicked()
    646 {
    647     if ( d_data->legend && sender()->isWidgetType() )
    648     {
    649         QwtPlotItem *plotItem =
    650             ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() );
    651         if ( plotItem )
    652             Q_EMIT legendClicked( plotItem );
    653     }
    654 }
    655 
    656 /*!
    657   Called internally when the legend has been checked
    658   Emits a legendClicked() signal.
    659 */
    660 void QwtPlot::legendItemChecked( bool on )
    661 {
    662     if ( d_data->legend && sender()->isWidgetType() )
    663     {
    664         QwtPlotItem *plotItem =
    665             ( QwtPlotItem* )d_data->legend->find( ( QWidget * )sender() );
    666         if ( plotItem )
    667             Q_EMIT legendChecked( plotItem, on );
    668     }
    669905}
    670906
     
    677913  with a best fit number of columns from left to right.
    678914
    679   If pos != QwtPlot::ExternalLegend the plot widget will become
    680   parent of the legend. It will be deleted when the plot is deleted,
    681   or another legend is set with insertLegend().
     915  insertLegend() will set the plot widget as parent for the legend.
     916  The legend will be deleted in the destructor of the plot or when
     917  another legend is inserted.
     918
     919  Legends, that are not inserted into the layout of the plot widget
     920  need to connect to the legendDataChanged() signal. Calling updateLegend()
     921  initiates this signal for an initial update. When the application code
     922  wants to implement its own layout this also needs to be done for
     923  rendering plots to a document ( see QwtPlotRenderer ).
    682924
    683925  \param legend Legend
    684926  \param pos The legend's position. For top/left position the number
    685              of colums will be limited to 1, otherwise it will be set to
     927             of columns will be limited to 1, otherwise it will be set to
    686928             unlimited.
    687929
    688   \param ratio Ratio between legend and the bounding rect
    689                of title, canvas and axes. The legend will be shrinked
     930  \param ratio Ratio between legend and the bounding rectangle
     931               of title, canvas and axes. The legend will be shrunk
    690932               if it would need more space than the given ratio.
    691933               The ratio is limited to ]0.0 .. 1.0]. In case of <= 0.0
     
    696938      QwtPlotLayout::setLegendPosition()
    697939*/
    698 void QwtPlot::insertLegend( QwtLegend *legend,
     940void QwtPlot::insertLegend( QwtAbstractLegend *legend,
    699941    QwtPlot::LegendPosition pos, double ratio )
    700942{
     
    710952        if ( d_data->legend )
    711953        {
    712             if ( pos != ExternalLegend )
    713             {
    714                 if ( d_data->legend->parent() != this )
    715                     d_data->legend->setParent( this );
    716             }
    717 
    718             const QwtPlotItemList& itmList = itemList();
    719             for ( QwtPlotItemIterator it = itmList.begin();
    720                 it != itmList.end(); ++it )
    721             {
    722                 ( *it )->updateLegend( d_data->legend );
    723             }
    724 
    725             QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
    726                 d_data->legend->contentsWidget()->layout() );
    727             if ( tl )
     954            connect( this,
     955                SIGNAL( legendDataChanged(
     956                    const QVariant &, const QList<QwtLegendData> & ) ),
     957                d_data->legend,
     958                SLOT( updateLegend(
     959                    const QVariant &, const QList<QwtLegendData> & ) )
     960            );
     961
     962            if ( d_data->legend->parent() != this )
     963                d_data->legend->setParent( this );
     964
     965            qwtEnableLegendItems( this, false );
     966            updateLegend();
     967            qwtEnableLegendItems( this, true );
     968
     969            QwtLegend *lgd = qobject_cast<QwtLegend *>( legend );
     970            if ( lgd )
    728971            {
    729972                switch ( d_data->layout->legendPosition() )
     
    731974                    case LeftLegend:
    732975                    case RightLegend:
    733                         tl->setMaxCols( 1 ); // 1 column: align vertical
     976                    {
     977                        if ( lgd->maxColumns() == 0     )
     978                            lgd->setMaxColumns( 1 ); // 1 column: align vertical
    734979                        break;
     980                    }
    735981                    case TopLegend:
    736982                    case BottomLegend:
    737                         tl->setMaxCols( 0 ); // unlimited
     983                    {
     984                        lgd->setMaxColumns( 0 ); // unlimited
    738985                        break;
    739                     case ExternalLegend:
     986                    }
     987                    default:
    740988                        break;
    741989                }
    742990            }
    743         }
    744         updateTabOrder();
     991
     992            QWidget *previousInChain = NULL;
     993            switch ( d_data->layout->legendPosition() )
     994            {
     995                case LeftLegend:
     996                {
     997                    previousInChain = axisWidget( QwtPlot::xTop );
     998                    break;
     999                }
     1000                case TopLegend:
     1001                {
     1002                    previousInChain = this;
     1003                    break;
     1004                }
     1005                case RightLegend:
     1006                {
     1007                    previousInChain = axisWidget( QwtPlot::yRight );
     1008                    break;
     1009                }
     1010                case BottomLegend:
     1011                {
     1012                    previousInChain = footerLabel();
     1013                    break;
     1014                }
     1015            }
     1016
     1017            if ( previousInChain )
     1018                qwtSetTabOrder( previousInChain, legend, true );
     1019        }
    7451020    }
    7461021
    7471022    updateLayout();
    7481023}
     1024
     1025/*!
     1026  Emit legendDataChanged() for all plot item
     1027
     1028  \sa QwtPlotItem::legendData(), legendDataChanged()
     1029 */
     1030void QwtPlot::updateLegend()
     1031{
     1032    const QwtPlotItemList& itmList = itemList();
     1033    for ( QwtPlotItemIterator it = itmList.begin();
     1034        it != itmList.end(); ++it )
     1035    {
     1036        updateLegend( *it );
     1037    }
     1038}
     1039
     1040/*!
     1041  Emit legendDataChanged() for a plot item
     1042
     1043  \param plotItem Plot item
     1044  \sa QwtPlotItem::legendData(), legendDataChanged()
     1045 */
     1046void QwtPlot::updateLegend( const QwtPlotItem *plotItem )
     1047{
     1048    if ( plotItem == NULL )
     1049        return;
     1050
     1051    QList<QwtLegendData> legendData;
     1052
     1053    if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) )
     1054        legendData = plotItem->legendData();
     1055
     1056    const QVariant itemInfo = itemToInfo( const_cast< QwtPlotItem *>( plotItem) );
     1057    Q_EMIT legendDataChanged( itemInfo, legendData );
     1058}
     1059
     1060/*!
     1061  \brief Update all plot items interested in legend attributes
     1062
     1063  Call QwtPlotItem::updateLegend(), when the QwtPlotItem::LegendInterest
     1064  flag is set.
     1065
     1066  \param itemInfo Info about the plot item
     1067  \param legendData Entries to be displayed for the plot item ( usually 1 )
     1068
     1069  \sa QwtPlotItem::LegendInterest,
     1070      QwtPlotLegendItem, QwtPlotItem::updateLegend()
     1071 */
     1072void QwtPlot::updateLegendItems( const QVariant &itemInfo,
     1073    const QList<QwtLegendData> &legendData )
     1074{
     1075    QwtPlotItem *plotItem = infoToItem( itemInfo );
     1076    if ( plotItem )
     1077    {
     1078        const QwtPlotItemList& itmList = itemList();
     1079        for ( QwtPlotItemIterator it = itmList.begin();
     1080            it != itmList.end(); ++it )
     1081        {
     1082            QwtPlotItem *item = *it;
     1083            if ( item->testItemInterest( QwtPlotItem::LegendInterest ) )
     1084                item->updateLegend( plotItem, legendData );
     1085        }
     1086    }
     1087}
     1088
     1089/*!
     1090  \brief Attach/Detach a plot item
     1091
     1092  \param plotItem Plot item
     1093  \param on When true attach the item, otherwise detach it
     1094 */
     1095void QwtPlot::attachItem( QwtPlotItem *plotItem, bool on )
     1096{
     1097    if ( plotItem->testItemInterest( QwtPlotItem::LegendInterest ) )
     1098    {
     1099        // plotItem is some sort of legend
     1100
     1101        const QwtPlotItemList& itmList = itemList();
     1102        for ( QwtPlotItemIterator it = itmList.begin();
     1103            it != itmList.end(); ++it )
     1104        {
     1105            QwtPlotItem *item = *it;
     1106
     1107            QList<QwtLegendData> legendData;
     1108            if ( on && item->testItemAttribute( QwtPlotItem::Legend ) )
     1109            {
     1110                legendData = item->legendData();
     1111                plotItem->updateLegend( item, legendData );
     1112            }
     1113        }
     1114    }
     1115
     1116    if ( on )
     1117        insertItem( plotItem );
     1118    else
     1119        removeItem( plotItem );
     1120
     1121    Q_EMIT itemAttached( plotItem, on );
     1122
     1123    if ( plotItem->testItemAttribute( QwtPlotItem::Legend ) )
     1124    {
     1125        // the item wants to be represented on the legend
     1126
     1127        if ( on )
     1128        {
     1129            updateLegend( plotItem );
     1130        }
     1131        else
     1132        {
     1133            const QVariant itemInfo = itemToInfo( plotItem );
     1134            Q_EMIT legendDataChanged( itemInfo, QList<QwtLegendData>() );
     1135        }
     1136    }
     1137
     1138    autoRefresh();
     1139}
     1140
     1141/*!
     1142  \brief Build an information, that can be used to identify
     1143         a plot item on the legend.
     1144
     1145  The default implementation simply wraps the plot item
     1146  into a QVariant object. When overloading itemToInfo()
     1147  usually infoToItem() needs to reimplemeted too.
     1148
     1149\code
     1150    QVariant itemInfo;
     1151    qVariantSetValue( itemInfo, plotItem );
     1152\endcode
     1153
     1154  \param plotItem Plot item
     1155  \return Plot item embedded in a QVariant
     1156  \sa infoToItem()
     1157 */
     1158QVariant QwtPlot::itemToInfo( QwtPlotItem *plotItem ) const
     1159{
     1160    QVariant itemInfo;
     1161    qVariantSetValue( itemInfo, plotItem );
     1162
     1163    return itemInfo;
     1164}
     1165
     1166/*!
     1167  \brief Identify the plot item according to an item info object,
     1168         that has bee generated from itemToInfo().
     1169
     1170  The default implementation simply tries to unwrap a QwtPlotItem
     1171  pointer:
     1172
     1173\code
     1174    if ( itemInfo.canConvert<QwtPlotItem *>() )
     1175        return qvariant_cast<QwtPlotItem *>( itemInfo );
     1176\endcode
     1177  \param itemInfo Plot item
     1178  \return A plot item, when successful, otherwise a NULL pointer.
     1179  \sa itemToInfo()
     1180*/
     1181QwtPlotItem *QwtPlot::infoToItem( const QVariant &itemInfo ) const
     1182{
     1183    if ( itemInfo.canConvert<QwtPlotItem *>() )
     1184        return qvariant_cast<QwtPlotItem *>( itemInfo );
     1185
     1186    return NULL;
     1187}
     1188
     1189
Note: See TracChangeset for help on using the changeset viewer.