qwt_thermo.cpp 22.5 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4 5 6 7 8 9
/* -*- 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
 *****************************************************************************/

Bryant's avatar
Bryant committed
10
#include "qwt_thermo.h"
pixhawk's avatar
pixhawk committed
11 12 13
#include "qwt_scale_engine.h"
#include "qwt_scale_draw.h"
#include "qwt_scale_map.h"
Bryant's avatar
Bryant committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
#include "qwt_color_map.h"
#include <qpainter.h>
#include <qevent.h>
#include <qdrawutil.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qmath.h>

static inline void qwtDrawLine( QPainter *painter, int pos, 
    const QColor &color, const QRect &pipeRect, const QRect &liquidRect,
    Qt::Orientation orientation )
{
    painter->setPen( color );
    if ( orientation == Qt::Horizontal )
    {
        if ( pos >= liquidRect.left() && pos < liquidRect.right() )
            painter->drawLine( pos, pipeRect.top(), pos, pipeRect.bottom() );
    }
    else
    {
        if ( pos >= liquidRect.top() && pos < liquidRect.bottom() )
            painter->drawLine( pipeRect.left(), pos, pipeRect.right(), pos );
    }
}

QVector<double> qwtTickList( const QwtScaleDiv &scaleDiv )
{
    QVector<double> values;

    double lowerLimit = scaleDiv.interval().minValue();
    double upperLimit = scaleDiv.interval().maxValue();

    if ( upperLimit < lowerLimit )
        qSwap( lowerLimit, upperLimit );

    values += lowerLimit;

    for ( int tickType = QwtScaleDiv::MinorTick;
        tickType < QwtScaleDiv::NTickTypes; tickType++ )
    {
        const QList<double> ticks = scaleDiv.ticks( tickType );

        for ( int i = 0; i < ticks.count(); i++ )
        {
            const double v = ticks[i];
            if ( v > lowerLimit && v < upperLimit )
                values += v;
        }       
    }   

    values += upperLimit;
    
    return values;
}
pixhawk's avatar
pixhawk committed
68 69 70 71 72

class QwtThermo::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
        orientation( Qt::Vertical ),
        scalePosition( QwtThermo::TrailingScale ),
        spacing( 3 ),
        borderWidth( 2 ),
        pipeWidth( 10 ),
        alarmLevel( 0.0 ),
        alarmEnabled( false ),
        autoFillPipe( true ),
        originMode( QwtThermo::OriginMinimum ),
        origin( 0.0 ),
        colorMap( NULL ),
        value( 0.0 )
    {
        rangeFlags = QwtInterval::IncludeBorders;
    }

    ~PrivateData()
    {
        delete colorMap;
    }
pixhawk's avatar
pixhawk committed
93 94

    Qt::Orientation orientation;
Bryant's avatar
Bryant committed
95 96 97
    QwtThermo::ScalePosition scalePosition;

    int spacing;
pixhawk's avatar
pixhawk committed
98
    int borderWidth;
Bryant's avatar
Bryant committed
99
    int pipeWidth;
pixhawk's avatar
pixhawk committed
100

Bryant's avatar
Bryant committed
101
    QwtInterval::BorderFlags rangeFlags;
pixhawk's avatar
pixhawk committed
102 103
    double alarmLevel;
    bool alarmEnabled;
Bryant's avatar
Bryant committed
104 105 106
    bool autoFillPipe;
    QwtThermo::OriginMode originMode;
    double origin;
pixhawk's avatar
pixhawk committed
107

Bryant's avatar
Bryant committed
108 109 110 111
    QwtColorMap *colorMap;

    double value;
};
pixhawk's avatar
pixhawk committed
112

113
/*!
pixhawk's avatar
pixhawk committed
114 115 116
  Constructor
  \param parent Parent widget
*/
Bryant's avatar
Bryant committed
117 118
QwtThermo::QwtThermo( QWidget *parent ):
    QwtAbstractScale( parent )
pixhawk's avatar
pixhawk committed
119 120 121
{
    d_data = new PrivateData;

Bryant's avatar
Bryant committed
122 123
    QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
    if ( d_data->orientation == Qt::Vertical )
pixhawk's avatar
pixhawk committed
124 125
        policy.transpose();

Bryant's avatar
Bryant committed
126
    setSizePolicy( policy );
127

Bryant's avatar
Bryant committed
128 129
    setAttribute( Qt::WA_WState_OwnSizePolicy, false );
    layoutThermo( true );
pixhawk's avatar
pixhawk committed
130 131 132 133 134 135 136 137
}

//! Destructor
QwtThermo::~QwtThermo()
{
    delete d_data;
}

Bryant's avatar
Bryant committed
138 139
/*!
  \brief Exclude/Include min/max values
pixhawk's avatar
pixhawk committed
140

Bryant's avatar
Bryant committed
141 142 143 144
  According to the flags minValue() and maxValue()
  are included/excluded from the pipe. In case of an
  excluded value the corresponding tick is painted
  1 pixel off of the pipeRect().
pixhawk's avatar
pixhawk committed
145

Bryant's avatar
Bryant committed
146 147 148 149 150 151 152 153
  F.e. when a minimum
  of 0.0 has to be displayed as an empty pipe the minValue()
  needs to be excluded.

  \param flags Range flags
  \sa rangeFlags()
*/
void QwtThermo::setRangeFlags( QwtInterval::BorderFlags flags )
154
{
Bryant's avatar
Bryant committed
155 156 157 158 159
    if ( d_data->rangeFlags != flags )
    {
        d_data->rangeFlags = flags;
        update();
    }
pixhawk's avatar
pixhawk committed
160 161
}

Bryant's avatar
Bryant committed
162 163 164 165 166
/*!
  \return Range flags
  \sa setRangeFlags()
*/
QwtInterval::BorderFlags QwtThermo::rangeFlags() const
167
{
Bryant's avatar
Bryant committed
168
    return d_data->rangeFlags;
pixhawk's avatar
pixhawk committed
169 170
}

Bryant's avatar
Bryant committed
171 172 173 174 175 176 177
/*!
  Set the current value.

  \param value New Value
  \sa value()
*/
void QwtThermo::setValue( double value )
pixhawk's avatar
pixhawk committed
178
{
Bryant's avatar
Bryant committed
179 180 181
    if ( d_data->value != value )
    {
        d_data->value = value;
pixhawk's avatar
pixhawk committed
182 183 184 185 186
        update();
    }
}

//! Return the value.
187 188 189
double QwtThermo::value() const
{
    return d_data->value;
pixhawk's avatar
pixhawk committed
190 191 192 193 194 195 196 197 198
}

/*!
  \brief Set a scale draw

  For changing the labels of the scales, it
  is necessary to derive from QwtScaleDraw and
  overload QwtScaleDraw::label().

199
  \param scaleDraw ScaleDraw object, that has to be created with
Bryant's avatar
Bryant committed
200
                   new and will be deleted in ~QwtThermo() or the next
pixhawk's avatar
pixhawk committed
201 202
                   call of setScaleDraw().
*/
Bryant's avatar
Bryant committed
203
void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw )
pixhawk's avatar
pixhawk committed
204
{
Bryant's avatar
Bryant committed
205
    setAbstractScaleDraw( scaleDraw );
pixhawk's avatar
pixhawk committed
206 207 208 209 210 211 212 213
}

/*!
   \return the scale draw of the thermo
   \sa setScaleDraw()
*/
const QwtScaleDraw *QwtThermo::scaleDraw() const
{
Bryant's avatar
Bryant committed
214
    return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
215 216 217 218 219 220
}

/*!
   \return the scale draw of the thermo
   \sa setScaleDraw()
*/
221
QwtScaleDraw *QwtThermo::scaleDraw()
pixhawk's avatar
pixhawk committed
222
{
Bryant's avatar
Bryant committed
223
    return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
pixhawk's avatar
pixhawk committed
224 225
}

Bryant's avatar
Bryant committed
226 227 228 229 230
/*!
  Paint event handler
  \param event Paint event
*/
void QwtThermo::paintEvent( QPaintEvent *event )
pixhawk's avatar
pixhawk committed
231
{
Bryant's avatar
Bryant committed
232 233
    QPainter painter( this );
    painter.setClipRegion( event->region() );
pixhawk's avatar
pixhawk committed
234

Bryant's avatar
Bryant committed
235 236 237
    QStyleOption opt;
    opt.init(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
pixhawk's avatar
pixhawk committed
238

Bryant's avatar
Bryant committed
239 240 241 242 243 244
    const QRect tRect = pipeRect();

    if ( !tRect.contains( event->rect() ) )
    {
        if ( d_data->scalePosition != QwtThermo::NoScale )
            scaleDraw()->draw( &painter, palette() );
pixhawk's avatar
pixhawk committed
245
    }
Bryant's avatar
Bryant committed
246 247 248 249 250 251 252 253 254 255

    const int bw = d_data->borderWidth;

    const QBrush brush = palette().brush( QPalette::Base );
    qDrawShadePanel( &painter, 
        tRect.adjusted( -bw, -bw, bw, bw ),
        palette(), true, bw, 
        d_data->autoFillPipe ? &brush : NULL );

    drawLiquid( &painter, tRect );
pixhawk's avatar
pixhawk committed
256 257
}

Bryant's avatar
Bryant committed
258 259 260 261 262
/*! 
  Resize event handler
  \param event Resize event
*/
void QwtThermo::resizeEvent( QResizeEvent *event )
pixhawk's avatar
pixhawk committed
263
{
Bryant's avatar
Bryant committed
264
    Q_UNUSED( event );
pixhawk's avatar
pixhawk committed
265 266 267
    layoutThermo( false );
}

Bryant's avatar
Bryant committed
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
/*! 
  Qt change event handler
  \param event Event
*/
void QwtThermo::changeEvent( QEvent *event )
{
    switch( event->type() )
    {
        case QEvent::StyleChange:
        case QEvent::FontChange:
        {
            layoutThermo( true );
            break;
        }
        default:
            break;
    }
}

pixhawk's avatar
pixhawk committed
287 288
/*!
  Recalculate the QwtThermo geometry and layout based on
Bryant's avatar
Bryant committed
289 290
  pipeRect() and the fonts.

pixhawk's avatar
pixhawk committed
291 292 293 294 295
  \param update_geometry notify the layout system and call update
         to redraw the scale
*/
void QwtThermo::layoutThermo( bool update_geometry )
{
Bryant's avatar
Bryant committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
    const QRect tRect = pipeRect();
    const int bw = d_data->borderWidth + d_data->spacing;
    const bool inverted = ( upperBound() < lowerBound() );

    int from, to;

    if ( d_data->orientation == Qt::Horizontal )
    {
        from = tRect.left();
        to = tRect.right();

        if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
        {
            if ( inverted )
                to++;
            else
                from--;
        }
        if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
        {
            if ( inverted )
                from--;
            else
                to++;
320
        }
pixhawk's avatar
pixhawk committed
321

Bryant's avatar
Bryant committed
322
        if ( d_data->scalePosition == QwtThermo::TrailingScale )
323
        {
Bryant's avatar
Bryant committed
324 325 326 327 328 329 330
            scaleDraw()->setAlignment( QwtScaleDraw::TopScale );
            scaleDraw()->move( from, tRect.top() - bw );
        }
        else
        {
            scaleDraw()->setAlignment( QwtScaleDraw::BottomScale );
            scaleDraw()->move( from, tRect.bottom() + bw );
331
        }
Bryant's avatar
Bryant committed
332 333 334 335 336 337 338 339 340 341 342 343 344 345

        scaleDraw()->setLength( to - from );
    }
    else // Qt::Vertical
    {
        from = tRect.top();
        to = tRect.bottom();

        if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
        {
            if ( inverted )
                from--;
            else
                to++;
pixhawk's avatar
pixhawk committed
346
        }
Bryant's avatar
Bryant committed
347 348 349 350 351 352
        if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
        {
            if ( inverted )
                to++;
            else
                from--;
353
        }
pixhawk's avatar
pixhawk committed
354

Bryant's avatar
Bryant committed
355
        if ( d_data->scalePosition == QwtThermo::LeadingScale )
356
        {
Bryant's avatar
Bryant committed
357 358
            scaleDraw()->setAlignment( QwtScaleDraw::RightScale );
            scaleDraw()->move( tRect.right() + bw, from );
359
        }
Bryant's avatar
Bryant committed
360 361 362 363
        else
        {
            scaleDraw()->setAlignment( QwtScaleDraw::LeftScale );
            scaleDraw()->move( tRect.left() - bw, from );
pixhawk's avatar
pixhawk committed
364
        }
Bryant's avatar
Bryant committed
365 366

        scaleDraw()->setLength( to - from );
pixhawk's avatar
pixhawk committed
367
    }
Bryant's avatar
Bryant committed
368 369 370

    if ( update_geometry )
    {
pixhawk's avatar
pixhawk committed
371 372 373 374 375 376
        updateGeometry();
        update();
    }
}

/*!
Bryant's avatar
Bryant committed
377 378 379 380 381 382 383 384 385 386 387 388 389 390
  \return Bounding rectangle of the pipe ( without borders )
          in widget coordinates
*/
QRect QwtThermo::pipeRect() const
{
    int mbd = 0;
    if ( d_data->scalePosition != QwtThermo::NoScale )
    {
        int d1, d2;
        scaleDraw()->getBorderDistHint( font(), d1, d2 );
        mbd = qMax( d1, d2 );
    }
    const int bw = d_data->borderWidth;
    const int scaleOff = bw + mbd;
pixhawk's avatar
pixhawk committed
391

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

Bryant's avatar
Bryant committed
394 395 396 397
    QRect pipeRect = cr;
    if ( d_data->orientation == Qt::Horizontal )
    {
        pipeRect.adjust( scaleOff, 0, -scaleOff, 0 );
pixhawk's avatar
pixhawk committed
398

Bryant's avatar
Bryant committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
        if ( d_data->scalePosition == QwtThermo::TrailingScale )
            pipeRect.setTop( cr.top() + cr.height() - bw - d_data->pipeWidth );
        else
            pipeRect.setTop( bw );

        pipeRect.setHeight( d_data->pipeWidth );
    }
    else // Qt::Vertical
    {
        pipeRect.adjust( 0, scaleOff, 0, -scaleOff );

        if ( d_data->scalePosition == QwtThermo::LeadingScale )
            pipeRect.setLeft( bw );
        else 
            pipeRect.setLeft( cr.left() + cr.width() - bw - d_data->pipeWidth );

        pipeRect.setWidth( d_data->pipeWidth );
    }

    return pipeRect;
}

/*!
  \brief Set the orientation.
  \param orientation Allowed values are Qt::Horizontal and Qt::Vertical.

  \sa orientation(), scalePosition()
pixhawk's avatar
pixhawk committed
426
*/
Bryant's avatar
Bryant committed
427
void QwtThermo::setOrientation( Qt::Orientation orientation )
pixhawk's avatar
pixhawk committed
428
{
Bryant's avatar
Bryant committed
429
    if ( orientation == d_data->orientation )
pixhawk's avatar
pixhawk committed
430 431
        return;

Bryant's avatar
Bryant committed
432
    d_data->orientation = orientation;
pixhawk's avatar
pixhawk committed
433

Bryant's avatar
Bryant committed
434 435 436 437 438 439 440
    if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
    {
        QSizePolicy sp = sizePolicy();
        sp.transpose();
        setSizePolicy( sp );

        setAttribute( Qt::WA_WState_OwnSizePolicy, false );
pixhawk's avatar
pixhawk committed
441 442
    }

Bryant's avatar
Bryant committed
443
    layoutThermo( true );
pixhawk's avatar
pixhawk committed
444 445 446
}

/*!
Bryant's avatar
Bryant committed
447 448 449 450 451 452 453
  \return Orientation
  \sa setOrientation()
*/
Qt::Orientation QwtThermo::orientation() const
{
    return d_data->orientation;
}
pixhawk's avatar
pixhawk committed
454

Bryant's avatar
Bryant committed
455 456 457 458 459 460 461 462
/*!
  \brief Change how the origin is determined.
  \sa originMode(), serOrigin(), origin()
 */
void QwtThermo::setOriginMode( OriginMode m )
{
    if ( m == d_data->originMode )
        return;
463

Bryant's avatar
Bryant committed
464 465 466
    d_data->originMode = m;
    update();
}
pixhawk's avatar
pixhawk committed
467

Bryant's avatar
Bryant committed
468 469 470 471 472
/*!
  \return Mode, how the origin is determined.
  \sa setOriginMode(), serOrigin(), origin()
 */
QwtThermo::OriginMode QwtThermo::originMode() const
pixhawk's avatar
pixhawk committed
473
{
Bryant's avatar
Bryant committed
474
    return d_data->originMode;
pixhawk's avatar
pixhawk committed
475 476
}

Bryant's avatar
Bryant committed
477 478 479 480 481 482 483 484 485 486
/*!
  \brief Specifies the custom origin.

  If originMode is set to OriginCustom this property controls where the
  liquid starts.

  \param origin New origin level
  \sa setOriginMode(), originMode(), origin()
 */
void QwtThermo::setOrigin( double origin )
pixhawk's avatar
pixhawk committed
487
{
Bryant's avatar
Bryant committed
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
    if ( origin == d_data->origin )
        return;

    d_data->origin = origin;
    update();
}

/*!
  \return Origin of the thermo, when OriginCustom is enabled
  \sa setOrigin(), setOriginMode(), originMode()
 */
double QwtThermo::origin() const
{
    return d_data->origin;
}

/*!
  \brief Change the position of the scale
  \param scalePosition Position of the scale.

  \sa ScalePosition, scalePosition()
*/
void QwtThermo::setScalePosition( ScalePosition scalePosition )
{
    if ( d_data->scalePosition == scalePosition )
        return;

    d_data->scalePosition = scalePosition;

    if ( testAttribute( Qt::WA_WState_Polished ) )
        layoutThermo( true );
pixhawk's avatar
pixhawk committed
519 520
}

Bryant's avatar
Bryant committed
521 522 523 524 525
/*!
   \return Scale position.
   \sa setScalePosition()
*/
QwtThermo::ScalePosition QwtThermo::scalePosition() const
pixhawk's avatar
pixhawk committed
526
{
Bryant's avatar
Bryant committed
527
    return d_data->scalePosition;
pixhawk's avatar
pixhawk committed
528 529 530 531 532
}

//! Notify a scale change.
void QwtThermo::scaleChange()
{
Bryant's avatar
Bryant committed
533
    layoutThermo( true );
pixhawk's avatar
pixhawk committed
534 535
}

Bryant's avatar
Bryant committed
536 537 538 539 540 541 542
/*!
   Redraw the liquid in thermometer pipe.
   \param painter Painter
   \param pipeRect Bounding rectangle of the pipe without borders
*/
void QwtThermo::drawLiquid( 
    QPainter *painter, const QRect &pipeRect ) const
pixhawk's avatar
pixhawk committed
543
{
Bryant's avatar
Bryant committed
544 545 546
    painter->save();
    painter->setClipRect( pipeRect, Qt::IntersectClip );
    painter->setPen( Qt::NoPen );
pixhawk's avatar
pixhawk committed
547

Bryant's avatar
Bryant committed
548
    const QwtScaleMap scaleMap = scaleDraw()->scaleMap();
pixhawk's avatar
pixhawk committed
549

Bryant's avatar
Bryant committed
550
    QRect liquidRect = fillRect( pipeRect );
pixhawk's avatar
pixhawk committed
551

Bryant's avatar
Bryant committed
552 553 554
    if ( d_data->colorMap != NULL )
    {
        const QwtInterval interval = scaleDiv().interval().normalized();
555

Bryant's avatar
Bryant committed
556 557
        // Because the positions of the ticks are rounded
        // we calculate the colors for the rounded tick values
pixhawk's avatar
pixhawk committed
558

Bryant's avatar
Bryant committed
559
        QVector<double> values = qwtTickList( scaleDraw()->scaleDiv() );
560

Bryant's avatar
Bryant committed
561 562 563 564 565 566 567 568 569 570 571 572
        if ( scaleMap.isInverting() )
            qSort( values.begin(), values.end(), qGreater<double>() );
        else
            qSort( values.begin(), values.end(), qLess<double>() );

        int from;
        if ( !values.isEmpty() )
        {
            from = qRound( scaleMap.transform( values[0] ) );
            qwtDrawLine( painter, from,
                d_data->colorMap->color( interval, values[0] ),
                pipeRect, liquidRect, d_data->orientation );
pixhawk's avatar
pixhawk committed
573 574
        }

Bryant's avatar
Bryant committed
575 576 577 578 579 580 581 582 583 584 585
        for ( int i = 1; i < values.size(); i++ )
        {
            const int to = qRound( scaleMap.transform( values[i] ) );

            for ( int pos = from + 1; pos < to; pos++ )
            {
                const double v = scaleMap.invTransform( pos );

                qwtDrawLine( painter, pos, 
                    d_data->colorMap->color( interval, v ),
                    pipeRect, liquidRect, d_data->orientation );
pixhawk's avatar
pixhawk committed
586
            }
Bryant's avatar
Bryant committed
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603

            qwtDrawLine( painter, to,
                d_data->colorMap->color( interval, values[i] ),
                pipeRect, liquidRect, d_data->orientation );

            from = to;
        }
    }
    else
    {
        if ( !liquidRect.isEmpty() && d_data->alarmEnabled )
        {
            const QRect r = alarmRect( liquidRect );
            if ( !r.isEmpty() )
            {
                painter->fillRect( r, palette().brush( QPalette::Highlight ) );
                liquidRect = QRegion( liquidRect ).subtracted( r ).boundingRect();
pixhawk's avatar
pixhawk committed
604 605
            }
        }
Bryant's avatar
Bryant committed
606 607

        painter->fillRect( liquidRect, palette().brush( QPalette::ButtonText ) );
pixhawk's avatar
pixhawk committed
608 609
    }

Bryant's avatar
Bryant committed
610 611
    painter->restore();
}
pixhawk's avatar
pixhawk committed
612

Bryant's avatar
Bryant committed
613 614
/*!
  \brief Change the spacing between pipe and scale
pixhawk's avatar
pixhawk committed
615

Bryant's avatar
Bryant committed
616 617 618 619
  A spacing of 0 means, that the backbone of the scale is below
  the pipe.

  The default setting is 3 pixels.
pixhawk's avatar
pixhawk committed
620

Bryant's avatar
Bryant committed
621 622 623 624
  \param spacing Number of pixels
  \sa spacing();
*/
void QwtThermo::setSpacing( int spacing )
pixhawk's avatar
pixhawk committed
625
{
Bryant's avatar
Bryant committed
626 627 628 629 630 631 632
    if ( spacing <= 0 )
        spacing = 0;

    if ( spacing != d_data->spacing  )
    {
        d_data->spacing = spacing;
        layoutThermo( true );
pixhawk's avatar
pixhawk committed
633 634 635
    }
}

Bryant's avatar
Bryant committed
636 637 638 639 640
/*!
  \return Number of pixels between pipe and scale
  \sa setSpacing()
*/
int QwtThermo::spacing() const
pixhawk's avatar
pixhawk committed
641
{
Bryant's avatar
Bryant committed
642
    return d_data->spacing;
pixhawk's avatar
pixhawk committed
643 644 645
}

/*!
Bryant's avatar
Bryant committed
646 647 648
   Set the border width of the pipe.
   \param width Border width
   \sa borderWidth()
pixhawk's avatar
pixhawk committed
649
*/
Bryant's avatar
Bryant committed
650
void QwtThermo::setBorderWidth( int width )
pixhawk's avatar
pixhawk committed
651
{
Bryant's avatar
Bryant committed
652 653
    if ( width <= 0 )
        width = 0;
pixhawk's avatar
pixhawk committed
654

Bryant's avatar
Bryant committed
655 656 657 658 659
    if ( width != d_data->borderWidth  )
    {
        d_data->borderWidth = width;
        layoutThermo( true );
    }
pixhawk's avatar
pixhawk committed
660 661 662
}

/*!
Bryant's avatar
Bryant committed
663 664
   \return Border width of the thermometer pipe.
   \sa setBorderWidth()
pixhawk's avatar
pixhawk committed
665
*/
Bryant's avatar
Bryant committed
666
int QwtThermo::borderWidth() const
pixhawk's avatar
pixhawk committed
667
{
Bryant's avatar
Bryant committed
668
    return d_data->borderWidth;
pixhawk's avatar
pixhawk committed
669 670
}

Bryant's avatar
Bryant committed
671 672 673 674 675 676 677 678
/*!
  \brief Assign a color map for the fill color

  \param colorMap Color map
  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
void QwtThermo::setColorMap( QwtColorMap *colorMap )
pixhawk's avatar
pixhawk committed
679
{
Bryant's avatar
Bryant committed
680 681 682 683 684
    if ( colorMap != d_data->colorMap )
    {
        delete d_data->colorMap;
        d_data->colorMap = colorMap;
    }
pixhawk's avatar
pixhawk committed
685 686 687
}

/*!
Bryant's avatar
Bryant committed
688 689 690
  \return Color map for the fill color
  \warning The alarm threshold has no effect, when
           a color map has been assigned
pixhawk's avatar
pixhawk committed
691
*/
Bryant's avatar
Bryant committed
692
QwtColorMap *QwtThermo::colorMap()
pixhawk's avatar
pixhawk committed
693
{
Bryant's avatar
Bryant committed
694
    return d_data->colorMap;
pixhawk's avatar
pixhawk committed
695 696
}

Bryant's avatar
Bryant committed
697 698 699 700 701 702
/*!
  \return Color map for the fill color
  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
const QwtColorMap *QwtThermo::colorMap() const
pixhawk's avatar
pixhawk committed
703
{
Bryant's avatar
Bryant committed
704
    return d_data->colorMap;
pixhawk's avatar
pixhawk committed
705 706 707
}

/*!
Bryant's avatar
Bryant committed
708 709 710 711 712 713
  \brief Change the brush of the liquid.
 
  Changes the QPalette::ButtonText brush of the palette.

  \param brush New brush. 
  \sa fillBrush(), QWidget::setPalette()
pixhawk's avatar
pixhawk committed
714
*/
Bryant's avatar
Bryant committed
715
void QwtThermo::setFillBrush( const QBrush& brush )
pixhawk's avatar
pixhawk committed
716
{
Bryant's avatar
Bryant committed
717 718 719
    QPalette pal = palette();
    pal.setBrush( QPalette::ButtonText, brush );
    setPalette( pal );
pixhawk's avatar
pixhawk committed
720 721
}

Bryant's avatar
Bryant committed
722 723 724 725 726
/*!
  \return Liquid ( QPalette::ButtonText ) brush. 
  \sa setFillBrush(), QWidget::palette()
*/
QBrush QwtThermo::fillBrush() const
pixhawk's avatar
pixhawk committed
727
{
Bryant's avatar
Bryant committed
728
    return palette().brush( QPalette::ButtonText );
pixhawk's avatar
pixhawk committed
729 730 731
}

/*!
Bryant's avatar
Bryant committed
732 733 734 735 736 737 738 739 740
  \brief Specify the liquid brush above the alarm threshold

  Changes the QPalette::Highlight brush of the palette.

  \param brush New brush. 
  \sa alarmBrush(), QWidget::setPalette()

  \warning The alarm threshold has no effect, when
           a color map has been assigned
pixhawk's avatar
pixhawk committed
741
*/
Bryant's avatar
Bryant committed
742
void QwtThermo::setAlarmBrush( const QBrush& brush )
pixhawk's avatar
pixhawk committed
743
{
Bryant's avatar
Bryant committed
744 745 746
    QPalette pal = palette();
    pal.setBrush( QPalette::Highlight, brush );
    setPalette( pal );
pixhawk's avatar
pixhawk committed
747 748
}

Bryant's avatar
Bryant committed
749 750 751 752 753 754 755 756
/*!
  \return Liquid brush ( QPalette::Highlight ) above the alarm threshold.
  \sa setAlarmBrush(), QWidget::palette()

  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
QBrush QwtThermo::alarmBrush() const
pixhawk's avatar
pixhawk committed
757
{
Bryant's avatar
Bryant committed
758
    return palette().brush( QPalette::Highlight );
pixhawk's avatar
pixhawk committed
759 760
}

Bryant's avatar
Bryant committed
761 762 763 764 765 766 767 768 769 770
/*!
  Specify the alarm threshold.

  \param level Alarm threshold
  \sa alarmLevel()

  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
void QwtThermo::setAlarmLevel( double level )
pixhawk's avatar
pixhawk committed
771
{
Bryant's avatar
Bryant committed
772
    d_data->alarmLevel = level;
pixhawk's avatar
pixhawk committed
773 774 775 776
    d_data->alarmEnabled = 1;
    update();
}

Bryant's avatar
Bryant committed
777 778 779 780 781 782 783
/*!
  \return Alarm threshold.
  \sa setAlarmLevel()

  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
pixhawk's avatar
pixhawk committed
784 785 786 787 788
double QwtThermo::alarmLevel() const
{
    return d_data->alarmLevel;
}

Bryant's avatar
Bryant committed
789 790
/*!
  Change the width of the pipe.
pixhawk's avatar
pixhawk committed
791

Bryant's avatar
Bryant committed
792 793 794 795
  \param width Width of the pipe
  \sa pipeWidth()
*/
void QwtThermo::setPipeWidth( int width )
pixhawk's avatar
pixhawk committed
796
{
Bryant's avatar
Bryant committed
797 798 799 800 801
    if ( width > 0 )
    {
        d_data->pipeWidth = width;
        layoutThermo( true );
    }
pixhawk's avatar
pixhawk committed
802 803 804
}

/*!
Bryant's avatar
Bryant committed
805 806
  \return Width of the pipe.
  \sa setPipeWidth()
pixhawk's avatar
pixhawk committed
807
*/
Bryant's avatar
Bryant committed
808
int QwtThermo::pipeWidth() const
pixhawk's avatar
pixhawk committed
809
{
Bryant's avatar
Bryant committed
810
    return d_data->pipeWidth;
pixhawk's avatar
pixhawk committed
811 812 813 814
}

/*!
  \brief Enable or disable the alarm threshold
Bryant's avatar
Bryant committed
815 816 817 818
  \param on true (disabled) or false (enabled)

  \warning The alarm threshold has no effect, when
           a color map has been assigned
pixhawk's avatar
pixhawk committed
819
*/
Bryant's avatar
Bryant committed
820
void QwtThermo::setAlarmEnabled( bool on )
pixhawk's avatar
pixhawk committed
821
{
Bryant's avatar
Bryant committed
822
    d_data->alarmEnabled = on;
pixhawk's avatar
pixhawk committed
823 824 825
    update();
}

Bryant's avatar
Bryant committed
826 827 828 829 830 831
/*! 
  \return True, when the alarm threshold is enabled.

  \warning The alarm threshold has no effect, when
           a color map has been assigned
*/
pixhawk's avatar
pixhawk committed
832 833 834 835 836 837 838
bool QwtThermo::alarmEnabled() const
{
    return d_data->alarmEnabled;
}

/*!
  \return the minimum size hint
Bryant's avatar
Bryant committed
839
  \sa minimumSizeHint()
pixhawk's avatar
pixhawk committed
840 841 842 843 844 845 846
*/
QSize QwtThermo::sizeHint() const
{
    return minimumSizeHint();
}

/*!
Bryant's avatar
Bryant committed
847
  \return Minimum size hint
pixhawk's avatar
pixhawk committed
848
  \warning The return value depends on the font and the scale.
Bryant's avatar
Bryant committed
849
  \sa sizeHint()
pixhawk's avatar
pixhawk committed
850 851 852 853 854
*/
QSize QwtThermo::minimumSizeHint() const
{
    int w = 0, h = 0;

Bryant's avatar
Bryant committed
855 856 857 858
    if ( d_data->scalePosition != NoScale )
    {
        const int sdExtent = qCeil( scaleDraw()->extent( font() ) );
        const int sdLength = scaleDraw()->minLength( font() );
pixhawk's avatar
pixhawk committed
859 860

        w = sdLength;
Bryant's avatar
Bryant committed
861
        h = d_data->pipeWidth + sdExtent + d_data->spacing;
pixhawk's avatar
pixhawk committed
862

Bryant's avatar
Bryant committed
863 864 865
    }
    else // no scale
    {
pixhawk's avatar
pixhawk committed
866
        w = 200;
Bryant's avatar
Bryant committed
867
        h = d_data->pipeWidth;
pixhawk's avatar
pixhawk committed
868 869 870
    }

    if ( d_data->orientation == Qt::Vertical )
Bryant's avatar
Bryant committed
871
        qSwap( w, h );
pixhawk's avatar
pixhawk committed
872 873 874 875

    w += 2 * d_data->borderWidth;
    h += 2 * d_data->borderWidth;

Bryant's avatar
Bryant committed
876 877 878 879 880 881
    // finally add the margins
    int left, right, top, bottom;
    getContentsMargins( &left, &top, &right, &bottom );
    w += left + right;
    h += top + bottom;

pixhawk's avatar
pixhawk committed
882 883 884
    return QSize( w, h );
}

Bryant's avatar
Bryant committed
885 886 887 888 889 890 891 892 893
/*!
  \brief Calculate the filled rectangle of the pipe

  \param pipeRect Rectangle of the pipe
  \return Rectangle to be filled ( fill and alarm brush )

  \sa pipeRect(), alarmRect()
 */
QRect QwtThermo::fillRect( const QRect &pipeRect ) const
pixhawk's avatar
pixhawk committed
894
{
Bryant's avatar
Bryant committed
895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
    double origin;        
    if ( d_data->originMode == OriginMinimum )
    {
        origin = qMin( lowerBound(), upperBound() );
    }
    else if ( d_data->originMode == OriginMaximum )
    {
        origin = qMax( lowerBound(), upperBound() );
    }
    else // OriginCustom
    {
        origin = d_data->origin;
    }

    const QwtScaleMap scaleMap = scaleDraw()->scaleMap();

    int from = qRound( scaleMap.transform( d_data->value ) );
    int to = qRound( scaleMap.transform( origin ) );
pixhawk's avatar
pixhawk committed
913

Bryant's avatar
Bryant committed
914 915 916 917 918 919 920 921 922 923 924 925 926 927
    if ( to < from )
        qSwap( from, to );
    
    QRect fillRect = pipeRect;
    if ( d_data->orientation == Qt::Horizontal )
    {
        fillRect.setLeft( from );
        fillRect.setRight( to );
    }
    else // Qt::Vertical
    {
        fillRect.setTop( from );
        fillRect.setBottom( to );
    }
pixhawk's avatar
pixhawk committed
928

Bryant's avatar
Bryant committed
929
    return fillRect.normalized();
pixhawk's avatar
pixhawk committed
930
}
Bryant's avatar
Bryant committed
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004

/*!
  \brief Calculate the alarm rectangle of the pipe

  \param fillRect Filled rectangle in the pipe
  \return Rectangle to be filled with the alarm brush

  \sa pipeRect(), fillRect(), alarmLevel(), alarmBrush()
 */
QRect QwtThermo::alarmRect( const QRect &fillRect ) const
{
    QRect alarmRect( 0, 0, -1, -1); // something invalid

    if ( !d_data->alarmEnabled )
        return alarmRect;

    const bool inverted = ( upperBound() < lowerBound() );
    
    bool increasing;
    if ( d_data->originMode == OriginCustom )
    {
        increasing = d_data->value > d_data->origin;
    }
    else
    {
        increasing = d_data->originMode == OriginMinimum;
    }

    const QwtScaleMap map = scaleDraw()->scaleMap();
    const int alarmPos = qRound( map.transform( d_data->alarmLevel ) );
    const int valuePos = qRound( map.transform( d_data->value ) );
    
    if ( d_data->orientation == Qt::Horizontal )
    {
        int v1, v2;
        if ( inverted )
        {
            v1 = fillRect.left();

            v2 = alarmPos - 1;
            v2 = qMin( v2, increasing ? fillRect.right() : valuePos );
        }
        else
        {
            v1 = alarmPos + 1;
            v1 = qMax( v1, increasing ? fillRect.left() : valuePos );

            v2 = fillRect.right();

        }
        alarmRect.setRect( v1, fillRect.top(), v2 - v1 + 1, fillRect.height() );
    }
    else
    {
        int v1, v2;
        if ( inverted )
        {
            v1 = alarmPos + 1;
            v1 = qMax( v1, increasing ? fillRect.top() : valuePos );

            v2 = fillRect.bottom();
        }
        else
        {
            v1 = fillRect.top();

            v2 = alarmPos - 1;
            v2 = qMin( v2, increasing ? fillRect.bottom() : valuePos );
        }
        alarmRect.setRect( fillRect.left(), v1, fillRect.width(), v2 - v1 + 1 );
    }

    return alarmRect;
}