Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

# qwt_legend.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <qapplication.h>
    00013 #include <qpainter.h>
    00014 #include <qbitmap.h>
    00015 #include <qstyle.h>
    00016 #include "qwt_text.h"
    00017 #include "qwt_legend.h"
    00018 #include "qwt_painter.h"
    00019 #include "qwt_dyngrid_layout.h"
    00020
    00021 static const int IdentifierWidth = 8;
    00022 static const int Margin = 2;
    00023
    00025 QwtLegendItem::QwtLegendItem():
    00026     d_identifierMode(ShowLine | ShowText),
    00027     d_curvePen(Qt::NoPen)
    00028 {
    00029 }
    00030
    00036 QwtLegendItem::QwtLegendItem(const QwtSymbol &symbol, const QPen &curvePen):
    00037     d_identifierMode(ShowLine | ShowText),
    00038     d_symbol(symbol),
    00039     d_curvePen(curvePen)
    00040 {
    00041 }
    00042
    00044 QwtLegendItem::~QwtLegendItem()
    00045 {
    00046 }
    00047
    00055 void QwtLegendItem::setIdentifierMode(int mode)
    00056 {
    00057     if ( mode != d_identifierMode )
    00058     {
    00059         d_identifierMode = mode;
    00060         updateItem();
    00061     }
    00062 }
    00063
    00068 int QwtLegendItem::identifierMode() const
    00069 {
    00070     return d_identifierMode;
    00071 }
    00072
    00079 void QwtLegendItem::setSymbol(const QwtSymbol &symbol)
    00080 {
    00081     if ( symbol != d_symbol )
    00082     {
    00083         d_symbol = symbol;
    00084         updateItem();
    00085     }
    00086 }
    00087
    00092 const QwtSymbol& QwtLegendItem::symbol() const
    00093 {
    00094     return d_symbol;
    00095 }
    00096
    00097
    00104 void QwtLegendItem::setCurvePen(const QPen &pen)
    00105 {
    00106     if ( pen != d_curvePen )
    00107     {
    00108         d_curvePen = pen;
    00109         updateItem();
    00110     }
    00111 }
    00112
    00117 const QPen& QwtLegendItem::curvePen() const
    00118 {
    00119     return d_curvePen;
    00120 }
    00121
    00123 void QwtLegendItem::updateItem()
    00124 {
    00125 }
    00126
    00132 void QwtLegendItem::drawIdentifier(
    00133     QPainter *painter, const QRect &rect) const
    00134 {
    00135     if ( rect.isEmpty() )
    00136         return;
    00137
    00138     if ( (d_identifierMode & ShowLine ) && (d_curvePen.style() != Qt::NoPen) )
    00139     {
    00140         painter->save();
    00141         painter->setPen(d_curvePen);
    00142         QwtPainter::drawLine(painter, rect.left(), rect.center().y(),
    00143             rect.right(), rect.center().y());
    00144         painter->restore();
    00145     }
    00146
    00147     if ( (d_identifierMode & ShowSymbol)
    00148         && (d_symbol.style() != QwtSymbol::None) )
    00149     {
    00150         QSize symbolSize =
    00151             QwtPainter::metricsMap().screenToLayout(d_symbol.size());
    00152
    00153         // scale the symbol size down if it doesn't fit into rect.
    00154
    00155         if ( rect.width() < symbolSize.width() )
    00156         {
    00157             const double ratio =
    00158                 double(symbolSize.width()) / double(rect.width());
    00159             symbolSize.setWidth(rect.width());
    00160             symbolSize.setHeight(qRound(symbolSize.height() / ratio));
    00161         }
    00162         if ( rect.height() < symbolSize.height() )
    00163         {
    00164             const double ratio =
    00165                 double(symbolSize.width()) / double(rect.width());
    00166             symbolSize.setHeight(rect.height());
    00167             symbolSize.setWidth(qRound(symbolSize.width() / ratio));
    00168         }
    00169
    00170         QRect symbolRect;
    00171         symbolRect.setSize(symbolSize);
    00172         symbolRect.moveCenter(rect.center());
    00173
    00174         painter->save();
    00175         painter->setBrush(d_symbol.brush());
    00176         painter->setPen(d_symbol.pen());
    00177         d_symbol.draw(painter, symbolRect);
    00178         painter->restore();
    00179     }
    00180 }
    00181
    00188 void QwtLegendItem::drawItem(QPainter *painter, const QRect &rect) const
    00189 {
    00190     const QwtMetricsMap &map = QwtPainter::metricsMap();
    00191
    00192     const int margin = map.screenToLayoutX(Margin);
    00193
    00194     const QRect identifierRect(rect.x() + margin, rect.y(),
    00195         map.screenToLayoutX(IdentifierWidth), rect.height());
    00196     drawIdentifier(painter, identifierRect);
    00197
    00198     // Label
    00199
    00200     QwtText *txt = titleText();
    00201     if ( txt )
    00202     {
    00203         QRect titleRect = rect;
    00204         titleRect.setX(identifierRect.right() + 2 * margin);
    00205
    00206         txt->draw(painter, titleRect);
    00207         delete txt;
    00208     }
    00209 }
    00210
    00211
    00216 QwtLegendButton::QwtLegendButton(QWidget *parent, const char *name):
    00217     QwtPushButton(parent, name)
    00218 {
    00219     init();
    00220 }
    00221
    00229 QwtLegendButton::QwtLegendButton(
    00230         const QwtSymbol &symbol, const QPen &curvePen, const QString &text,
    00231         QWidget *parent, const char *name):
    00232     QwtPushButton(text, parent, name),
    00233     QwtLegendItem(symbol, curvePen)
    00234 {
    00235     init();
    00236 }
    00237
    00238 void QwtLegendButton::init()
    00239 {
    00240     setFlat(TRUE);
    00241     setAlignment(Qt::AlignLeft | Qt::AlignVCenter |
    00242         Qt::ExpandTabs | Qt::WordBreak);
    00243     setIndent(2 * Margin);
    00244     updateIconset();
    00245 }
    00246
    00247 void QwtLegendButton::updateItem()
    00248 {
    00249     updateIconset();
    00250 }
    00251
    00255 void QwtLegendButton::updateIconset()
    00256 {
    00257     const QFontMetrics fm(font());
    00258
    00259     QPixmap pm(IdentifierWidth, fm.height());
    00260     pm.fill(this, 0, 0);
    00261
    00262     QPainter p(&pm);
    00263     drawIdentifier(&p, QRect(0, 0, pm.width(), pm.height()) );
    00264     p.end();
    00265
    00266     pm.setMask(pm.createHeuristicMask());
    00267
    00268     setIconSet(QIconSet(pm));
    00269 }
    00270
    00277 void QwtLegendButton::setTitle(const QString &title)
    00278 {
    00279     setText(title);
    00280 }
    00281
    00286 QString QwtLegendButton::title() const
    00287 {
    00288     return text();
    00289 }
    00290
    00295 QwtText *QwtLegendButton::titleText() const
    00296 {
    00297     return QwtText::makeText(text(), usedTextFormat(),
    00298         alignment(), font());
    00299 }
    00300
    00305 QwtLegendLabel::QwtLegendLabel(QWidget *parent, const char *name):
    00306     QLabel(parent, name)
    00307 {
    00308     init();
    00309 }
    00310
    00318 QwtLegendLabel::QwtLegendLabel(const QwtSymbol &symbol,
    00319         const QPen &curvePen, const QString &text,
    00320         QWidget *parent, const char *name):
    00321     QLabel(text, parent, name),
    00322     QwtLegendItem(symbol, curvePen)
    00323 {
    00324     init();
    00325 }
    00326
    00327 void QwtLegendLabel::init()
    00328 {
    00329     setAlignment(Qt::AlignLeft | Qt::AlignVCenter |
    00330         Qt::ExpandTabs | Qt::WordBreak);
    00331     setIndent(Margin + IdentifierWidth + 2 * Margin);
    00332     setMargin(Margin);
    00333 }
    00334
    00341 void QwtLegendLabel::setTitle(const QString &title)
    00342 {
    00343     setText(title);
    00344 }
    00345
    00350 QString QwtLegendLabel::title() const
    00351 {
    00352     return text();
    00353 }
    00354
    00359 QwtText *QwtLegendLabel::titleText() const
    00360 {
    00361     return QwtText::makeText(text(), textFormat(),
    00362         alignment(), font());
    00363 }
    00364
    00368 void QwtLegendLabel::drawContents(QPainter *painter)
    00369 {
    00370     QLabel::drawContents(painter);
    00371
    00372     QRect rect = contentsRect();
    00373     rect.setX(rect.x() + Margin);
    00374     rect.setWidth(IdentifierWidth);
    00375
    00376     drawIdentifier(painter, rect);
    00377 }
    00378
    00379 void QwtLegendLabel::updateItem()
    00380 {
    00381     update();
    00382 }
    00383
    00388 QwtLegend::QwtLegend(QWidget *parent, const char *name):
    00389     QScrollView(parent, name),
    00390     d_readOnly(FALSE),
    00391     d_displayPolicy(QwtLegend::Auto),
    00392     d_identifierMode(QwtLegendButton::ShowLine
    00393              | QwtLegendButton::ShowSymbol
    00394              | QwtLegendButton::ShowText)
    00395 {
    00396     setFrameStyle(NoFrame);
    00397     setResizePolicy(Manual);
    00398
    00399     viewport()->setBackgroundMode(NoBackground); // Avoid flicker
    00400
    00401     d_contentsWidget = new QWidget(viewport());
    00402     d_contentsWidget->installEventFilter(this);
    00403
    00404     QwtDynGridLayout *layout = new QwtDynGridLayout(d_contentsWidget);
    00405     layout->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
    00406     layout->setAutoAdd(TRUE);
    00407
    00408     addChild(d_contentsWidget);
    00409 }
    00410
    00415 void QwtLegend::setReadOnly(bool readOnly)
    00416 {
    00417     d_readOnly = readOnly;
    00418 }
    00419
    00424 bool QwtLegend::isReadOnly() const
    00425 {
    00426     return d_readOnly;
    00427 }
    00428
    00437 void QwtLegend::setDisplayPolicy(LegendDisplayPolicy policy, int mode)
    00438 {
    00439     d_displayPolicy = policy;
    00440     if (-1 != mode)
    00441        d_identifierMode = mode;
    00442 }
    00443
    00450 QwtLegend::LegendDisplayPolicy QwtLegend::displayPolicy() const
    00451 {
    00452     return d_displayPolicy;
    00453 }
    00454
    00462 int QwtLegend::identifierMode() const
    00463 {
    00464     return d_identifierMode;
    00465 }
    00466
    00471 QWidget *QwtLegend::contentsWidget()
    00472 {
    00473     return d_contentsWidget;
    00474 }
    00475
    00481 const QWidget *QwtLegend::contentsWidget() const
    00482 {
    00483     return d_contentsWidget;
    00484 }
    00485
    00493 void QwtLegend::insertItem(QWidget *item, long key)
    00494 {
    00495     if ( item == NULL || key < 0 )
    00496         return;
    00497
    00498     if ( item->parent() != d_contentsWidget )
    00499         item->reparent(d_contentsWidget, QPoint(0, 0));
    00500
    00501     item->show();
    00502
    00503     if ( d_items.count() > d_items.size() - 5 )
    00504         d_items.resize(d_items.count() + 5);
    00505
    00506     d_items.insert(key, item);
    00507
    00508     layoutContents();
    00509
    00510     QWidget *w = 0;
    00511
    00512     if ( d_contentsWidget->layout() )
    00513     {
    00514         // set tab focus chain
    00515
    00516         QLayoutIterator layoutIterator =
    00517             d_contentsWidget->layout()->iterator();
    00518
    00519         for ( QLayoutItem *item = layoutIterator.current();
    00520             item != 0; item = ++layoutIterator)
    00521         {
    00522             if ( w && item->widget() )
    00523                 QWidget::setTabOrder(w, item->widget());
    00524
    00525             w = item->widget();
    00526         }
    00527     }
    00528 }
    00529
    00531 QWidget *QwtLegend::findItem(long key)
    00532 {
    00533     return d_items.find(key);
    00534 }
    00535
    00537 const QWidget *QwtLegend::findItem(long key) const
    00538 {
    00539     return d_items.find(key);
    00540 }
    00541
    00543 QWidget *QwtLegend::takeItem(long key)
    00544 {
    00545     return d_items.take(key);
    00546 }
    00547
    00553 long QwtLegend::key(const QWidget *item) const
    00554 {
    00555     QWidgetIntDictIt it(d_items);
    00556     for ( const QWidget *w = it.toFirst(); w != 0; w = ++it)
    00557     {
    00558         if ( w == item )
    00559             return it.currentKey();
    00560     }
    00561     return -1;
    00562 }
    00563
    00565 void QwtLegend::clear()
    00566 {
    00567     // We can't delete the items while we are running
    00568     // through the iterator. So we collect them in
    00569     // a list first.
    00570
    00571     QValueList<QWidget *> clearList;
    00572
    00573     QWidgetIntDictIt it(d_items);
    00574     for ( QWidget *item = it.toFirst(); item != 0; item = ++it)
    00575         clearList += item;
    00576
    00577     for ( uint i = 0; i < clearList.count(); i++ )
    00578         delete clearList[i];
    00579
    00580 #if QT_VERSION < 232
    00581     // In Qt 2.3.0 the ChildRemoved events are not sent, before the
    00582     // first show of the legend. Thus the deleted items are not cleared
    00583     // from the list in QwtLegend::eventFilter. In most cases
    00584     // the following clear is useless, but is is safe to do so.
    00585
    00586     d_items.clear();
    00587 #endif
    00588 }
    00589
    00591 QWidgetIntDictIt QwtLegend::itemIterator() const
    00592 {
    00593     return QWidgetIntDictIt(d_items);
    00594 }
    00595
    00597 QSize QwtLegend::sizeHint() const
    00598 {
    00599     QSize hint = d_contentsWidget->sizeHint();
    00600     hint += QSize(2 * frameWidth(), 2 * frameWidth());
    00601
    00602     return hint;
    00603 }
    00604
    00608 int QwtLegend::heightForWidth(int w) const
    00609 {
    00610     w -= 2 * frameWidth();
    00611
    00612     int h = d_contentsWidget->heightForWidth(w);
    00613     if ( h <= 0 ) // not implemented, we try the layout
    00614     {
    00615         QLayout *l = d_contentsWidget->layout();
    00616         if ( l && l->hasHeightForWidth() )
    00617         {
    00618             h = l->heightForWidth(w);
    00619             h += 2 * frameWidth();
    00620         }
    00621     }
    00622
    00623     return h;
    00624 }
    00625
    00629 void QwtLegend::layoutContents()
    00630 {
    00631     const QSize visibleSize = viewport()->size();
    00632
    00633     const QLayout *l = d_contentsWidget->layout();
    00634     if ( l && l->inherits("QwtDynGridLayout") )
    00635     {
    00636         const QwtDynGridLayout *tl = (const QwtDynGridLayout *)l;
    00637
    00638         const int minW = int(tl->maxItemWidth()) + 2 * tl->margin();
    00639
    00640         int w = QMAX(visibleSize.width(), minW);
    00641         int h = QMAX(tl->heightForWidth(w), visibleSize.height());
    00642
    00643         const int vpWidth = viewportSize(w, h).width();
    00644
    00645         if ( w > vpWidth )
    00646         {
    00647             w = QMAX(vpWidth, minW);
    00648             h = QMAX(tl->heightForWidth(w), visibleSize.height());
    00649         }
    00650
    00651         d_contentsWidget->resize(w, h);
    00652         resizeContents(w, h);
    00653     }
    00654 }
    00655
    00656 /*
    00657   Filter QEvent::ChildRemoved, and QEvent::LayoutHint for
    00658   QwtLegend::contentsWidget().
    00659 */
    00660
    00662 bool QwtLegend::eventFilter(QObject *o, QEvent *e)
    00663 {
    00664     if ( o == d_contentsWidget )
    00665     {
    00666         switch(e->type())
    00667         {
    00668             case QEvent::ChildRemoved:
    00669             {
    00670                 const QChildEvent *ce = (const QChildEvent *)e;
    00671                 if ( ce->child()->isWidgetType() )
    00672                     (void)takeItem(key((QWidget *)ce->child()));
    00673                 break;
    00674             }
    00675             case QEvent::LayoutHint:
    00676             {
    00677                 layoutContents();
    00678                 break;
    00679             }
    00680             default:
    00681                 break;
    00682         }
    00683     }
    00684
    00685     return QScrollView::eventFilter(o, e);
    00686 }
    00687
    00692 void QwtLegend::viewportResizeEvent(QResizeEvent *e)
    00693 {
    00694     QScrollView::viewportResizeEvent(e);
    00695
    00696     // It's not safe to update the layout now, because
    00697     // we are in an internal update of the scrollview framework.
    00698     // So we delay the update by posting a LayoutHint.
    00699
    00700     QApplication::postEvent(d_contentsWidget, new QEvent(QEvent::LayoutHint));
    00701 }