Skip to content
qwt_legend.cpp 20.5 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
pixhawk's avatar
pixhawk committed
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
#include "qwt_legend.h"
#include "qwt_legend_label.h"
#include "qwt_dyngrid_layout.h"
#include "qwt_math.h"
#include "qwt_plot_item.h"
#include "qwt_painter.h"
#include <qapplication.h>
#include <qscrollbar.h>
Bryant's avatar
Bryant committed
#include <qscrollarea.h>
#include <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
class QwtLegendMap
pixhawk's avatar
pixhawk committed
{
public:
Bryant's avatar
Bryant committed
    inline bool isEmpty() const { return d_entries.isEmpty(); }

    void insert( const QVariant &, const QList<QWidget *> & );
    void remove( const QVariant & );

    void removeWidget( const QWidget * );

    QList<QWidget *> legendWidgets( const QVariant & ) const;
    QVariant itemInfo( const QWidget * ) const;

private:
    // we don't know anything about itemInfo and therefore don't have
    // any key that can be used for a map or hashtab.
    // But a simple linear list is o.k. here, as we will never have
    // more than a few entries.

    class Entry
pixhawk's avatar
pixhawk committed
    {
    public:
Bryant's avatar
Bryant committed
        QVariant itemInfo;
        QList<QWidget *> widgets;
    };
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QList< Entry > d_entries;
};
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
void QwtLegendMap::insert( const QVariant &itemInfo, 
    const QList<QWidget *> &widgets )
{
    for ( int i = 0; i < d_entries.size(); i++ )
    {
        Entry &entry = d_entries[i];
        if ( entry.itemInfo == itemInfo )
        {
            entry.widgets = widgets;
            return;
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    Entry newEntry;
    newEntry.itemInfo = itemInfo;
    newEntry.widgets = widgets;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    d_entries += newEntry;
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
void QwtLegendMap::remove( const QVariant &itemInfo )
{
    for ( int i = 0; i < d_entries.size(); i++ )
    {
        Entry &entry = d_entries[i];
        if ( entry.itemInfo == itemInfo )
        {
            d_entries.removeAt( i );
            return;
        }
    }
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
void QwtLegendMap::removeWidget( const QWidget *widget )
{
    QWidget *w = const_cast<QWidget *>( widget );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    for ( int i = 0; i < d_entries.size(); i++ )
        d_entries[ i ].widgets.removeAll( w );
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const
{
    if ( widget != NULL )
    {
        QWidget *w = const_cast<QWidget *>( widget );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        for ( int i = 0; i < d_entries.size(); i++ )
        {
            const Entry &entry = d_entries[i];
            if ( entry.widgets.indexOf( w ) >= 0 )
                return entry.itemInfo;
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return QVariant();
}

QList<QWidget *> QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const
{
    if ( itemInfo.isValid() )
    {
        for ( int i = 0; i < d_entries.size(); i++ )
        {
            const Entry &entry = d_entries[i];
            if ( entry.itemInfo == itemInfo )
                return entry.widgets;
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return QList<QWidget *>();
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
class QwtLegend::PrivateData
pixhawk's avatar
pixhawk committed
{
public:
Bryant's avatar
Bryant committed
    PrivateData():
        itemMode( QwtLegendData::ReadOnly ),
        view( NULL )
    {
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QwtLegendData::Mode itemMode;
    QwtLegendMap itemMap;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    class LegendView;
    LegendView *view;
};
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
class QwtLegend::PrivateData::LegendView: public QScrollArea
{
public:
    LegendView( QWidget *parent ):
        QScrollArea( parent )
    {
        contentsWidget = new QWidget( this );
        contentsWidget->setObjectName( "QwtLegendViewContents" );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        setWidget( contentsWidget );
        setWidgetResizable( false );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        viewport()->setObjectName( "QwtLegendViewport" );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        // QScrollArea::setWidget internally sets autoFillBackground to true
        // But we don't want a background.
        contentsWidget->setAutoFillBackground( false );
        viewport()->setAutoFillBackground( false );
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    virtual bool event( QEvent *event )
    {
        if ( event->type() == QEvent::PolishRequest )
        {
            setFocusPolicy( Qt::NoFocus );
        }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        if ( event->type() == QEvent::Resize )
        {
            // adjust the size to en/disable the scrollbars
            // before QScrollArea adjusts the viewport size
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            const QRect cr = contentsRect();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            int w = cr.width();
            int h = contentsWidget->heightForWidth( cr.width() );
            if ( h > w )
            {
                w -= verticalScrollBar()->sizeHint().width();
                h = contentsWidget->heightForWidth( w );
            }

            contentsWidget->resize( w, h );
        }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        return QScrollArea::event( event );
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    virtual bool viewportEvent( QEvent *event )
    {
        bool ok = QScrollArea::viewportEvent( event );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        if ( event->type() == QEvent::Resize )
        {
            layoutContents();
pixhawk's avatar
pixhawk committed
        }
        return ok;
    }

Bryant's avatar
Bryant committed
    QSize viewportSize( int w, int h ) const
    {
pixhawk's avatar
pixhawk committed
        const int sbHeight = horizontalScrollBar()->sizeHint().height();
        const int sbWidth = verticalScrollBar()->sizeHint().width();
pixhawk's avatar
pixhawk committed
        const int cw = contentsRect().width();
        const int ch = contentsRect().height();

        int vw = cw;
        int vh = ch;

        if ( w > vw )
            vh -= sbHeight;

Bryant's avatar
Bryant committed
        if ( h > vh )
        {
pixhawk's avatar
pixhawk committed
            vw -= sbWidth;
            if ( w > vw && vh == ch )
                vh -= sbHeight;
        }
Bryant's avatar
Bryant committed
        return QSize( vw, vh );
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    void layoutContents()
    {
        const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
            contentsWidget->layout() );
        if ( tl == NULL )
            return;
Bryant's avatar
Bryant committed
        const QSize visibleSize = viewport()->contentsRect().size();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        int w = qMax( visibleSize.width(), minW );
        int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        const int vpWidth = viewportSize( w, h ).width();
        if ( w > vpWidth )
        {
            w = qMax( vpWidth, minW );
            h = qMax( tl->heightForWidth( w ), visibleSize.height() );
        }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        contentsWidget->resize( w, h );
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QWidget *contentsWidget;
};
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Constructor
  \param parent Parent widget
*/
QwtLegend::QwtLegend( QWidget *parent ):
    QwtAbstractLegend( parent )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    setFrameStyle( NoFrame );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    d_data = new QwtLegend::PrivateData;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    d_data->view = new QwtLegend::PrivateData::LegendView( this );
    d_data->view->setObjectName( "QwtLegendView" );
    d_data->view->setFrameStyle( NoFrame );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
        d_data->view->contentsWidget );
    gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );

    d_data->view->contentsWidget->installEventFilter( this );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QVBoxLayout *layout = new QVBoxLayout( this );
    layout->setContentsMargins( 0, 0, 0, 0 );
    layout->addWidget( d_data->view );
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! Destructor
QwtLegend::~QwtLegend()
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    delete d_data;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  \brief Set the maximum number of entries in a row
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  F.e when the maximum is set to 1 all items are aligned
  vertically. 0 means unlimited
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param numColums Maximum number of entries in a row
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \sa maxColumns(), QwtDynGridLayout::setMaxColumns()
 */
void QwtLegend::setMaxColumns( uint numColums )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
        d_data->view->contentsWidget->layout() );
    if ( tl )
        tl->setMaxColumns( numColums );
pixhawk's avatar
pixhawk committed

/*!
Bryant's avatar
Bryant committed
  \return Maximum number of entries in a row
  \sa setMaxColumns(), QwtDynGridLayout::maxColumns()
 */
uint QwtLegend::maxColumns() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    uint maxCols = 0;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    const QwtDynGridLayout *tl = qobject_cast<const QwtDynGridLayout *>(
        d_data->view->contentsWidget->layout() );
    if ( tl )
        maxCols = tl->maxColumns();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return maxCols;
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
  \brief Set the default mode for legend labels
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  Legend labels will be constructed according to the
  attributes in a QwtLegendData object. When it doesn't
  contain a value for the QwtLegendData::ModeRole the
  label will be initialized with the default mode of the legend.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param mode Default item mode
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData()
  \note Changing the mode doesn't have any effect on existing labels.
 */
void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode )
pixhawk's avatar
pixhawk committed
{
    d_data->itemMode = mode;
}

/*!
Bryant's avatar
Bryant committed
  \return Default item mode
  \sa setDefaultItemMode()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QwtLegendData::Mode QwtLegend::defaultItemMode() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->itemMode;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
  The contents widget is the only child of the viewport of 
  the internal QScrollArea and the parent widget of all legend items.

  \return Container widget of the legend items
pixhawk's avatar
pixhawk committed
*/
QWidget *QwtLegend::contentsWidget()
{
    return d_data->view->contentsWidget;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  \return Horizontal scrollbar
  \sa verticalScrollBar()
*/
pixhawk's avatar
pixhawk committed
QScrollBar *QwtLegend::horizontalScrollBar() const
{
    return d_data->view->horizontalScrollBar();
}

Bryant's avatar
Bryant committed
/*!
  \return Vertical scrollbar
  \sa horizontalScrollBar()
*/
pixhawk's avatar
pixhawk committed
QScrollBar *QwtLegend::verticalScrollBar() const
{
    return d_data->view->verticalScrollBar();
}

Bryant's avatar
Bryant committed
  The contents widget is the only child of the viewport of 
  the internal QScrollArea and the parent widget of all legend items.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \return Container widget of the legend items

*/
const QWidget *QwtLegend::contentsWidget() const
{
    return d_data->view->contentsWidget;
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
  \brief Update the entries for an item

  \param itemInfo Info for an item
  \param data List of legend entry attributes for the item
 */
void QwtLegend::updateLegend( const QVariant &itemInfo, 
    const QList<QwtLegendData> &data )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    QList<QWidget *> widgetList = legendWidgets( itemInfo );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( widgetList.size() != data.size() )
    {
        QLayout *contentsLayout = d_data->view->contentsWidget->layout();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        while ( widgetList.size() > data.size() )
        {
            QWidget *w = widgetList.takeLast();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            contentsLayout->removeWidget( w );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            // updates might be triggered by signals from the legend widget
            // itself. So we better don't delete it here.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            w->hide();
            w->deleteLater();
        }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        for ( int i = widgetList.size(); i < data.size(); i++ )
        {
            QWidget *widget = createWidget( data[i] );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            if ( contentsLayout )
                contentsLayout->addWidget( widget );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            widgetList += widget;
        }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        if ( widgetList.isEmpty() )
        {
            d_data->itemMap.remove( itemInfo );
pixhawk's avatar
pixhawk committed
        }
Bryant's avatar
Bryant committed
        else
        {
            d_data->itemMap.insert( itemInfo, widgetList );
        }

        updateTabOrder();
pixhawk's avatar
pixhawk committed
    }
Bryant's avatar
Bryant committed
    
    for ( int i = 0; i < data.size(); i++ )
        updateWidget( widgetList[i], data[i] );
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
  \brief Create a widget to be inserted into the legend
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  The default implementation returns a QwtLegendLabel.

  \param data Attributes of the legend entry
  \return Widget representing data on the legend
  
  \note updateWidget() will called soon after createWidget()
        with the same attributes.
 */
QWidget *QwtLegend::createWidget( const QwtLegendData &data ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    Q_UNUSED( data );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QwtLegendLabel *label = new QwtLegendLabel();
    label->setItemMode( defaultItemMode() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) );
    connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) );

    return label;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
  \brief Update the widget 
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param widget Usually a QwtLegendLabel
  \param data Attributes to be displayed

  \sa createWidget()
  \note When widget is no QwtLegendLabel updateWidget() does nothing.
 */
void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &data )
Bryant's avatar
Bryant committed
    QwtLegendLabel *label = qobject_cast<QwtLegendLabel *>( widget );
    if ( label )
    {
        label->setData( data );
        if ( !data.value( QwtLegendData::ModeRole ).isValid() )
        {
            // use the default mode, when there is no specific
            // hint from the legend data

            label->setItemMode( defaultItemMode() );
        }
    }
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
void QwtLegend::updateTabOrder()
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    QLayout *contentsLayout = d_data->view->contentsWidget->layout();
    if ( contentsLayout )
    {
        // set tab focus chain
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        QWidget *w = NULL;

        for ( int i = 0; i < contentsLayout->count(); i++ )
        {
            QLayoutItem *item = contentsLayout->itemAt( i );
            if ( w && item->widget() )
                QWidget::setTabOrder( w, item->widget() );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            w = item->widget();
        }
    }
pixhawk's avatar
pixhawk committed
}

//! Return a size hint.
QSize QwtLegend::sizeHint() const
{
    QSize hint = d_data->view->contentsWidget->sizeHint();
Bryant's avatar
Bryant committed
    hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
pixhawk's avatar
pixhawk committed

    return hint;
}

/*!
Bryant's avatar
Bryant committed
  \return The preferred height, for a width.
pixhawk's avatar
pixhawk committed
  \param width Width
*/
Bryant's avatar
Bryant committed
int QwtLegend::heightForWidth( int width ) const
pixhawk's avatar
pixhawk committed
{
    width -= 2 * frameWidth();

Bryant's avatar
Bryant committed
    int h = d_data->view->contentsWidget->heightForWidth( width );
pixhawk's avatar
pixhawk committed
    if ( h >= 0 )
        h += 2 * frameWidth();

    return h;
}

Bryant's avatar
Bryant committed

pixhawk's avatar
pixhawk committed
/*!
Bryant's avatar
Bryant committed
  Handle QEvent::ChildRemoved andQEvent::LayoutRequest events 
  for the contentsWidget().
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param object Object to be filtered
  \param event Event
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \return Forwarded to QwtAbstractLegend::eventFilter()
*/
bool QwtLegend::eventFilter( QObject *object, QEvent *event )
{
    if ( object == d_data->view->contentsWidget )
    {
        switch ( event->type() )
        {
            case QEvent::ChildRemoved:
            {
                const QChildEvent *ce = 
                    static_cast<const QChildEvent *>(event);
                if ( ce->child()->isWidgetType() )
                {
                    QWidget *w = static_cast< QWidget * >( ce->child() );
                    d_data->itemMap.removeWidget( w );
                }
                break;
            }
            case QEvent::LayoutRequest:
            {
                d_data->view->layoutContents();

                if ( parentWidget() && parentWidget()->layout() == NULL )
                {
                    /*
                       We want the parent widget ( usually QwtPlot ) to recalculate
                       its layout, when the contentsWidget has changed. But
                       because of the scroll view we have to forward the LayoutRequest
                       event manually.

                       We don't use updateGeometry() because it doesn't post LayoutRequest
                       events when the legend is hidden. But we want the
                       parent widget notified, so it can show/hide the legend
                       depending on its items.
                     */
                    QApplication::postEvent( parentWidget(),
                        new QEvent( QEvent::LayoutRequest ) );
                }                
                break;
            }
            default:
                break;
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return QwtAbstractLegend::eventFilter( object, event );
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Called internally when the legend has been clicked on.
  Emits a clicked() signal.
*/
void QwtLegend::itemClicked()
{
    QWidget *w = qobject_cast<QWidget *>( sender() );
    if ( w )
    {
        const QVariant itemInfo = d_data->itemMap.itemInfo( w );
        if ( itemInfo.isValid() )
        {
            const QList<QWidget *> widgetList =
                d_data->itemMap.legendWidgets( itemInfo );

            const int index = widgetList.indexOf( w );
            if ( index >= 0 )
                Q_EMIT clicked( itemInfo, index );
pixhawk's avatar
pixhawk committed
        }
Bryant's avatar
Bryant committed
    }
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Called internally when the legend has been checked
  Emits a checked() signal.
*/
void QwtLegend::itemChecked( bool on )
{
    QWidget *w = qobject_cast<QWidget *>( sender() );
    if ( w )
    {
        const QVariant itemInfo = d_data->itemMap.itemInfo( w );
        if ( itemInfo.isValid() )
        {
            const QList<QWidget *> widgetList =
                d_data->itemMap.legendWidgets( itemInfo );

            const int index = widgetList.indexOf( w );
            if ( index >= 0 )
                Q_EMIT checked( itemInfo, on, index );
        }
pixhawk's avatar
pixhawk committed
    }
}

Bryant's avatar
Bryant committed
/*!
  Render the legend into a given rectangle.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param painter Painter
  \param rect Bounding rectangle
  \param fillBackground When true, fill rect with the widget background 
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself
*/
void QwtLegend::renderLegend( QPainter *painter, 
    const QRectF &rect, bool fillBackground ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->itemMap.isEmpty() )
        return;

    if ( fillBackground )
    {
        if ( autoFillBackground() ||
            testAttribute( Qt::WA_StyledBackground ) )
        {
            QwtPainter::drawBackgound( painter, rect, this );
pixhawk's avatar
pixhawk committed
        }
    }
Bryant's avatar
Bryant committed
    const QwtDynGridLayout *legendLayout = 
        qobject_cast<QwtDynGridLayout *>( contentsWidget()->layout() );
    if ( legendLayout == NULL )
        return;

    int left, right, top, bottom;
    getContentsMargins( &left, &top, &right, &bottom );

    QRect layoutRect; 
    layoutRect.setLeft( qCeil( rect.left() ) + left );
    layoutRect.setTop( qCeil( rect.top() ) + top );
    layoutRect.setRight( qFloor( rect.right() ) - right );
    layoutRect.setBottom( qFloor( rect.bottom() ) - bottom );

    uint numCols = legendLayout->columnsForWidth( layoutRect.width() );
    QList<QRect> itemRects =
        legendLayout->layoutItems( layoutRect, numCols );

    int index = 0;

    for ( int i = 0; i < legendLayout->count(); i++ )
    {
        QLayoutItem *item = legendLayout->itemAt( i );
        QWidget *w = item->widget();
        if ( w )
        {
            painter->save();

            painter->setClipRect( itemRects[index], Qt::IntersectClip );
            renderItem( painter, w, itemRects[index], fillBackground );

            index++;
            painter->restore();
        }
    }
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  Render a legend entry into a given rectangle.
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param painter Painter
  \param widget Widget representing a legend entry
  \param rect Bounding rectangle
  \param fillBackground When true, fill rect with the widget background 

  \note When widget is not derived from QwtLegendLabel renderItem
        does nothing beside the background
*/
void QwtLegend::renderItem( QPainter *painter, 
    const QWidget *widget, const QRectF &rect, bool fillBackground ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( fillBackground )
    {
        if ( widget->autoFillBackground() ||
            widget->testAttribute( Qt::WA_StyledBackground ) )
        {
            QwtPainter::drawBackgound( painter, rect, widget );
        }
    }

    const QwtLegendLabel *label = qobject_cast<const QwtLegendLabel *>( widget );
    if ( label )
    {
        // icon

        const QwtGraphic &icon = label->data().icon();
        const QSizeF sz = icon.defaultSize();

        const QRectF iconRect( rect.x() + label->margin(),
            rect.center().y() - 0.5 * sz.height(), 
            sz.width(), sz.height() );

        icon.render( painter, iconRect, Qt::KeepAspectRatio );

        // title

        QRectF titleRect = rect;
        titleRect.setX( iconRect.right() + 2 * label->spacing() );

        painter->setFont( label->font() );
        painter->setPen( label->palette().color( QPalette::Text ) );
        const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect );
    }
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  \return List of widgets associated to a item
  \param itemInfo Info about an item
  \sa legendWidget(), itemInfo(), QwtPlot::itemToInfo()
 */
QList<QWidget *> QwtLegend::legendWidgets( const QVariant &itemInfo ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->itemMap.legendWidgets( itemInfo );
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  \return First widget in the list of widgets associated to an item
  \param itemInfo Info about an item
  \sa itemInfo(), QwtPlot::itemToInfo()
  \note Almost all types of items have only one widget
*/
QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    const QList<QWidget *> list = d_data->itemMap.legendWidgets( itemInfo );
    if ( list.isEmpty() )
        return NULL;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return list[0];
}

/*!
  Find the item that is associated to a widget
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param widget Widget on the legend
  \return Associated item info
  \sa legendWidget()
 */
QVariant QwtLegend::itemInfo( const QWidget *widget ) const
{
    return d_data->itemMap.itemInfo( widget );
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
//! \return True, when no item is inserted
bool QwtLegend::isEmpty() const
{
    return d_data->itemMap.isEmpty();
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
    Return the extent, that is needed for the scrollbars

    \param orientation Orientation ( 
    \return The width of the vertical scrollbar for Qt::Horizontal and v.v.
 */
int QwtLegend::scrollExtent( Qt::Orientation orientation ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    int extent = 0;

    if ( orientation == Qt::Horizontal )
        extent = verticalScrollBar()->sizeHint().width();
    else
        extent = horizontalScrollBar()->sizeHint().height();

    return extent;
pixhawk's avatar
pixhawk committed
}
Bryant's avatar
Bryant committed