彻底改版2.0
This commit is contained in:
827
third/3rd_qwt/qwt_legend.cpp
Normal file
827
third/3rd_qwt/qwt_legend.cpp
Normal file
@@ -0,0 +1,827 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#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>
|
||||
#include <qscrollarea.h>
|
||||
#include <qpainter.h>
|
||||
#include <qstyle.h>
|
||||
#include <qstyleoption.h>
|
||||
|
||||
class QwtLegendMap
|
||||
{
|
||||
public:
|
||||
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
|
||||
{
|
||||
public:
|
||||
QVariant itemInfo;
|
||||
QList<QWidget *> widgets;
|
||||
};
|
||||
|
||||
QList< Entry > d_entries;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Entry newEntry;
|
||||
newEntry.itemInfo = itemInfo;
|
||||
newEntry.widgets = widgets;
|
||||
|
||||
d_entries += newEntry;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QwtLegendMap::removeWidget( const QWidget *widget )
|
||||
{
|
||||
QWidget *w = const_cast<QWidget *>( widget );
|
||||
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
d_entries[ i ].widgets.removeAll( w );
|
||||
}
|
||||
|
||||
QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const
|
||||
{
|
||||
if ( widget != NULL )
|
||||
{
|
||||
QWidget *w = const_cast<QWidget *>( widget );
|
||||
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
{
|
||||
const Entry &entry = d_entries[i];
|
||||
if ( entry.widgets.indexOf( w ) >= 0 )
|
||||
return entry.itemInfo;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return QList<QWidget *>();
|
||||
}
|
||||
|
||||
class QwtLegend::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
itemMode( QwtLegendData::ReadOnly ),
|
||||
view( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
QwtLegendData::Mode itemMode;
|
||||
QwtLegendMap itemMap;
|
||||
|
||||
class LegendView;
|
||||
LegendView *view;
|
||||
};
|
||||
|
||||
class QwtLegend::PrivateData::LegendView: public QScrollArea
|
||||
{
|
||||
public:
|
||||
explicit LegendView( QWidget *parent ):
|
||||
QScrollArea( parent )
|
||||
{
|
||||
contentsWidget = new QWidget( this );
|
||||
contentsWidget->setObjectName( "QwtLegendViewContents" );
|
||||
|
||||
setWidget( contentsWidget );
|
||||
setWidgetResizable( false );
|
||||
|
||||
viewport()->setObjectName( "QwtLegendViewport" );
|
||||
|
||||
// QScrollArea::setWidget internally sets autoFillBackground to true
|
||||
// But we don't want a background.
|
||||
contentsWidget->setAutoFillBackground( false );
|
||||
viewport()->setAutoFillBackground( false );
|
||||
}
|
||||
|
||||
virtual bool event( QEvent *event )
|
||||
{
|
||||
if ( event->type() == QEvent::PolishRequest )
|
||||
{
|
||||
setFocusPolicy( Qt::NoFocus );
|
||||
}
|
||||
|
||||
if ( event->type() == QEvent::Resize )
|
||||
{
|
||||
// adjust the size to en/disable the scrollbars
|
||||
// before QScrollArea adjusts the viewport size
|
||||
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
return QScrollArea::event( event );
|
||||
}
|
||||
|
||||
virtual bool viewportEvent( QEvent *event )
|
||||
{
|
||||
bool ok = QScrollArea::viewportEvent( event );
|
||||
|
||||
if ( event->type() == QEvent::Resize )
|
||||
{
|
||||
layoutContents();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
QSize viewportSize( int w, int h ) const
|
||||
{
|
||||
const int sbHeight = horizontalScrollBar()->sizeHint().height();
|
||||
const int sbWidth = verticalScrollBar()->sizeHint().width();
|
||||
|
||||
const int cw = contentsRect().width();
|
||||
const int ch = contentsRect().height();
|
||||
|
||||
int vw = cw;
|
||||
int vh = ch;
|
||||
|
||||
if ( w > vw )
|
||||
vh -= sbHeight;
|
||||
|
||||
if ( h > vh )
|
||||
{
|
||||
vw -= sbWidth;
|
||||
if ( w > vw && vh == ch )
|
||||
vh -= sbHeight;
|
||||
}
|
||||
return QSize( vw, vh );
|
||||
}
|
||||
|
||||
void layoutContents()
|
||||
{
|
||||
const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||
contentsWidget->layout() );
|
||||
if ( tl == NULL )
|
||||
return;
|
||||
|
||||
const QSize visibleSize = viewport()->contentsRect().size();
|
||||
|
||||
const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
|
||||
|
||||
int w = qMax( visibleSize.width(), minW );
|
||||
int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||
|
||||
const int vpWidth = viewportSize( w, h ).width();
|
||||
if ( w > vpWidth )
|
||||
{
|
||||
w = qMax( vpWidth, minW );
|
||||
h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||
}
|
||||
|
||||
contentsWidget->resize( w, h );
|
||||
}
|
||||
|
||||
QWidget *contentsWidget;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param parent Parent widget
|
||||
*/
|
||||
QwtLegend::QwtLegend( QWidget *parent ):
|
||||
QwtAbstractLegend( parent )
|
||||
{
|
||||
setFrameStyle( NoFrame );
|
||||
|
||||
d_data = new QwtLegend::PrivateData;
|
||||
|
||||
d_data->view = new QwtLegend::PrivateData::LegendView( this );
|
||||
d_data->view->setObjectName( "QwtLegendView" );
|
||||
d_data->view->setFrameStyle( NoFrame );
|
||||
|
||||
QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
|
||||
d_data->view->contentsWidget );
|
||||
gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
|
||||
|
||||
d_data->view->contentsWidget->installEventFilter( this );
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout( this );
|
||||
layout->setContentsMargins( 0, 0, 0, 0 );
|
||||
layout->addWidget( d_data->view );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtLegend::~QwtLegend()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the maximum number of entries in a row
|
||||
|
||||
F.e when the maximum is set to 1 all items are aligned
|
||||
vertically. 0 means unlimited
|
||||
|
||||
\param numColums Maximum number of entries in a row
|
||||
|
||||
\sa maxColumns(), QwtDynGridLayout::setMaxColumns()
|
||||
*/
|
||||
void QwtLegend::setMaxColumns( uint numColums )
|
||||
{
|
||||
QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||
d_data->view->contentsWidget->layout() );
|
||||
if ( tl )
|
||||
tl->setMaxColumns( numColums );
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Maximum number of entries in a row
|
||||
\sa setMaxColumns(), QwtDynGridLayout::maxColumns()
|
||||
*/
|
||||
uint QwtLegend::maxColumns() const
|
||||
{
|
||||
uint maxCols = 0;
|
||||
|
||||
const QwtDynGridLayout *tl = qobject_cast<const QwtDynGridLayout *>(
|
||||
d_data->view->contentsWidget->layout() );
|
||||
if ( tl )
|
||||
maxCols = tl->maxColumns();
|
||||
|
||||
return maxCols;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the default mode for legend labels
|
||||
|
||||
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.
|
||||
|
||||
\param mode Default item mode
|
||||
|
||||
\sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData()
|
||||
\note Changing the mode doesn't have any effect on existing labels.
|
||||
*/
|
||||
void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode )
|
||||
{
|
||||
d_data->itemMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Default item mode
|
||||
\sa setDefaultItemMode()
|
||||
*/
|
||||
QwtLegendData::Mode QwtLegend::defaultItemMode() const
|
||||
{
|
||||
return d_data->itemMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
*/
|
||||
QWidget *QwtLegend::contentsWidget()
|
||||
{
|
||||
return d_data->view->contentsWidget;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Horizontal scrollbar
|
||||
\sa verticalScrollBar()
|
||||
*/
|
||||
QScrollBar *QwtLegend::horizontalScrollBar() const
|
||||
{
|
||||
return d_data->view->horizontalScrollBar();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Vertical scrollbar
|
||||
\sa horizontalScrollBar()
|
||||
*/
|
||||
QScrollBar *QwtLegend::verticalScrollBar() const
|
||||
{
|
||||
return d_data->view->verticalScrollBar();
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
|
||||
*/
|
||||
const QWidget *QwtLegend::contentsWidget() const
|
||||
{
|
||||
return d_data->view->contentsWidget;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Update the entries for an item
|
||||
|
||||
\param itemInfo Info for an item
|
||||
\param legendData List of legend entry attributes for the item
|
||||
*/
|
||||
void QwtLegend::updateLegend( const QVariant &itemInfo,
|
||||
const QList<QwtLegendData> &legendData )
|
||||
{
|
||||
QList<QWidget *> widgetList = legendWidgets( itemInfo );
|
||||
|
||||
if ( widgetList.size() != legendData.size() )
|
||||
{
|
||||
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||
|
||||
while ( widgetList.size() > legendData.size() )
|
||||
{
|
||||
QWidget *w = widgetList.takeLast();
|
||||
|
||||
contentsLayout->removeWidget( w );
|
||||
|
||||
// updates might be triggered by signals from the legend widget
|
||||
// itself. So we better don't delete it here.
|
||||
|
||||
w->hide();
|
||||
w->deleteLater();
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
widgetList.reserve( legendData.size() );
|
||||
#endif
|
||||
|
||||
for ( int i = widgetList.size(); i < legendData.size(); i++ )
|
||||
{
|
||||
QWidget *widget = createWidget( legendData[i] );
|
||||
|
||||
if ( contentsLayout )
|
||||
contentsLayout->addWidget( widget );
|
||||
|
||||
if ( isVisible() )
|
||||
{
|
||||
// QLayout does a delayed show, with the effect, that
|
||||
// the size hint will be wrong, when applications
|
||||
// call replot() right after changing the list
|
||||
// of plot items. So we better do the show now.
|
||||
|
||||
widget->setVisible( true );
|
||||
}
|
||||
|
||||
widgetList += widget;
|
||||
}
|
||||
|
||||
if ( widgetList.isEmpty() )
|
||||
{
|
||||
d_data->itemMap.remove( itemInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
d_data->itemMap.insert( itemInfo, widgetList );
|
||||
}
|
||||
|
||||
updateTabOrder();
|
||||
}
|
||||
|
||||
for ( int i = 0; i < legendData.size(); i++ )
|
||||
updateWidget( widgetList[i], legendData[i] );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Create a widget to be inserted into the legend
|
||||
|
||||
The default implementation returns a QwtLegendLabel.
|
||||
|
||||
\param legendData 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 &legendData ) const
|
||||
{
|
||||
Q_UNUSED( legendData );
|
||||
|
||||
QwtLegendLabel *label = new QwtLegendLabel();
|
||||
label->setItemMode( defaultItemMode() );
|
||||
|
||||
connect( label, SIGNAL(clicked()), SLOT(itemClicked()) );
|
||||
connect( label, SIGNAL(checked(bool)), SLOT(itemChecked(bool)) );
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Update the widget
|
||||
|
||||
\param widget Usually a QwtLegendLabel
|
||||
\param legendData Attributes to be displayed
|
||||
|
||||
\sa createWidget()
|
||||
\note When widget is no QwtLegendLabel updateWidget() does nothing.
|
||||
*/
|
||||
void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &legendData )
|
||||
{
|
||||
QwtLegendLabel *label = qobject_cast<QwtLegendLabel *>( widget );
|
||||
if ( label )
|
||||
{
|
||||
label->setData( legendData );
|
||||
if ( !legendData.value( QwtLegendData::ModeRole ).isValid() )
|
||||
{
|
||||
// use the default mode, when there is no specific
|
||||
// hint from the legend data
|
||||
|
||||
label->setItemMode( defaultItemMode() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QwtLegend::updateTabOrder()
|
||||
{
|
||||
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||
if ( contentsLayout )
|
||||
{
|
||||
// set tab focus chain
|
||||
|
||||
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() );
|
||||
|
||||
w = item->widget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Return a size hint.
|
||||
QSize QwtLegend::sizeHint() const
|
||||
{
|
||||
QSize hint = d_data->view->contentsWidget->sizeHint();
|
||||
hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The preferred height, for a width.
|
||||
\param width Width
|
||||
*/
|
||||
int QwtLegend::heightForWidth( int width ) const
|
||||
{
|
||||
width -= 2 * frameWidth();
|
||||
|
||||
int h = d_data->view->contentsWidget->heightForWidth( width );
|
||||
if ( h >= 0 )
|
||||
h += 2 * frameWidth();
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
|
||||
for the contentsWidget().
|
||||
|
||||
\param object Object to be filtered
|
||||
\param event Event
|
||||
|
||||
\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() )
|
||||
{
|
||||
/*
|
||||
We are called from the ~QObject and ce->child() is
|
||||
no widget anymore. But all we need is the address
|
||||
to remove it from the map.
|
||||
*/
|
||||
QWidget *w = reinterpret_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;
|
||||
}
|
||||
}
|
||||
|
||||
return QwtAbstractLegend::eventFilter( object, event );
|
||||
}
|
||||
|
||||
/*!
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Render the legend into a given rectangle.
|
||||
|
||||
\param painter Painter
|
||||
\param rect Bounding rectangle
|
||||
\param fillBackground When true, fill rect with the widget background
|
||||
|
||||
\sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself
|
||||
*/
|
||||
void QwtLegend::renderLegend( QPainter *painter,
|
||||
const QRectF &rect, bool fillBackground ) const
|
||||
{
|
||||
if ( d_data->itemMap.isEmpty() )
|
||||
return;
|
||||
|
||||
if ( fillBackground )
|
||||
{
|
||||
if ( autoFillBackground() ||
|
||||
testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
QwtPainter::drawBackgound( painter, rect, this );
|
||||
}
|
||||
}
|
||||
|
||||
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() );
|
||||
const 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Render a legend entry into a given rectangle.
|
||||
|
||||
\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
|
||||
{
|
||||
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() );
|
||||
|
||||
QFont labelFont = label->font();
|
||||
labelFont.resolve( QFont::AllPropertiesResolved );
|
||||
|
||||
painter->setFont( labelFont );
|
||||
painter->setPen( label->palette().color( QPalette::Text ) );
|
||||
|
||||
const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
{
|
||||
return d_data->itemMap.legendWidgets( itemInfo );
|
||||
}
|
||||
|
||||
/*!
|
||||
\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
|
||||
{
|
||||
const QList<QWidget *> list = d_data->itemMap.legendWidgets( itemInfo );
|
||||
if ( list.isEmpty() )
|
||||
return NULL;
|
||||
|
||||
return list[0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the item that is associated to a widget
|
||||
|
||||
\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 );
|
||||
}
|
||||
|
||||
//! \return True, when no item is inserted
|
||||
bool QwtLegend::isEmpty() const
|
||||
{
|
||||
return d_data->itemMap.isEmpty();
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
{
|
||||
int extent = 0;
|
||||
|
||||
if ( orientation == Qt::Horizontal )
|
||||
extent = verticalScrollBar()->sizeHint().width();
|
||||
else
|
||||
extent = horizontalScrollBar()->sizeHint().height();
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user