# qwt_legend_item.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 <qpainter.h>
    00013 #include <qdrawutil.h>
    00014 #include <qstyle.h>
    00015 #include <qpen.h>
    00016 #if QT_VERSION >= 0x040000
    00017 #include <qevent.h>
    00018 #include <qstyleoption.h>
    00019 #endif
    00020 #include "qwt_math.h"
    00021 #include "qwt_painter.h"
    00022 #include "qwt_symbol.h"
    00023 #include "qwt_legend_item.h"
    00024
    00025 static const int ButtonFrame = 2;
    00026 static const int Margin = 2;
    00027
    00028 static QSize buttonShift(const QwtLegendItem *w)
    00029 {
    00030 #if QT_VERSION < 0x040000
    00031     const int ph = w->style().pixelMetric(
    00032         QStyle::PM_ButtonShiftHorizontal, w);
    00033     const int pv = w->style().pixelMetric(
    00034         QStyle::PM_ButtonShiftVertical, w);
    00035 #else
    00036     QStyleOption option;
    00037     option.init(w);
    00038
    00039     const int ph = w->style()->pixelMetric(
    00040         QStyle::PM_ButtonShiftHorizontal, &option, w);
    00041     const int pv = w->style()->pixelMetric(
    00042         QStyle::PM_ButtonShiftVertical, &option, w);
    00043 #endif
    00044     return QSize(ph, pv);
    00045 }
    00046
    00047 class QwtLegendItem::PrivateData
    00048 {
    00049 public:
    00050     PrivateData():
    00051         itemMode(QwtLegend::ReadOnlyItem),
    00052         isDown(false),
    00053         identifierWidth(8),
    00054         identifierMode(QwtLegendItem::ShowLine | QwtLegendItem::ShowText),
    00055         curvePen(Qt::NoPen),
    00056         spacing(Margin)
    00057     {
    00058         symbol = new QwtSymbol();
    00059     }
    00060
    00061     ~PrivateData()
    00062     {
    00063         delete symbol;
    00064     }
    00065
    00066     QwtLegend::LegendItemMode itemMode;
    00067     bool isDown;
    00068
    00069     int identifierWidth;
    00070     int identifierMode;
    00071     QwtSymbol *symbol;
    00072     QPen curvePen;
    00073
    00074     int spacing;
    00075 };
    00076
    00080 QwtLegendItem::QwtLegendItem(QWidget *parent):
    00081     QwtTextLabel(parent)
    00082 {
    00083     d_data = new PrivateData;
    00084     init(QwtText());
    00085 }
    00086
    00093 QwtLegendItem::QwtLegendItem(const QwtSymbol &symbol,
    00094         const QPen &curvePen, const QwtText &text,
    00095         QWidget *parent):
    00096     QwtTextLabel(parent)
    00097 {
    00098     d_data = new PrivateData;
    00099
    00100     delete d_data->symbol;
    00101     d_data->symbol = symbol.clone();
    00102
    00103     d_data->curvePen = curvePen;
    00104
    00105     init(text);
    00106 }
    00107
    00108 void QwtLegendItem::init(const QwtText &text)
    00109 {
    00110     setMargin(Margin);
    00111     setIndent(margin() + d_data->identifierWidth + 2 * d_data->spacing);
    00112     setText(text);
    00113 }
    00114
    00116 QwtLegendItem::~QwtLegendItem()
    00117 {
    00118     delete d_data;
    00119     d_data = NULL;
    00120 }
    00121
    00128 void QwtLegendItem::setText(const QwtText &text)
    00129 {
    00130     const int flags = Qt::AlignLeft | Qt::AlignVCenter
    00131 #if QT_VERSION < 0x040000
    00132         | Qt::WordBreak | Qt::ExpandTabs;
    00133 #else
    00134         | Qt::TextExpandTabs | Qt::TextWordWrap;
    00135 #endif
    00136
    00137     QwtText txt = text;
    00138     txt.setRenderFlags(flags);
    00139
    00140     QwtTextLabel::setText(txt);
    00141 }
    00142
    00150 void QwtLegendItem::setItemMode(QwtLegend::LegendItemMode mode)
    00151 {
    00152     d_data->itemMode = mode;
    00153     d_data->isDown = false;
    00154
    00155 #if QT_VERSION >= 0x040000
    00156     using namespace Qt;
    00157 #endif
    00158     setFocusPolicy(mode != QwtLegend::ReadOnlyItem ? TabFocus : NoFocus);
    00159     setMargin(ButtonFrame + Margin);
    00160
    00161     updateGeometry();
    00162 }
    00163
    00169 QwtLegend::LegendItemMode QwtLegendItem::itemMode() const
    00170 {
    00171     return d_data->itemMode;
    00172 }
    00173
    00181 void QwtLegendItem::setIdentifierMode(int mode)
    00182 {
    00183     if ( mode != d_data->identifierMode )
    00184     {
    00185         d_data->identifierMode = mode;
    00186         update();
    00187     }
    00188 }
    00189
    00194 int QwtLegendItem::identifierMode() const
    00195 {
    00196     return d_data->identifierMode;
    00197 }
    00198
    00207 void QwtLegendItem::setIdentfierWidth(int width)
    00208 {
    00209     width = qwtMax(width, 0);
    00210     if ( width != d_data->identifierWidth )
    00211     {
    00212         d_data->identifierWidth = width;
    00213         setIndent(margin() + d_data->identifierWidth
    00214             + 2 * d_data->spacing);
    00215     }
    00216 }
    00222 int QwtLegendItem::identifierWidth() const
    00223 {
    00224     return d_data->identifierWidth;
    00225 }
    00226
    00232 void QwtLegendItem::setSpacing(int spacing)
    00233 {
    00234     spacing = qwtMax(spacing, 0);
    00235     if ( spacing != d_data->spacing )
    00236     {
    00237         d_data->spacing = spacing;
    00238         setIndent(margin() + d_data->identifierWidth
    00239             + 2 * d_data->spacing);
    00240     }
    00241 }
    00242
    00247 int QwtLegendItem::spacing() const
    00248 {
    00249     return d_data->spacing;
    00250 }
    00251
    00258 void QwtLegendItem::setSymbol(const QwtSymbol &symbol)
    00259 {
    00260     delete d_data->symbol;
    00261     d_data->symbol = symbol.clone();
    00262     update();
    00263 }
    00264
    00269 const QwtSymbol& QwtLegendItem::symbol() const
    00270 {
    00271     return *d_data->symbol;
    00272 }
    00273
    00274
    00281 void QwtLegendItem::setCurvePen(const QPen &pen)
    00282 {
    00283     if ( pen != d_data->curvePen )
    00284     {
    00285         d_data->curvePen = pen;
    00286         update();
    00287     }
    00288 }
    00289
    00294 const QPen& QwtLegendItem::curvePen() const
    00295 {
    00296     return d_data->curvePen;
    00297 }
    00298
    00304 void QwtLegendItem::drawIdentifier(
    00305     QPainter *painter, const QRect &rect) const
    00306 {
    00307     if ( rect.isEmpty() )
    00308         return;
    00309
    00310     if ( (d_data->identifierMode & ShowLine ) && (d_data->curvePen.style() != Qt::NoPen) )
    00311     {
    00312         painter->save();
    00313         painter->setPen(d_data->curvePen);
    00314         QwtPainter::drawLine(painter, rect.left(), rect.center().y(),
    00315             rect.right(), rect.center().y());
    00316         painter->restore();
    00317     }
    00318
    00319     if ( (d_data->identifierMode & ShowSymbol)
    00320         && (d_data->symbol->style() != QwtSymbol::NoSymbol) )
    00321     {
    00322         QSize symbolSize =
    00323             QwtPainter::metricsMap().screenToLayout(d_data->symbol->size());
    00324
    00325         // scale the symbol size down if it doesn't fit into rect.
    00326
    00327         if ( rect.width() < symbolSize.width() )
    00328         {
    00329             const double ratio =
    00330                 double(symbolSize.width()) / double(rect.width());
    00331             symbolSize.setWidth(rect.width());
    00332             symbolSize.setHeight(qRound(symbolSize.height() / ratio));
    00333         }
    00334         if ( rect.height() < symbolSize.height() )
    00335         {
    00336             const double ratio =
    00337                 double(symbolSize.width()) / double(rect.width());
    00338             symbolSize.setHeight(rect.height());
    00339             symbolSize.setWidth(qRound(symbolSize.width() / ratio));
    00340         }
    00341
    00342         QRect symbolRect;
    00343         symbolRect.setSize(symbolSize);
    00344         symbolRect.moveCenter(rect.center());
    00345
    00346         painter->save();
    00347         painter->setBrush(d_data->symbol->brush());
    00348         painter->setPen(d_data->symbol->pen());
    00349         d_data->symbol->draw(painter, symbolRect);
    00350         painter->restore();
    00351     }
    00352 }
    00353
    00360 void QwtLegendItem::drawItem(QPainter *painter, const QRect &rect) const
    00361 {
    00362     painter->save();
    00363
    00364     const QwtMetricsMap &map = QwtPainter::metricsMap();
    00365
    00366     const int m = map.screenToLayoutX(margin());
    00367     const int spacing = map.screenToLayoutX(d_data->spacing);
    00368     const int identifierWidth = map.screenToLayoutX(d_data->identifierWidth);
    00369
    00370     const QRect identifierRect(rect.x() + m, rect.y(),
    00371         identifierWidth, rect.height());
    00372     drawIdentifier(painter, identifierRect);
    00373
    00374     // Label
    00375
    00376     QRect titleRect = rect;
    00377     titleRect.setX(identifierRect.right() + 2 * spacing);
    00378
    00379     text().draw(painter, titleRect);
    00380
    00381     painter->restore();
    00382 }
    00383
    00385 void QwtLegendItem::paintEvent(QPaintEvent *e)
    00386 {
    00387     const QRect cr = contentsRect();
    00388
    00389     QPainter painter(this);
    00390     painter.setClipRegion(e->region());
    00391
    00392     if ( d_data->isDown )
    00393     {
    00394         qDrawWinButton(&painter, 0, 0, width(), height(),
    00395 #if QT_VERSION < 0x040000
    00396             colorGroup(),
    00397 #else
    00398             palette(),
    00399 #endif
    00400             true);
    00401     }
    00402
    00403     painter.save();
    00404
    00405     if ( d_data->isDown )
    00406     {
    00407         const QSize shiftSize = buttonShift(this);
    00408         painter.translate(shiftSize.width(), shiftSize.height());
    00409     }
    00410
    00411     painter.setClipRect(cr);
    00412
    00413     drawContents(&painter);
    00414
    00415     QRect rect = cr;
    00416     rect.setX(rect.x() + margin());
    00417     if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
    00418         rect.setX(rect.x() + ButtonFrame);
    00419
    00420     rect.setWidth(d_data->identifierWidth);
    00421
    00422     drawIdentifier(&painter, rect);
    00423
    00424     painter.restore();
    00425 }
    00426
    00428 void QwtLegendItem::mousePressEvent(QMouseEvent *e)
    00429 {
    00430     if ( e->button() == Qt::LeftButton )
    00431     {
    00432         switch(d_data->itemMode)
    00433         {
    00434             case QwtLegend::ClickableItem:
    00435             {
    00436                 setDown(true);
    00437                 return;
    00438             }
    00439             case QwtLegend::CheckableItem:
    00440             {
    00441                 setDown(!isDown());
    00442                 return;
    00443             }
    00444             default:;
    00445         }
    00446     }
    00447     QwtTextLabel::mousePressEvent(e);
    00448 }
    00449
    00451 void QwtLegendItem::mouseReleaseEvent(QMouseEvent *e)
    00452 {
    00453     if ( e->button() == Qt::LeftButton )
    00454     {
    00455         switch(d_data->itemMode)
    00456         {
    00457             case QwtLegend::ClickableItem:
    00458             {
    00459                 setDown(false);
    00460                 return;
    00461             }
    00462             case QwtLegend::CheckableItem:
    00463             {
    00464                 return; // do nothing, but accept
    00465             }
    00466             default:;
    00467         }
    00468     }
    00469     QwtTextLabel::mouseReleaseEvent(e);
    00470 }
    00471
    00473 void QwtLegendItem::keyPressEvent(QKeyEvent *e)
    00474 {
    00475     if ( e->key() == Qt::Key_Space )
    00476     {
    00477         switch(d_data->itemMode)
    00478         {
    00479             case QwtLegend::ClickableItem:
    00480             {
    00481                 if ( !e->isAutoRepeat() )
    00482                     setDown(true);
    00483                 return;
    00484             }
    00485             case QwtLegend::CheckableItem:
    00486             {
    00487                 if ( !e->isAutoRepeat() )
    00488                     setDown(!isDown());
    00489                 return;
    00490             }
    00491             default:;
    00492         }
    00493     }
    00494
    00495     QwtTextLabel::keyPressEvent(e);
    00496 }
    00497
    00499 void QwtLegendItem::keyReleaseEvent(QKeyEvent *e)
    00500 {
    00501     if ( e->key() == Qt::Key_Space )
    00502     {
    00503         switch(d_data->itemMode)
    00504         {
    00505             case QwtLegend::ClickableItem:
    00506             {
    00507                 if ( !e->isAutoRepeat() )
    00508                     setDown(false);
    00509                 return;
    00510             }
    00511             case QwtLegend::CheckableItem:
    00512             {
    00513                 return; // do nothing, but accept
    00514             }
    00515             default:;
    00516         }
    00517     }
    00518
    00519     QwtTextLabel::keyReleaseEvent(e);
    00520 }
    00521
    00528 void QwtLegendItem::setChecked(bool on)
    00529 {
    00530     if ( d_data->itemMode == QwtLegend::CheckableItem )
    00531     {
    00532         const bool isBlocked = signalsBlocked();
    00533         blockSignals(true);
    00534
    00535         setDown(on);
    00536
    00537         blockSignals(isBlocked);
    00538     }
    00539 }
    00540
    00542 bool QwtLegendItem::isChecked() const
    00543 {
    00544     return d_data->itemMode == QwtLegend::CheckableItem && isDown();
    00545 }
    00546
    00548 void QwtLegendItem::setDown(bool down)
    00549 {
    00550     if ( down == d_data->isDown )
    00551         return;
    00552
    00553     d_data->isDown = down;
    00554     update();
    00555
    00556     if ( d_data->itemMode == QwtLegend::ClickableItem )
    00557     {
    00558         if ( d_data->isDown )
    00559             emit pressed();
    00560         else
    00561         {
    00562             emit released();
    00563             emit clicked();
    00564         }
    00565     }
    00566
    00567     if ( d_data->itemMode == QwtLegend::CheckableItem )
    00568         emit checked(d_data->isDown);
    00569 }
    00570
    00572 bool QwtLegendItem::isDown() const
    00573 {
    00574     return d_data->isDown;
    00575 }
    00576
    00578 QSize QwtLegendItem::sizeHint() const
    00579 {
    00580     QSize sz = QwtTextLabel::sizeHint();
    00581     if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
    00582         sz += buttonShift(this);
    00583
    00584     return sz;
    00585 }
    00586
    00587 void QwtLegendItem::drawText(QPainter *painter, const QRect &rect)
    00588 {
    00589     QwtTextLabel::drawText(painter, rect);
    00590 }