qwt_legend_item.cpp 12.4 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
5
 *
pixhawk's avatar
pixhawk committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

// vim: expandtab

#include <qpainter.h>
#include <qdrawutil.h>
#include <qstyle.h>
#include <qpen.h>
#if QT_VERSION >= 0x040000
#include <qevent.h>
#include <qstyleoption.h>
#endif
#include "qwt_math.h"
#include "qwt_painter.h"
#include "qwt_symbol.h"
#include "qwt_legend_item.h"

static const int ButtonFrame = 2;
static const int Margin = 2;

static QSize buttonShift(const QwtLegendItem *w)
{
#if QT_VERSION < 0x040000
    const int ph = w->style().pixelMetric(
32
                       QStyle::PM_ButtonShiftHorizontal, w);
pixhawk's avatar
pixhawk committed
33
    const int pv = w->style().pixelMetric(
34
                       QStyle::PM_ButtonShiftVertical, w);
pixhawk's avatar
pixhawk committed
35 36 37 38 39
#else
    QStyleOption option;
    option.init(w);

    const int ph = w->style()->pixelMetric(
40
                       QStyle::PM_ButtonShiftHorizontal, &option, w);
pixhawk's avatar
pixhawk committed
41
    const int pv = w->style()->pixelMetric(
42
                       QStyle::PM_ButtonShiftVertical, &option, w);
pixhawk's avatar
pixhawk committed
43 44 45 46 47 48 49 50 51 52 53 54 55
#endif
    return QSize(ph, pv);
}

class QwtLegendItem::PrivateData
{
public:
    PrivateData():
        itemMode(QwtLegend::ReadOnlyItem),
        isDown(false),
        identifierWidth(8),
        identifierMode(QwtLegendItem::ShowLine | QwtLegendItem::ShowText),
        curvePen(Qt::NoPen),
56
        spacing(Margin) {
pixhawk's avatar
pixhawk committed
57 58 59
        symbol = new QwtSymbol();
    }

60
    ~PrivateData() {
pixhawk's avatar
pixhawk committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
        delete symbol;
    }

    QwtLegend::LegendItemMode itemMode;
    bool isDown;

    int identifierWidth;
    int identifierMode;
    QwtSymbol *symbol;
    QPen curvePen;

    int spacing;
};

/*!
  \param parent Parent widget
*/
QwtLegendItem::QwtLegendItem(QWidget *parent):
    QwtTextLabel(parent)
{
    d_data = new PrivateData;
    init(QwtText());
}

/*!
  \param symbol Curve symbol
  \param curvePen Curve pen
  \param text Label text
  \param parent Parent widget
*/
91 92 93
QwtLegendItem::QwtLegendItem(const QwtSymbol &symbol,
                             const QPen &curvePen, const QwtText &text,
                             QWidget *parent):
pixhawk's avatar
pixhawk committed
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    QwtTextLabel(parent)
{
    d_data = new PrivateData;

    delete d_data->symbol;
    d_data->symbol = symbol.clone();

    d_data->curvePen = curvePen;

    init(text);
}

void QwtLegendItem::init(const QwtText &text)
{
    setMargin(Margin);
    setIndent(margin() + d_data->identifierWidth + 2 * d_data->spacing);
    setText(text);
}

//! Destructor
QwtLegendItem::~QwtLegendItem()
{
    delete d_data;
    d_data = NULL;
}

/*!
   Set the text to the legend item

   \param text Text label
    \sa QwtTextLabel::text()
*/
void QwtLegendItem::setText(const QwtText &text)
{
    const int flags = Qt::AlignLeft | Qt::AlignVCenter
#if QT_VERSION < 0x040000
130
                      | Qt::WordBreak | Qt::ExpandTabs;
pixhawk's avatar
pixhawk committed
131
#else
132
                      | Qt::TextExpandTabs | Qt::TextWordWrap;
pixhawk's avatar
pixhawk committed
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#endif

    QwtText txt = text;
    txt.setRenderFlags(flags);

    QwtTextLabel::setText(txt);
}

/*!
   Set the item mode
   The default is QwtLegend::ReadOnlyItem

   \param mode Item mode
   \sa itemMode()
*/
148 149 150 151
void QwtLegendItem::setItemMode(QwtLegend::LegendItemMode mode)
{
    d_data->itemMode = mode;
    d_data->isDown = false;
pixhawk's avatar
pixhawk committed
152 153 154 155 156 157 158 159 160 161

#if QT_VERSION >= 0x040000
    using namespace Qt;
#endif
    setFocusPolicy(mode != QwtLegend::ReadOnlyItem ? TabFocus : NoFocus);
    setMargin(ButtonFrame + Margin);

    updateGeometry();
}

162
/*!
pixhawk's avatar
pixhawk committed
163 164 165 166
   Return the item mode

   \sa setItemMode()
*/
167 168 169
QwtLegend::LegendItemMode QwtLegendItem::itemMode() const
{
    return d_data->itemMode;
pixhawk's avatar
pixhawk committed
170 171 172 173 174 175 176 177 178 179 180
}

/*!
  Set identifier mode.
  Default is ShowLine | ShowText.
  \param mode Or'd values of IdentifierMode

  \sa identifierMode()
*/
void QwtLegendItem::setIdentifierMode(int mode)
{
181
    if ( mode != d_data->identifierMode ) {
pixhawk's avatar
pixhawk committed
182 183 184 185 186 187 188 189 190
        d_data->identifierMode = mode;
        update();
    }
}

/*!
  Or'd values of IdentifierMode.
  \sa setIdentifierMode(), IdentifierMode
*/
191 192 193
int QwtLegendItem::identifierMode() const
{
    return d_data->identifierMode;
pixhawk's avatar
pixhawk committed
194 195 196 197 198 199 200 201 202 203 204 205 206
}

/*!
  Set the width for the identifier
  Default is 8 pixels

  \param width New width

  \sa identifierMode(), identifierWidth
*/
void QwtLegendItem::setIdentfierWidth(int width)
{
    width = qwtMax(width, 0);
207
    if ( width != d_data->identifierWidth ) {
pixhawk's avatar
pixhawk committed
208
        d_data->identifierWidth = width;
209 210
        setIndent(margin() + d_data->identifierWidth
                  + 2 * d_data->spacing);
pixhawk's avatar
pixhawk committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    }
}
/*!
   Return the width of the identifier

   \sa setIdentfierWidth
*/
int QwtLegendItem::identifierWidth() const
{
    return d_data->identifierWidth;
}

/*!
   Change the spacing
   \param spacing Spacing
   \sa spacing(), identifierWidth(), QwtTextLabel::margin()
*/
void QwtLegendItem::setSpacing(int spacing)
{
    spacing = qwtMax(spacing, 0);
231
    if ( spacing != d_data->spacing ) {
pixhawk's avatar
pixhawk committed
232
        d_data->spacing = spacing;
233 234
        setIndent(margin() + d_data->identifierWidth
                  + 2 * d_data->spacing);
pixhawk's avatar
pixhawk committed
235 236 237 238 239 240 241 242 243 244 245 246
    }
}

/*!
   Return the spacing
   \sa setSpacing(), identifierWidth(), QwtTextLabel::margin()
*/
int QwtLegendItem::spacing() const
{
    return d_data->spacing;
}

247
/*!
pixhawk's avatar
pixhawk committed
248 249 250 251 252
  Set curve symbol.
  \param symbol Symbol

  \sa symbol()
*/
253
void QwtLegendItem::setSymbol(const QwtSymbol &symbol)
pixhawk's avatar
pixhawk committed
254 255 256 257 258
{
    delete d_data->symbol;
    d_data->symbol = symbol.clone();
    update();
}
259

pixhawk's avatar
pixhawk committed
260 261 262 263
/*!
  \return The curve symbol.
  \sa setSymbol()
*/
264 265 266
const QwtSymbol& QwtLegendItem::symbol() const
{
    return *d_data->symbol;
pixhawk's avatar
pixhawk committed
267 268
}

269 270

/*!
pixhawk's avatar
pixhawk committed
271 272 273 274 275
  Set curve pen.
  \param pen Curve pen

  \sa curvePen()
*/
276
void QwtLegendItem::setCurvePen(const QPen &pen)
pixhawk's avatar
pixhawk committed
277
{
278
    if ( pen != d_data->curvePen ) {
pixhawk's avatar
pixhawk committed
279 280 281 282 283 284 285 286 287
        d_data->curvePen = pen;
        update();
    }
}

/*!
  \return The curve pen.
  \sa setCurvePen()
*/
288 289 290
const QPen& QwtLegendItem::curvePen() const
{
    return d_data->curvePen;
pixhawk's avatar
pixhawk committed
291 292
}

293
/*!
pixhawk's avatar
pixhawk committed
294 295 296 297 298 299 300 301 302 303
  Paint the identifier to a given rect.
  \param painter Painter
  \param rect Rect where to paint
*/
void QwtLegendItem::drawIdentifier(
    QPainter *painter, const QRect &rect) const
{
    if ( rect.isEmpty() )
        return;

304
    if ( (d_data->identifierMode & ShowLine ) && (d_data->curvePen.style() != Qt::NoPen) ) {
pixhawk's avatar
pixhawk committed
305 306
        painter->save();
        painter->setPen(d_data->curvePen);
307 308
        QwtPainter::drawLine(painter, rect.left(), rect.center().y(),
                             rect.right(), rect.center().y());
pixhawk's avatar
pixhawk committed
309 310 311
        painter->restore();
    }

312 313 314
    if ( (d_data->identifierMode & ShowSymbol)
            && (d_data->symbol->style() != QwtSymbol::NoSymbol) ) {
        QSize symbolSize =
pixhawk's avatar
pixhawk committed
315 316 317 318
            QwtPainter::metricsMap().screenToLayout(d_data->symbol->size());

        // scale the symbol size down if it doesn't fit into rect.

319 320
        if ( rect.width() < symbolSize.width() ) {
            const double ratio =
pixhawk's avatar
pixhawk committed
321 322 323 324
                double(symbolSize.width()) / double(rect.width());
            symbolSize.setWidth(rect.width());
            symbolSize.setHeight(qRound(symbolSize.height() / ratio));
        }
325 326
        if ( rect.height() < symbolSize.height() ) {
            const double ratio =
pixhawk's avatar
pixhawk committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
                double(symbolSize.width()) / double(rect.width());
            symbolSize.setHeight(rect.height());
            symbolSize.setWidth(qRound(symbolSize.width() / ratio));
        }

        QRect symbolRect;
        symbolRect.setSize(symbolSize);
        symbolRect.moveCenter(rect.center());

        painter->save();
        painter->setBrush(d_data->symbol->brush());
        painter->setPen(d_data->symbol->pen());
        d_data->symbol->draw(painter, symbolRect);
        painter->restore();
    }
}

/*!
  Draw the legend item to a given rect.
  \param painter Painter
  \param rect Rect where to paint the button
*/

void QwtLegendItem::drawItem(QPainter *painter, const QRect &rect) const
{
    painter->save();

    const QwtMetricsMap &map = QwtPainter::metricsMap();

    const int m = map.screenToLayoutX(margin());
    const int spacing = map.screenToLayoutX(d_data->spacing);
    const int identifierWidth = map.screenToLayoutX(d_data->identifierWidth);

360 361
    const QRect identifierRect(rect.x() + m, rect.y(),
                               identifierWidth, rect.height());
pixhawk's avatar
pixhawk committed
362 363 364 365 366 367
    drawIdentifier(painter, identifierRect);

    // Label

    QRect titleRect = rect;
    titleRect.setX(identifierRect.right() + 2 * spacing);
368

pixhawk's avatar
pixhawk committed
369 370 371 372 373 374 375 376 377 378 379 380 381
    text().draw(painter, titleRect);

    painter->restore();
}

//! Paint event
void QwtLegendItem::paintEvent(QPaintEvent *e)
{
    const QRect cr = contentsRect();

    QPainter painter(this);
    painter.setClipRegion(e->region());

382 383
    if ( d_data->isDown ) {
        qDrawWinButton(&painter, 0, 0, width(), height(),
pixhawk's avatar
pixhawk committed
384
#if QT_VERSION < 0x040000
385
                       colorGroup(),
pixhawk's avatar
pixhawk committed
386
#else
387
                       palette(),
pixhawk's avatar
pixhawk committed
388
#endif
389
                       true);
pixhawk's avatar
pixhawk committed
390 391 392 393
    }

    painter.save();

394
    if ( d_data->isDown ) {
pixhawk's avatar
pixhawk committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417
        const QSize shiftSize = buttonShift(this);
        painter.translate(shiftSize.width(), shiftSize.height());
    }

    painter.setClipRect(cr);

    drawContents(&painter);

    QRect rect = cr;
    rect.setX(rect.x() + margin());
    if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
        rect.setX(rect.x() + ButtonFrame);

    rect.setWidth(d_data->identifierWidth);

    drawIdentifier(&painter, rect);

    painter.restore();
}

//! Handle mouse press events
void QwtLegendItem::mousePressEvent(QMouseEvent *e)
{
418 419 420 421 422 423 424 425 426 427 428 429
    if ( e->button() == Qt::LeftButton ) {
        switch(d_data->itemMode) {
        case QwtLegend::ClickableItem: {
            setDown(true);
            return;
        }
        case QwtLegend::CheckableItem: {
            setDown(!isDown());
            return;
        }
        default:
            ;
pixhawk's avatar
pixhawk committed
430 431 432 433 434 435 436 437
        }
    }
    QwtTextLabel::mousePressEvent(e);
}

//! Handle mouse release events
void QwtLegendItem::mouseReleaseEvent(QMouseEvent *e)
{
438 439 440 441 442 443 444 445 446 447 448
    if ( e->button() == Qt::LeftButton ) {
        switch(d_data->itemMode) {
        case QwtLegend::ClickableItem: {
            setDown(false);
            return;
        }
        case QwtLegend::CheckableItem: {
            return; // do nothing, but accept
        }
        default:
            ;
pixhawk's avatar
pixhawk committed
449 450 451 452 453 454 455 456
        }
    }
    QwtTextLabel::mouseReleaseEvent(e);
}

//! Handle key press events
void QwtLegendItem::keyPressEvent(QKeyEvent *e)
{
457 458 459 460 461 462 463 464 465 466 467 468 469 470
    if ( e->key() == Qt::Key_Space ) {
        switch(d_data->itemMode) {
        case QwtLegend::ClickableItem: {
            if ( !e->isAutoRepeat() )
                setDown(true);
            return;
        }
        case QwtLegend::CheckableItem: {
            if ( !e->isAutoRepeat() )
                setDown(!isDown());
            return;
        }
        default:
            ;
pixhawk's avatar
pixhawk committed
471 472 473 474 475 476 477 478 479
        }
    }

    QwtTextLabel::keyPressEvent(e);
}

//! Handle key release events
void QwtLegendItem::keyReleaseEvent(QKeyEvent *e)
{
480 481 482 483 484 485 486 487 488 489 490 491
    if ( e->key() == Qt::Key_Space ) {
        switch(d_data->itemMode) {
        case QwtLegend::ClickableItem: {
            if ( !e->isAutoRepeat() )
                setDown(false);
            return;
        }
        case QwtLegend::CheckableItem: {
            return; // do nothing, but accept
        }
        default:
            ;
pixhawk's avatar
pixhawk committed
492 493 494 495 496 497 498 499 500 501 502 503 504 505
        }
    }

    QwtTextLabel::keyReleaseEvent(e);
}

/*!
    Check/Uncheck a the item

    \param on check/uncheck
    \sa setItemMode()
*/
void QwtLegendItem::setChecked(bool on)
{
506
    if ( d_data->itemMode == QwtLegend::CheckableItem ) {
pixhawk's avatar
pixhawk committed
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
        const bool isBlocked = signalsBlocked();
        blockSignals(true);

        setDown(on);

        blockSignals(isBlocked);
    }
}

//! Return true, if the item is checked
bool QwtLegendItem::isChecked() const
{
    return d_data->itemMode == QwtLegend::CheckableItem && isDown();
}

//! Set the item being down
void QwtLegendItem::setDown(bool down)
{
    if ( down == d_data->isDown )
        return;

    d_data->isDown = down;
    update();

531
    if ( d_data->itemMode == QwtLegend::ClickableItem ) {
pixhawk's avatar
pixhawk committed
532 533
        if ( d_data->isDown )
            emit pressed();
534
        else {
pixhawk's avatar
pixhawk committed
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
            emit released();
            emit clicked();
        }
    }

    if ( d_data->itemMode == QwtLegend::CheckableItem )
        emit checked(d_data->isDown);
}

//! Return true, if the item is down
bool QwtLegendItem::isDown() const
{
    return d_data->isDown;
}

//! Return a size hint
QSize QwtLegendItem::sizeHint() const
{
    QSize sz = QwtTextLabel::sizeHint();
    if ( d_data->itemMode != QwtLegend::ReadOnlyItem )
        sz += buttonShift(this);

    return sz;
}

void QwtLegendItem::drawText(QPainter *painter, const QRect &rect)
{
    QwtTextLabel::drawText(painter, rect);
}