1
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3
* Copyright (C) 1997 Josef Wilgen
4
* Copyright (C) 2002 Uwe Rathmann
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the Qwt License, Version 1.0
8
*****************************************************************************/
14
#include <qdrawutil.h>
16
#include "qwt_scale_engine.h"
17
#include "qwt_scale_draw.h"
18
#include "qwt_scale_map.h"
19
#include "qwt_paint_buffer.h"
20
#include "qwt_thermo.h"
22
class QwtThermo::PrivateData
27
alarmBrush(Qt::white),
28
orientation(Qt::Vertical),
29
scalePos(QwtThermo::LeftScale),
39
map.setScaleInterval(minValue, maxValue);
47
Qt::Orientation orientation;
62
\param parent Parent widget
64
QwtThermo::QwtThermo(QWidget *parent):
70
#if QT_VERSION < 0x040000
73
\param parent Parent widget
74
\param name Object name
76
QwtThermo::QwtThermo(QWidget *parent, const char *name):
83
void QwtThermo::initThermo()
85
#if QT_VERSION < 0x040000
86
setWFlags(Qt::WNoAutoErase);
88
d_data = new PrivateData;
89
setRange(d_data->minValue, d_data->maxValue, false);
91
QSizePolicy policy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
92
if (d_data->orientation == Qt::Vertical)
95
setSizePolicy(policy);
97
#if QT_VERSION >= 0x040000
98
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
100
clearWState( WState_OwnSizePolicy );
105
QwtThermo::~QwtThermo()
110
//! Set the maximum value.
111
void QwtThermo::setMaxValue(double v)
113
setRange(d_data->minValue, v);
116
//! Return the maximum value.
117
double QwtThermo::maxValue() const
119
return d_data->maxValue;
122
//! Set the minimum value.
123
void QwtThermo::setMinValue(double v)
125
setRange(v, d_data->maxValue);
128
//! Return the minimum value.
129
double QwtThermo::minValue() const
131
return d_data->minValue;
134
//! Set the current value.
135
void QwtThermo::setValue(double v)
137
if (d_data->value != v)
144
//! Return the value.
145
double QwtThermo::value() const
147
return d_data->value;
151
\brief Set a scale draw
153
For changing the labels of the scales, it
154
is necessary to derive from QwtScaleDraw and
155
overload QwtScaleDraw::label().
157
\param scaleDraw ScaleDraw object, that has to be created with
158
new and will be deleted in ~QwtThermo or the next
159
call of setScaleDraw().
161
void QwtThermo::setScaleDraw(QwtScaleDraw *scaleDraw)
163
setAbstractScaleDraw(scaleDraw);
167
\return the scale draw of the thermo
170
const QwtScaleDraw *QwtThermo::scaleDraw() const
172
return (QwtScaleDraw *)abstractScaleDraw();
176
\return the scale draw of the thermo
179
QwtScaleDraw *QwtThermo::scaleDraw()
181
return (QwtScaleDraw *)abstractScaleDraw();
185
void QwtThermo::paintEvent(QPaintEvent *e)
187
// Use double-buffering
188
const QRect &ur = e->rect();
191
#if QT_VERSION < 0x040000
192
QwtPaintBuffer paintBuffer(this, ur);
193
draw(paintBuffer.painter(), ur);
195
QPainter painter(this);
201
//! Draw the whole QwtThermo.
202
void QwtThermo::draw(QPainter *p, const QRect& ur)
204
if ( !d_data->thermoRect.contains(ur) )
206
if (d_data->scalePos != NoScale)
208
#if QT_VERSION < 0x040000
209
scaleDraw()->draw(p, colorGroup());
211
scaleDraw()->draw(p, palette());
216
d_data->thermoRect.x() - d_data->borderWidth,
217
d_data->thermoRect.y() - d_data->borderWidth,
218
d_data->thermoRect.width() + 2*d_data->borderWidth,
219
d_data->thermoRect.height() + 2*d_data->borderWidth,
220
#if QT_VERSION < 0x040000
225
true, d_data->borderWidth,0);
230
//! Qt resize event handler
231
void QwtThermo::resizeEvent(QResizeEvent *)
233
layoutThermo( false );
237
Recalculate the QwtThermo geometry and layout based on
238
the QwtThermo::rect() and the fonts.
239
\param update_geometry notify the layout system and call update
242
void QwtThermo::layoutThermo( bool update_geometry )
246
if ( d_data->scalePos != NoScale )
249
scaleDraw()->getBorderDistHint(font(), d1, d2);
250
mbd = qwtMax(d1, d2);
253
if ( d_data->orientation == Qt::Horizontal )
255
switch ( d_data->scalePos )
259
d_data->thermoRect.setRect(
260
r.x() + mbd + d_data->borderWidth,
262
- d_data->thermoWidth - 2*d_data->borderWidth,
263
r.width() - 2*(d_data->borderWidth + mbd),
264
d_data->thermoWidth);
265
scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
266
scaleDraw()->move( d_data->thermoRect.x(),
267
d_data->thermoRect.y() - d_data->borderWidth
268
- d_data->scaleDist);
269
scaleDraw()->setLength(d_data->thermoRect.width());
274
case NoScale: // like Bottom but without scale
275
default: // inconsistent orientation and scale position
276
// Mapping between values and pixels requires
277
// initialization of the scale geometry
279
d_data->thermoRect.setRect(
280
r.x() + mbd + d_data->borderWidth,
281
r.y() + d_data->borderWidth,
282
r.width() - 2*(d_data->borderWidth + mbd),
283
d_data->thermoWidth);
284
scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
286
d_data->thermoRect.x(),
287
d_data->thermoRect.y() + d_data->thermoRect.height()
288
+ d_data->borderWidth + d_data->scaleDist );
289
scaleDraw()->setLength(d_data->thermoRect.width());
293
d_data->map.setPaintInterval(d_data->thermoRect.x(),
294
d_data->thermoRect.x() + d_data->thermoRect.width() - 1);
298
switch ( d_data->scalePos )
302
d_data->thermoRect.setRect(
303
r.x() + d_data->borderWidth,
304
r.y() + mbd + d_data->borderWidth,
306
r.height() - 2*(d_data->borderWidth + mbd));
307
scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
309
d_data->thermoRect.x() + d_data->thermoRect.width()
310
+ d_data->borderWidth + d_data->scaleDist,
311
d_data->thermoRect.y());
312
scaleDraw()->setLength(d_data->thermoRect.height());
317
case NoScale: // like Left but without scale
318
default: // inconsistent orientation and scale position
319
// Mapping between values and pixels requires
320
// initialization of the scale geometry
322
d_data->thermoRect.setRect(
323
r.x() + r.width() - 2*d_data->borderWidth - d_data->thermoWidth,
324
r.y() + mbd + d_data->borderWidth,
326
r.height() - 2*(d_data->borderWidth + mbd));
327
scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
329
d_data->thermoRect.x() - d_data->scaleDist
330
- d_data->borderWidth,
331
d_data->thermoRect.y() );
332
scaleDraw()->setLength(d_data->thermoRect.height());
336
d_data->map.setPaintInterval(
337
d_data->thermoRect.y() + d_data->thermoRect.height() - 1,
338
d_data->thermoRect.y());
340
if ( update_geometry )
348
\brief Set the thermometer orientation and the scale position.
350
The scale position NoScale disables the scale.
351
\param o orientation. Possible values are Qt::Horizontal and Qt::Vertical.
352
The default value is Qt::Vertical.
353
\param s Position of the scale.
354
The default value is NoScale.
356
A valid combination of scale position and orientation is enforced:
357
- a horizontal thermometer can have the scale positions TopScale,
358
BottomScale or NoScale;
359
- a vertical thermometer can have the scale positions LeftScale,
360
RightScale or NoScale;
361
- an invalid scale position will default to NoScale.
363
\sa QwtThermo::setScalePosition()
365
void QwtThermo::setOrientation(Qt::Orientation o, ScalePos s)
367
if ( o == d_data->orientation && s == d_data->scalePos )
374
if ((s == NoScale) || (s == BottomScale) || (s == TopScale))
375
d_data->scalePos = s;
377
d_data->scalePos = NoScale;
382
if ((s == NoScale) || (s == LeftScale) || (s == RightScale))
383
d_data->scalePos = s;
385
d_data->scalePos = NoScale;
390
if ( o != d_data->orientation )
392
#if QT_VERSION >= 0x040000
393
if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
395
if ( !testWState( WState_OwnSizePolicy ) )
398
QSizePolicy sp = sizePolicy();
402
#if QT_VERSION >= 0x040000
403
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
405
clearWState( WState_OwnSizePolicy );
410
d_data->orientation = o;
415
\brief Change the scale position (and thermometer orientation).
417
\param s Position of the scale.
419
A valid combination of scale position and orientation is enforced:
420
- if the new scale position is LeftScale or RightScale, the
421
scale orientation will become Qt::Vertical;
422
- if the new scale position is BottomScale or TopScale, the scale
423
orientation will become Qt::Horizontal;
424
- if the new scale position is NoScale, the scale orientation will not change.
426
\sa QwtThermo::setOrientation()
428
void QwtThermo::setScalePosition(ScalePos s)
430
if ((s == BottomScale) || (s == TopScale))
431
setOrientation(Qt::Horizontal, s);
432
else if ((s == LeftScale) || (s == RightScale))
433
setOrientation(Qt::Vertical, s);
435
setOrientation(d_data->orientation, NoScale);
438
//! Return the scale position.
439
QwtThermo::ScalePos QwtThermo::scalePosition() const
441
return d_data->scalePos;
444
//! Notify a font change.
445
void QwtThermo::fontChange(const QFont &f)
447
QWidget::fontChange( f );
451
//! Notify a scale change.
452
void QwtThermo::scaleChange()
458
//! Redraw the liquid in thermometer pipe.
459
void QwtThermo::drawThermo(QPainter *p)
461
int alarm = 0, taval = 0;
467
int inverted = ( d_data->maxValue < d_data->minValue );
470
// Determine if value exceeds alarm threshold.
471
// Note: The alarm value is allowed to lie
472
// outside the interval (minValue, maxValue).
474
if (d_data->alarmEnabled)
478
alarm = ((d_data->alarmLevel >= d_data->maxValue)
479
&& (d_data->alarmLevel <= d_data->minValue)
480
&& (d_data->value >= d_data->alarmLevel));
485
alarm = (( d_data->alarmLevel >= d_data->minValue)
486
&& (d_data->alarmLevel <= d_data->maxValue)
487
&& (d_data->value >= d_data->alarmLevel));
494
int tval = transform(d_data->value);
497
taval = transform(d_data->alarmLevel);
500
// calculate recangles
502
if ( d_data->orientation == Qt::Horizontal )
506
bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
507
tval - d_data->thermoRect.x(),
508
d_data->thermoRect.height());
512
aRect.setRect(tval, d_data->thermoRect.y(),
514
d_data->thermoRect.height());
515
fRect.setRect(taval + 1, d_data->thermoRect.y(),
516
d_data->thermoRect.x() + d_data->thermoRect.width() - (taval + 1),
517
d_data->thermoRect.height());
521
fRect.setRect(tval, d_data->thermoRect.y(),
522
d_data->thermoRect.x() + d_data->thermoRect.width() - tval,
523
d_data->thermoRect.height());
528
bRect.setRect(tval + 1, d_data->thermoRect.y(),
529
d_data->thermoRect.width() - (tval + 1 - d_data->thermoRect.x()),
530
d_data->thermoRect.height());
534
aRect.setRect(taval, d_data->thermoRect.y(),
536
d_data->thermoRect.height());
537
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
538
taval - d_data->thermoRect.x(),
539
d_data->thermoRect.height());
543
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
544
tval - d_data->thermoRect.x() + 1,
545
d_data->thermoRect.height());
552
if (tval < d_data->thermoRect.y())
553
tval = d_data->thermoRect.y();
556
if (tval > d_data->thermoRect.y() + d_data->thermoRect.height())
557
tval = d_data->thermoRect.y() + d_data->thermoRect.height();
562
bRect.setRect(d_data->thermoRect.x(), tval + 1,
563
d_data->thermoRect.width(),
564
d_data->thermoRect.height() - (tval + 1 - d_data->thermoRect.y()));
568
aRect.setRect(d_data->thermoRect.x(), taval,
569
d_data->thermoRect.width(),
571
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
572
d_data->thermoRect.width(),
573
taval - d_data->thermoRect.y());
577
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
578
d_data->thermoRect.width(),
579
tval - d_data->thermoRect.y() + 1);
584
bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
585
d_data->thermoRect.width(),
586
tval - d_data->thermoRect.y());
589
aRect.setRect(d_data->thermoRect.x(),tval,
590
d_data->thermoRect.width(),
592
fRect.setRect(d_data->thermoRect.x(),taval + 1,
593
d_data->thermoRect.width(),
594
d_data->thermoRect.y() + d_data->thermoRect.height() - (taval + 1));
598
fRect.setRect(d_data->thermoRect.x(),tval,
599
d_data->thermoRect.width(),
600
d_data->thermoRect.y() + d_data->thermoRect.height() - tval);
608
const QColor bgColor =
609
#if QT_VERSION < 0x040000
610
colorGroup().color(QColorGroup::Background);
612
palette().color(QPalette::Background);
614
p->fillRect(bRect, bgColor);
617
p->fillRect(aRect, d_data->alarmBrush);
619
p->fillRect(fRect, d_data->fillBrush);
622
//! Set the border width of the pipe.
623
void QwtThermo::setBorderWidth(int w)
625
if ((w >= 0) && (w < (qwtMin(d_data->thermoRect.width(),
626
d_data->thermoRect.height()) + d_data->borderWidth) / 2 - 1))
628
d_data->borderWidth = w;
633
//! Return the border width of the thermometer pipe.
634
int QwtThermo::borderWidth() const
636
return d_data->borderWidth;
641
\param vmin value corresponding lower or left end of the thermometer
642
\param vmax value corresponding to the upper or right end of the thermometer
643
\param logarithmic logarithmic mapping, true or false
645
void QwtThermo::setRange(double vmin, double vmax, bool logarithmic)
647
d_data->minValue = vmin;
648
d_data->maxValue = vmax;
651
setScaleEngine(new QwtLog10ScaleEngine);
653
setScaleEngine(new QwtLinearScaleEngine);
656
There are two different maps, one for the scale, the other
657
for the values. This is confusing and will be changed
658
in the future. TODO ...
661
d_data->map.setTransformation(scaleEngine()->transformation());
662
d_data->map.setScaleInterval(d_data->minValue, d_data->maxValue);
665
rescale(d_data->minValue, d_data->maxValue);
671
\brief Change the brush of the liquid.
672
\param brush New brush. The default brush is solid black.
674
void QwtThermo::setFillBrush(const QBrush& brush)
676
d_data->fillBrush = brush;
680
//! Return the liquid brush.
681
const QBrush& QwtThermo::fillBrush() const
683
return d_data->fillBrush;
687
\brief Change the color of the liquid.
688
\param c New color. The default color is black.
690
void QwtThermo::setFillColor(const QColor &c)
692
d_data->fillBrush.setColor(c);
696
//! Return the liquid color.
697
const QColor &QwtThermo::fillColor() const
699
return d_data->fillBrush.color();
703
\brief Specify the liquid brush above the alarm threshold
704
\param brush New brush. The default is solid white.
706
void QwtThermo::setAlarmBrush(const QBrush& brush)
708
d_data->alarmBrush = brush;
712
//! Return the liquid brush above the alarm threshold.
713
const QBrush& QwtThermo::alarmBrush() const
715
return d_data->alarmBrush;
719
\brief Specify the liquid color above the alarm threshold
720
\param c New color. The default is white.
722
void QwtThermo::setAlarmColor(const QColor &c)
724
d_data->alarmBrush.setColor(c);
728
//! Return the liquid color above the alarm threshold.
729
const QColor &QwtThermo::alarmColor() const
731
return d_data->alarmBrush.color();
734
//! Specify the alarm threshold.
735
void QwtThermo::setAlarmLevel(double v)
737
d_data->alarmLevel = v;
738
d_data->alarmEnabled = 1;
742
//! Return the alarm threshold.
743
double QwtThermo::alarmLevel() const
745
return d_data->alarmLevel;
748
//! Change the width of the pipe.
749
void QwtThermo::setPipeWidth(int w)
753
d_data->thermoWidth = w;
758
//! Return the width of the pipe.
759
int QwtThermo::pipeWidth() const
761
return d_data->thermoWidth;
766
\brief Specify the distance between the pipe's endpoints
767
and the widget's border
769
The margin is used to leave some space for the scale
770
labels. If a large font is used, it is advisable to
772
\param m New Margin. The default values are 10 for
773
horizontal orientation and 20 for vertical
775
\warning The margin has no effect if the scale is disabled.
776
\warning This function is a NOOP because margins are determined
779
void QwtThermo::setMargin(int)
785
\brief Enable or disable the alarm threshold
786
\param tf true (disabled) or false (enabled)
788
void QwtThermo::setAlarmEnabled(bool tf)
790
d_data->alarmEnabled = tf;
794
//! Return if the alarm threshold is enabled or disabled.
795
bool QwtThermo::alarmEnabled() const
797
return d_data->alarmEnabled;
801
\return the minimum size hint
802
\sa QwtThermo::minimumSizeHint
804
QSize QwtThermo::sizeHint() const
806
return minimumSizeHint();
810
\brief Return a minimum size hint
811
\warning The return value depends on the font and the scale.
812
\sa QwtThermo::sizeHint
814
QSize QwtThermo::minimumSizeHint() const
818
if ( d_data->scalePos != NoScale )
820
const int sdExtent = scaleDraw()->extent( QPen(), font() );
821
const int sdLength = scaleDraw()->minLength( QPen(), font() );
824
h = d_data->thermoWidth + sdExtent +
825
d_data->borderWidth + d_data->scaleDist;
831
h = d_data->thermoWidth;
834
if ( d_data->orientation == Qt::Vertical )
837
w += 2 * d_data->borderWidth;
838
h += 2 * d_data->borderWidth;
840
return QSize( w, h );
843
int QwtThermo::transform(double value) const
845
const double min = qwtMin(d_data->map.s1(), d_data->map.s2());
846
const double max = qwtMax(d_data->map.s1(), d_data->map.s2());
853
return d_data->map.transform(value);