You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1004 lines
22 KiB
1004 lines
22 KiB
/* -*- 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_thermo.h" |
|
#include "qwt_scale_engine.h" |
|
#include "qwt_scale_draw.h" |
|
#include "qwt_scale_map.h" |
|
#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; |
|
} |
|
|
|
class QwtThermo::PrivateData |
|
{ |
|
public: |
|
PrivateData(): |
|
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; |
|
} |
|
|
|
Qt::Orientation orientation; |
|
QwtThermo::ScalePosition scalePosition; |
|
|
|
int spacing; |
|
int borderWidth; |
|
int pipeWidth; |
|
|
|
QwtInterval::BorderFlags rangeFlags; |
|
double alarmLevel; |
|
bool alarmEnabled; |
|
bool autoFillPipe; |
|
QwtThermo::OriginMode originMode; |
|
double origin; |
|
|
|
QwtColorMap *colorMap; |
|
|
|
double value; |
|
}; |
|
|
|
/*! |
|
Constructor |
|
\param parent Parent widget |
|
*/ |
|
QwtThermo::QwtThermo( QWidget *parent ): |
|
QwtAbstractScale( parent ) |
|
{ |
|
d_data = new PrivateData; |
|
|
|
QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); |
|
if ( d_data->orientation == Qt::Vertical ) |
|
policy.transpose(); |
|
|
|
setSizePolicy( policy ); |
|
|
|
setAttribute( Qt::WA_WState_OwnSizePolicy, false ); |
|
layoutThermo( true ); |
|
} |
|
|
|
//! Destructor |
|
QwtThermo::~QwtThermo() |
|
{ |
|
delete d_data; |
|
} |
|
|
|
/*! |
|
\brief Exclude/Include min/max values |
|
|
|
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(). |
|
|
|
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 ) |
|
{ |
|
if ( d_data->rangeFlags != flags ) |
|
{ |
|
d_data->rangeFlags = flags; |
|
update(); |
|
} |
|
} |
|
|
|
/*! |
|
\return Range flags |
|
\sa setRangeFlags() |
|
*/ |
|
QwtInterval::BorderFlags QwtThermo::rangeFlags() const |
|
{ |
|
return d_data->rangeFlags; |
|
} |
|
|
|
/*! |
|
Set the current value. |
|
|
|
\param value New Value |
|
\sa value() |
|
*/ |
|
void QwtThermo::setValue( double value ) |
|
{ |
|
if ( d_data->value != value ) |
|
{ |
|
d_data->value = value; |
|
update(); |
|
} |
|
} |
|
|
|
//! Return the value. |
|
double QwtThermo::value() const |
|
{ |
|
return d_data->value; |
|
} |
|
|
|
/*! |
|
\brief Set a scale draw |
|
|
|
For changing the labels of the scales, it |
|
is necessary to derive from QwtScaleDraw and |
|
overload QwtScaleDraw::label(). |
|
|
|
\param scaleDraw ScaleDraw object, that has to be created with |
|
new and will be deleted in ~QwtThermo() or the next |
|
call of setScaleDraw(). |
|
*/ |
|
void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw ) |
|
{ |
|
setAbstractScaleDraw( scaleDraw ); |
|
} |
|
|
|
/*! |
|
\return the scale draw of the thermo |
|
\sa setScaleDraw() |
|
*/ |
|
const QwtScaleDraw *QwtThermo::scaleDraw() const |
|
{ |
|
return static_cast<const QwtScaleDraw *>( abstractScaleDraw() ); |
|
} |
|
|
|
/*! |
|
\return the scale draw of the thermo |
|
\sa setScaleDraw() |
|
*/ |
|
QwtScaleDraw *QwtThermo::scaleDraw() |
|
{ |
|
return static_cast<QwtScaleDraw *>( abstractScaleDraw() ); |
|
} |
|
|
|
/*! |
|
Paint event handler |
|
\param event Paint event |
|
*/ |
|
void QwtThermo::paintEvent( QPaintEvent *event ) |
|
{ |
|
QPainter painter( this ); |
|
painter.setClipRegion( event->region() ); |
|
|
|
QStyleOption opt; |
|
opt.init(this); |
|
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); |
|
|
|
const QRect tRect = pipeRect(); |
|
|
|
if ( !tRect.contains( event->rect() ) ) |
|
{ |
|
if ( d_data->scalePosition != QwtThermo::NoScale ) |
|
scaleDraw()->draw( &painter, palette() ); |
|
} |
|
|
|
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 ); |
|
} |
|
|
|
/*! |
|
Resize event handler |
|
\param event Resize event |
|
*/ |
|
void QwtThermo::resizeEvent( QResizeEvent *event ) |
|
{ |
|
Q_UNUSED( event ); |
|
layoutThermo( false ); |
|
} |
|
|
|
/*! |
|
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; |
|
} |
|
} |
|
|
|
/*! |
|
Recalculate the QwtThermo geometry and layout based on |
|
pipeRect() and the fonts. |
|
|
|
\param update_geometry notify the layout system and call update |
|
to redraw the scale |
|
*/ |
|
void QwtThermo::layoutThermo( bool update_geometry ) |
|
{ |
|
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++; |
|
} |
|
|
|
if ( d_data->scalePosition == QwtThermo::TrailingScale ) |
|
{ |
|
scaleDraw()->setAlignment( QwtScaleDraw::TopScale ); |
|
scaleDraw()->move( from, tRect.top() - bw ); |
|
} |
|
else |
|
{ |
|
scaleDraw()->setAlignment( QwtScaleDraw::BottomScale ); |
|
scaleDraw()->move( from, tRect.bottom() + bw ); |
|
} |
|
|
|
scaleDraw()->setLength( to - from ); |
|
} |
|
else // Qt::Vertical |
|
{ |
|
from = tRect.top(); |
|
to = tRect.bottom(); |
|
|
|
if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum ) |
|
{ |
|
if ( inverted ) |
|
from--; |
|
else |
|
to++; |
|
} |
|
if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum ) |
|
{ |
|
if ( inverted ) |
|
to++; |
|
else |
|
from--; |
|
} |
|
|
|
if ( d_data->scalePosition == QwtThermo::LeadingScale ) |
|
{ |
|
scaleDraw()->setAlignment( QwtScaleDraw::RightScale ); |
|
scaleDraw()->move( tRect.right() + bw, from ); |
|
} |
|
else |
|
{ |
|
scaleDraw()->setAlignment( QwtScaleDraw::LeftScale ); |
|
scaleDraw()->move( tRect.left() - bw, from ); |
|
} |
|
|
|
scaleDraw()->setLength( to - from ); |
|
} |
|
|
|
if ( update_geometry ) |
|
{ |
|
updateGeometry(); |
|
update(); |
|
} |
|
} |
|
|
|
/*! |
|
\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; |
|
|
|
const QRect cr = contentsRect(); |
|
|
|
QRect pipeRect = cr; |
|
if ( d_data->orientation == Qt::Horizontal ) |
|
{ |
|
pipeRect.adjust( scaleOff, 0, -scaleOff, 0 ); |
|
|
|
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() |
|
*/ |
|
void QwtThermo::setOrientation( Qt::Orientation orientation ) |
|
{ |
|
if ( orientation == d_data->orientation ) |
|
return; |
|
|
|
d_data->orientation = orientation; |
|
|
|
if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) ) |
|
{ |
|
QSizePolicy sp = sizePolicy(); |
|
sp.transpose(); |
|
setSizePolicy( sp ); |
|
|
|
setAttribute( Qt::WA_WState_OwnSizePolicy, false ); |
|
} |
|
|
|
layoutThermo( true ); |
|
} |
|
|
|
/*! |
|
\return Orientation |
|
\sa setOrientation() |
|
*/ |
|
Qt::Orientation QwtThermo::orientation() const |
|
{ |
|
return d_data->orientation; |
|
} |
|
|
|
/*! |
|
\brief Change how the origin is determined. |
|
\sa originMode(), serOrigin(), origin() |
|
*/ |
|
void QwtThermo::setOriginMode( OriginMode m ) |
|
{ |
|
if ( m == d_data->originMode ) |
|
return; |
|
|
|
d_data->originMode = m; |
|
update(); |
|
} |
|
|
|
/*! |
|
\return Mode, how the origin is determined. |
|
\sa setOriginMode(), serOrigin(), origin() |
|
*/ |
|
QwtThermo::OriginMode QwtThermo::originMode() const |
|
{ |
|
return d_data->originMode; |
|
} |
|
|
|
/*! |
|
\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 ) |
|
{ |
|
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 ); |
|
} |
|
|
|
/*! |
|
\return Scale position. |
|
\sa setScalePosition() |
|
*/ |
|
QwtThermo::ScalePosition QwtThermo::scalePosition() const |
|
{ |
|
return d_data->scalePosition; |
|
} |
|
|
|
//! Notify a scale change. |
|
void QwtThermo::scaleChange() |
|
{ |
|
layoutThermo( true ); |
|
} |
|
|
|
/*! |
|
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 |
|
{ |
|
painter->save(); |
|
painter->setClipRect( pipeRect, Qt::IntersectClip ); |
|
painter->setPen( Qt::NoPen ); |
|
|
|
const QwtScaleMap scaleMap = scaleDraw()->scaleMap(); |
|
|
|
QRect liquidRect = fillRect( pipeRect ); |
|
|
|
if ( d_data->colorMap != NULL ) |
|
{ |
|
const QwtInterval interval = scaleDiv().interval().normalized(); |
|
|
|
// Because the positions of the ticks are rounded |
|
// we calculate the colors for the rounded tick values |
|
|
|
QVector<double> values = qwtTickList( scaleDraw()->scaleDiv() ); |
|
|
|
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 ); |
|
} |
|
|
|
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 ); |
|
} |
|
|
|
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(); |
|
} |
|
} |
|
|
|
painter->fillRect( liquidRect, palette().brush( QPalette::ButtonText ) ); |
|
} |
|
|
|
painter->restore(); |
|
} |
|
|
|
/*! |
|
\brief Change the spacing between pipe and scale |
|
|
|
A spacing of 0 means, that the backbone of the scale is below |
|
the pipe. |
|
|
|
The default setting is 3 pixels. |
|
|
|
\param spacing Number of pixels |
|
\sa spacing(); |
|
*/ |
|
void QwtThermo::setSpacing( int spacing ) |
|
{ |
|
if ( spacing <= 0 ) |
|
spacing = 0; |
|
|
|
if ( spacing != d_data->spacing ) |
|
{ |
|
d_data->spacing = spacing; |
|
layoutThermo( true ); |
|
} |
|
} |
|
|
|
/*! |
|
\return Number of pixels between pipe and scale |
|
\sa setSpacing() |
|
*/ |
|
int QwtThermo::spacing() const |
|
{ |
|
return d_data->spacing; |
|
} |
|
|
|
/*! |
|
Set the border width of the pipe. |
|
\param width Border width |
|
\sa borderWidth() |
|
*/ |
|
void QwtThermo::setBorderWidth( int width ) |
|
{ |
|
if ( width <= 0 ) |
|
width = 0; |
|
|
|
if ( width != d_data->borderWidth ) |
|
{ |
|
d_data->borderWidth = width; |
|
layoutThermo( true ); |
|
} |
|
} |
|
|
|
/*! |
|
\return Border width of the thermometer pipe. |
|
\sa setBorderWidth() |
|
*/ |
|
int QwtThermo::borderWidth() const |
|
{ |
|
return d_data->borderWidth; |
|
} |
|
|
|
/*! |
|
\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 ) |
|
{ |
|
if ( colorMap != d_data->colorMap ) |
|
{ |
|
delete d_data->colorMap; |
|
d_data->colorMap = colorMap; |
|
} |
|
} |
|
|
|
/*! |
|
\return Color map for the fill color |
|
\warning The alarm threshold has no effect, when |
|
a color map has been assigned |
|
*/ |
|
QwtColorMap *QwtThermo::colorMap() |
|
{ |
|
return d_data->colorMap; |
|
} |
|
|
|
/*! |
|
\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 |
|
{ |
|
return d_data->colorMap; |
|
} |
|
|
|
/*! |
|
\brief Change the brush of the liquid. |
|
|
|
Changes the QPalette::ButtonText brush of the palette. |
|
|
|
\param brush New brush. |
|
\sa fillBrush(), QWidget::setPalette() |
|
*/ |
|
void QwtThermo::setFillBrush( const QBrush& brush ) |
|
{ |
|
QPalette pal = palette(); |
|
pal.setBrush( QPalette::ButtonText, brush ); |
|
setPalette( pal ); |
|
} |
|
|
|
/*! |
|
\return Liquid ( QPalette::ButtonText ) brush. |
|
\sa setFillBrush(), QWidget::palette() |
|
*/ |
|
QBrush QwtThermo::fillBrush() const |
|
{ |
|
return palette().brush( QPalette::ButtonText ); |
|
} |
|
|
|
/*! |
|
\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 |
|
*/ |
|
void QwtThermo::setAlarmBrush( const QBrush& brush ) |
|
{ |
|
QPalette pal = palette(); |
|
pal.setBrush( QPalette::Highlight, brush ); |
|
setPalette( pal ); |
|
} |
|
|
|
/*! |
|
\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 |
|
{ |
|
return palette().brush( QPalette::Highlight ); |
|
} |
|
|
|
/*! |
|
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 ) |
|
{ |
|
d_data->alarmLevel = level; |
|
d_data->alarmEnabled = 1; |
|
update(); |
|
} |
|
|
|
/*! |
|
\return Alarm threshold. |
|
\sa setAlarmLevel() |
|
|
|
\warning The alarm threshold has no effect, when |
|
a color map has been assigned |
|
*/ |
|
double QwtThermo::alarmLevel() const |
|
{ |
|
return d_data->alarmLevel; |
|
} |
|
|
|
/*! |
|
Change the width of the pipe. |
|
|
|
\param width Width of the pipe |
|
\sa pipeWidth() |
|
*/ |
|
void QwtThermo::setPipeWidth( int width ) |
|
{ |
|
if ( width > 0 ) |
|
{ |
|
d_data->pipeWidth = width; |
|
layoutThermo( true ); |
|
} |
|
} |
|
|
|
/*! |
|
\return Width of the pipe. |
|
\sa setPipeWidth() |
|
*/ |
|
int QwtThermo::pipeWidth() const |
|
{ |
|
return d_data->pipeWidth; |
|
} |
|
|
|
/*! |
|
\brief Enable or disable the alarm threshold |
|
\param on true (disabled) or false (enabled) |
|
|
|
\warning The alarm threshold has no effect, when |
|
a color map has been assigned |
|
*/ |
|
void QwtThermo::setAlarmEnabled( bool on ) |
|
{ |
|
d_data->alarmEnabled = on; |
|
update(); |
|
} |
|
|
|
/*! |
|
\return True, when the alarm threshold is enabled. |
|
|
|
\warning The alarm threshold has no effect, when |
|
a color map has been assigned |
|
*/ |
|
bool QwtThermo::alarmEnabled() const |
|
{ |
|
return d_data->alarmEnabled; |
|
} |
|
|
|
/*! |
|
\return the minimum size hint |
|
\sa minimumSizeHint() |
|
*/ |
|
QSize QwtThermo::sizeHint() const |
|
{ |
|
return minimumSizeHint(); |
|
} |
|
|
|
/*! |
|
\return Minimum size hint |
|
\warning The return value depends on the font and the scale. |
|
\sa sizeHint() |
|
*/ |
|
QSize QwtThermo::minimumSizeHint() const |
|
{ |
|
int w = 0, h = 0; |
|
|
|
if ( d_data->scalePosition != NoScale ) |
|
{ |
|
const int sdExtent = qCeil( scaleDraw()->extent( font() ) ); |
|
const int sdLength = scaleDraw()->minLength( font() ); |
|
|
|
w = sdLength; |
|
h = d_data->pipeWidth + sdExtent + d_data->spacing; |
|
|
|
} |
|
else // no scale |
|
{ |
|
w = 200; |
|
h = d_data->pipeWidth; |
|
} |
|
|
|
if ( d_data->orientation == Qt::Vertical ) |
|
qSwap( w, h ); |
|
|
|
w += 2 * d_data->borderWidth; |
|
h += 2 * d_data->borderWidth; |
|
|
|
// finally add the margins |
|
int left, right, top, bottom; |
|
getContentsMargins( &left, &top, &right, &bottom ); |
|
w += left + right; |
|
h += top + bottom; |
|
|
|
return QSize( w, h ); |
|
} |
|
|
|
/*! |
|
\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 |
|
{ |
|
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 ) ); |
|
|
|
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 ); |
|
} |
|
|
|
return fillRect.normalized(); |
|
} |
|
|
|
/*! |
|
\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; |
|
}
|
|
|