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;
150
void QwtThermo::setScaleDraw(QwtScaleDraw *scaleDraw)
152
setAbstractScaleDraw(scaleDraw);
155
const QwtScaleDraw *QwtThermo::scaleDraw() const
157
return (QwtScaleDraw *)abstractScaleDraw();
160
QwtScaleDraw *QwtThermo::scaleDraw()
162
return (QwtScaleDraw *)abstractScaleDraw();
166
void QwtThermo::paintEvent(QPaintEvent *e)
168
// Use double-buffering
169
const QRect &ur = e->rect();
172
#if QT_VERSION < 0x040000
173
QwtPaintBuffer paintBuffer(this, ur);
174
draw(paintBuffer.painter(), ur);
176
QPainter painter(this);
182
//! Draw the whole QwtThermo.
183
void QwtThermo::draw(QPainter *p, const QRect& ur)
185
if ( !d_data->thermoRect.contains(ur) )
187
if (d_data->scalePos != NoScale)
189
#if QT_VERSION < 0x040000
190
scaleDraw()->draw(p, colorGroup());
192
scaleDraw()->draw(p, palette());
197
d_data->thermoRect.x() - d_data->borderWidth,
198
d_data->thermoRect.y() - d_data->borderWidth,
199
d_data->thermoRect.width() + 2*d_data->borderWidth,
200
d_data->thermoRect.height() + 2*d_data->borderWidth,
201
#if QT_VERSION < 0x040000
206
true, d_data->borderWidth,0);
211
//! Qt resize event handler
212
void QwtThermo::resizeEvent(QResizeEvent *)
214
layoutThermo( false );
218
Recalculate the QwtThermo geometry and layout based on
219
the QwtThermo::rect() and the fonts.
220
\param update_geometry notify the layout system and call update
223
void QwtThermo::layoutThermo( bool update_geometry )
227
if ( d_data->scalePos != NoScale )
230
scaleDraw()->getBorderDistHint(font(), d1, d2);
231
mbd = qwtMax(d1, d2);
234
if ( d_data->orientation == Qt::Horizontal )
236
switch ( d_data->scalePos )
240
d_data->thermoRect.setRect(
241
r.x() + mbd + d_data->borderWidth,
243
- d_data->thermoWidth - 2*d_data->borderWidth,
244
r.width() - 2*(d_data->borderWidth + mbd),
245
d_data->thermoWidth);
246
scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
247
scaleDraw()->move( d_data->thermoRect.x(),
248
d_data->thermoRect.y() - d_data->borderWidth
249
- d_data->scaleDist);
250
scaleDraw()->setLength(d_data->thermoRect.width());
255
case NoScale: // like Bottom but without scale
256
default: // inconsistent orientation and scale position
257
// Mapping between values and pixels requires
258
// initialization of the scale geometry
260
d_data->thermoRect.setRect(
261
r.x() + mbd + d_data->borderWidth,
262
r.y() + d_data->borderWidth,
263
r.width() - 2*(d_data->borderWidth + mbd),
264
d_data->thermoWidth);
265
scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
267
d_data->thermoRect.x(),
268
d_data->thermoRect.y() + d_data->thermoRect.height()
269
+ d_data->borderWidth + d_data->scaleDist );
270
scaleDraw()->setLength(d_data->thermoRect.width());
274
d_data->map.setPaintInterval(d_data->thermoRect.x(),
275
d_data->thermoRect.x() + d_data->thermoRect.width() - 1);
279
switch ( d_data->scalePos )
283
d_data->thermoRect.setRect(
284
r.x() + d_data->borderWidth,
285
r.y() + mbd + d_data->borderWidth,
287
r.height() - 2*(d_data->borderWidth + mbd));
288
scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
290
d_data->thermoRect.x() + d_data->thermoRect.width()
291
+ d_data->borderWidth + d_data->scaleDist,
292
d_data->thermoRect.y());
293
scaleDraw()->setLength(d_data->thermoRect.height());
298
case NoScale: // like Left but without scale
299
default: // inconsistent orientation and scale position
300
// Mapping between values and pixels requires
301
// initialization of the scale geometry
303
d_data->thermoRect.setRect(
304
r.x() + r.width() - 2*d_data->borderWidth - d_data->thermoWidth,
305
r.y() + mbd + d_data->borderWidth,
307
r.height() - 2*(d_data->borderWidth + mbd));
308
scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
310
d_data->thermoRect.x() - d_data->scaleDist
311
- d_data->borderWidth,
312
d_data->thermoRect.y() );
313
scaleDraw()->setLength(d_data->thermoRect.height());
317
d_data->map.setPaintInterval(
318
d_data->thermoRect.y() + d_data->thermoRect.height() - 1,
319
d_data->thermoRect.y());
321
if ( update_geometry )
329
\brief Set the thermometer orientation and the scale position.
331
The scale position NoScale disables the scale.
332
\param o orientation. Possible values are Qt::Horizontal and Qt::Vertical.
333
The default value is Qt::Vertical.
334
\param s Position of the scale.
335
The default value is NoScale.
337
A valid combination of scale position and orientation is enforced:
338
- a horizontal thermometer can have the scale positions TopScale,
339
BottomScale or NoScale;
340
- a vertical thermometer can have the scale positions LeftScale,
341
RightScale or NoScale;
342
- an invalid scale position will default to NoScale.
344
\sa QwtThermo::setScalePosition()
346
void QwtThermo::setOrientation(Qt::Orientation o, ScalePos s)
348
if ( o == d_data->orientation && s == d_data->scalePos )
355
if ((s == NoScale) || (s == BottomScale) || (s == TopScale))
356
d_data->scalePos = s;
358
d_data->scalePos = NoScale;
363
if ((s == NoScale) || (s == LeftScale) || (s == RightScale))
364
d_data->scalePos = s;
366
d_data->scalePos = NoScale;
371
if ( o != d_data->orientation )
373
#if QT_VERSION >= 0x040000
374
if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
376
if ( !testWState( WState_OwnSizePolicy ) )
379
QSizePolicy sp = sizePolicy();
383
#if QT_VERSION >= 0x040000
384
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
386
clearWState( WState_OwnSizePolicy );
391
d_data->orientation = o;
396
\brief Change the scale position (and thermometer orientation).
398
\param s Position of the scale.
400
A valid combination of scale position and orientation is enforced:
401
- if the new scale position is LeftScale or RightScale, the
402
scale orientation will become Qt::Vertical;
403
- if the new scale position is BottomScale or TopScale, the scale
404
orientation will become Qt::Horizontal;
405
- if the new scale position is NoScale, the scale orientation will not change.
407
\sa QwtThermo::setOrientation()
409
void QwtThermo::setScalePosition(ScalePos s)
411
if ((s == BottomScale) || (s == TopScale))
412
setOrientation(Qt::Horizontal, s);
413
else if ((s == LeftScale) || (s == RightScale))
414
setOrientation(Qt::Vertical, s);
416
setOrientation(d_data->orientation, NoScale);
419
//! Return the scale position.
420
QwtThermo::ScalePos QwtThermo::scalePosition() const
422
return d_data->scalePos;
425
//! Notify a font change.
426
void QwtThermo::fontChange(const QFont &f)
428
QWidget::fontChange( f );
432
//! Notify a scale change.
433
void QwtThermo::scaleChange()
439
//! Redraw the liquid in thermometer pipe.
440
void QwtThermo::drawThermo(QPainter *p)
442
int alarm = 0, taval = 0;
448
int inverted = ( d_data->maxValue < d_data->minValue );
451
// Determine if value exceeds alarm threshold.
452
// Note: The alarm value is allowed to lie
453
// outside the interval (minValue, maxValue).
455
if (d_data->alarmEnabled)
459
alarm = ((d_data->alarmLevel >= d_data->maxValue)
460
&& (d_data->alarmLevel <= d_data->minValue)
461
&& (d_data->value >= d_data->alarmLevel));
466
alarm = (( d_data->alarmLevel >= d_data->minValue)
467
&& (d_data->alarmLevel <= d_data->maxValue)
468
&& (d_data->value >= d_data->alarmLevel));
475
int tval = transform(d_data->value);
478
taval = transform(d_data->alarmLevel);
481
// calculate recangles
483
if ( d_data->orientation == Qt::Horizontal )
487
bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
488
tval - d_data->thermoRect.x(),
489
d_data->thermoRect.height());
493
aRect.setRect(tval, d_data->thermoRect.y(),
495
d_data->thermoRect.height());
496
fRect.setRect(taval + 1, d_data->thermoRect.y(),
497
d_data->thermoRect.x() + d_data->thermoRect.width() - (taval + 1),
498
d_data->thermoRect.height());
502
fRect.setRect(tval, d_data->thermoRect.y(),
503
d_data->thermoRect.x() + d_data->thermoRect.width() - tval,
504
d_data->thermoRect.height());
509
bRect.setRect(tval + 1, d_data->thermoRect.y(),
510
d_data->thermoRect.width() - (tval + 1 - d_data->thermoRect.x()),
511
d_data->thermoRect.height());
515
aRect.setRect(taval, d_data->thermoRect.y(),
517
d_data->thermoRect.height());
518
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
519
taval - d_data->thermoRect.x(),
520
d_data->thermoRect.height());
524
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
525
tval - d_data->thermoRect.x() + 1,
526
d_data->thermoRect.height());
533
if (tval < d_data->thermoRect.y())
534
tval = d_data->thermoRect.y();
537
if (tval > d_data->thermoRect.y() + d_data->thermoRect.height())
538
tval = d_data->thermoRect.y() + d_data->thermoRect.height();
543
bRect.setRect(d_data->thermoRect.x(), tval + 1,
544
d_data->thermoRect.width(),
545
d_data->thermoRect.height() - (tval + 1 - d_data->thermoRect.y()));
549
aRect.setRect(d_data->thermoRect.x(), taval,
550
d_data->thermoRect.width(),
552
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
553
d_data->thermoRect.width(),
554
taval - d_data->thermoRect.y());
558
fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
559
d_data->thermoRect.width(),
560
tval - d_data->thermoRect.y() + 1);
565
bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
566
d_data->thermoRect.width(),
567
tval - d_data->thermoRect.y());
570
aRect.setRect(d_data->thermoRect.x(),tval,
571
d_data->thermoRect.width(),
573
fRect.setRect(d_data->thermoRect.x(),taval + 1,
574
d_data->thermoRect.width(),
575
d_data->thermoRect.y() + d_data->thermoRect.height() - (taval + 1));
579
fRect.setRect(d_data->thermoRect.x(),tval,
580
d_data->thermoRect.width(),
581
d_data->thermoRect.y() + d_data->thermoRect.height() - tval);
589
const QColor bgColor =
590
#if QT_VERSION < 0x040000
591
colorGroup().color(QColorGroup::Background);
593
palette().color(QPalette::Background);
595
p->fillRect(bRect, bgColor);
598
p->fillRect(aRect, d_data->alarmBrush);
600
p->fillRect(fRect, d_data->fillBrush);
603
//! Set the border width of the pipe.
604
void QwtThermo::setBorderWidth(int w)
606
if ((w >= 0) && (w < (qwtMin(d_data->thermoRect.width(),
607
d_data->thermoRect.height()) + d_data->borderWidth) / 2 - 1))
609
d_data->borderWidth = w;
614
//! Return the border width of the thermometer pipe.
615
int QwtThermo::borderWidth() const
617
return d_data->borderWidth;
622
\param vmin value corresponding lower or left end of the thermometer
623
\param vmax value corresponding to the upper or right end of the thermometer
624
\param logarithmic logarithmic mapping, true or false
626
void QwtThermo::setRange(double vmin, double vmax, bool logarithmic)
628
d_data->minValue = vmin;
629
d_data->maxValue = vmax;
632
setScaleEngine(new QwtLog10ScaleEngine);
634
setScaleEngine(new QwtLinearScaleEngine);
637
There are two different maps, one for the scale, the other
638
for the values. This is confusing and will be changed
639
in the future. TODO ...
642
d_data->map.setTransformation(scaleEngine()->transformation());
643
d_data->map.setScaleInterval(d_data->minValue, d_data->maxValue);
646
rescale(d_data->minValue, d_data->maxValue);
652
\brief Change the brush of the liquid.
653
\param brush New brush. The default brush is solid black.
655
void QwtThermo::setFillBrush(const QBrush& brush)
657
d_data->fillBrush = brush;
661
//! Return the liquid brush.
662
const QBrush& QwtThermo::fillBrush() const
664
return d_data->fillBrush;
668
\brief Change the color of the liquid.
669
\param c New color. The default color is black.
671
void QwtThermo::setFillColor(const QColor &c)
673
d_data->fillBrush.setColor(c);
677
//! Return the liquid color.
678
const QColor &QwtThermo::fillColor() const
680
return d_data->fillBrush.color();
684
\brief Specify the liquid brush above the alarm threshold
685
\param brush New brush. The default is solid white.
687
void QwtThermo::setAlarmBrush(const QBrush& brush)
689
d_data->alarmBrush = brush;
693
//! Return the liquid brush above the alarm threshold.
694
const QBrush& QwtThermo::alarmBrush() const
696
return d_data->alarmBrush;
700
\brief Specify the liquid color above the alarm threshold
701
\param c New color. The default is white.
703
void QwtThermo::setAlarmColor(const QColor &c)
705
d_data->alarmBrush.setColor(c);
709
//! Return the liquid color above the alarm threshold.
710
const QColor &QwtThermo::alarmColor() const
712
return d_data->alarmBrush.color();
715
//! Specify the alarm threshold.
716
void QwtThermo::setAlarmLevel(double v)
718
d_data->alarmLevel = v;
719
d_data->alarmEnabled = 1;
723
//! Return the alarm threshold.
724
double QwtThermo::alarmLevel() const
726
return d_data->alarmLevel;
729
//! Change the width of the pipe.
730
void QwtThermo::setPipeWidth(int w)
734
d_data->thermoWidth = w;
739
//! Return the width of the pipe.
740
int QwtThermo::pipeWidth() const
742
return d_data->thermoWidth;
747
\brief Specify the distance between the pipe's endpoints
748
and the widget's border
750
The margin is used to leave some space for the scale
751
labels. If a large font is used, it is advisable to
753
\param m New Margin. The default values are 10 for
754
horizontal orientation and 20 for vertical
756
\warning The margin has no effect if the scale is disabled.
757
\warning This function is a NOOP because margins are determined
760
void QwtThermo::setMargin(int)
766
\brief Enable or disable the alarm threshold
767
\param tf true (disabled) or false (enabled)
769
void QwtThermo::setAlarmEnabled(bool tf)
771
d_data->alarmEnabled = tf;
775
//! Return if the alarm threshold is enabled or disabled.
776
bool QwtThermo::alarmEnabled() const
778
return d_data->alarmEnabled;
782
\return the minimum size hint
783
\sa QwtThermo::minimumSizeHint
785
QSize QwtThermo::sizeHint() const
787
return minimumSizeHint();
791
\brief Return a minimum size hint
792
\warning The return value depends on the font and the scale.
793
\sa QwtThermo::sizeHint
795
QSize QwtThermo::minimumSizeHint() const
799
if ( d_data->scalePos != NoScale )
801
const int sdExtent = scaleDraw()->extent( QPen(), font() );
802
const int sdLength = scaleDraw()->minLength( QPen(), font() );
805
h = d_data->thermoWidth + sdExtent +
806
d_data->borderWidth + d_data->scaleDist;
812
h = d_data->thermoWidth;
815
if ( d_data->orientation == Qt::Vertical )
818
w += 2 * d_data->borderWidth;
819
h += 2 * d_data->borderWidth;
821
return QSize( w, h );
824
int QwtThermo::transform(double value) const
826
const double min = qwtMin(d_data->map.s1(), d_data->map.s2());
827
const double max = qwtMax(d_data->map.s1(), d_data->map.s2());
834
return d_data->map.transform(value);