地面站终端 App
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.

874 lines
21 KiB

15 years ago
/* -*- 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
*****************************************************************************/
// vim: expandtab
#include <qpainter.h>
#include <qevent.h>
#include "qwt_painter.h"
#include "qwt_color_map.h"
#include "qwt_scale_widget.h"
#include "qwt_scale_map.h"
#include "qwt_math.h"
#include "qwt_paint_buffer.h"
#include "qwt_scale_div.h"
#include "qwt_text.h"
class QwtScaleWidget::PrivateData
{
public:
PrivateData():
scaleDraw(NULL) {
15 years ago
colorBar.colorMap = NULL;
}
~PrivateData() {
15 years ago
delete scaleDraw;
delete colorBar.colorMap;
}
QwtScaleDraw *scaleDraw;
int borderDist[2];
int minBorderDist[2];
int scaleLength;
int margin;
int penWidth;
int titleOffset;
int spacing;
QwtText title;
struct t_colorBar {
15 years ago
bool isEnabled;
int width;
QwtDoubleInterval interval;
QwtColorMap *colorMap;
} colorBar;
};
/*!
\brief Create a scale with the position QwtScaleWidget::Left
\param parent Parent widget
*/
QwtScaleWidget::QwtScaleWidget(QWidget *parent):
QWidget(parent)
{
initScale(QwtScaleDraw::LeftScale);
}
#if QT_VERSION < 0x040000
/*!
\brief Create a scale with the position QwtScaleWidget::Left
\param parent Parent widget
\param name Object name
*/
QwtScaleWidget::QwtScaleWidget(QWidget *parent, const char *name):
QWidget(parent, name)
{
initScale(QwtScaleDraw::LeftScale);
}
#endif
/*!
\brief Constructor
\param align Alignment.
15 years ago
\param parent Parent widget
*/
QwtScaleWidget::QwtScaleWidget(
QwtScaleDraw::Alignment align, QWidget *parent):
15 years ago
QWidget(parent)
{
initScale(align);
}
//! Destructor
QwtScaleWidget::~QwtScaleWidget()
{
delete d_data;
}
//! Initialize the scale
void QwtScaleWidget::initScale(QwtScaleDraw::Alignment align)
{
d_data = new PrivateData;
#if QT_VERSION < 0x040000
setWFlags(Qt::WNoAutoErase);
#endif
15 years ago
d_data->borderDist[0] = 0;
d_data->borderDist[1] = 0;
d_data->minBorderDist[0] = 0;
d_data->minBorderDist[1] = 0;
d_data->margin = 4;
d_data->penWidth = 0;
d_data->titleOffset = 0;
d_data->spacing = 2;
d_data->scaleDraw = new QwtScaleDraw;
d_data->scaleDraw->setAlignment(align);
d_data->scaleDraw->setLength(10);
d_data->colorBar.colorMap = new QwtLinearColorMap();
d_data->colorBar.isEnabled = false;
d_data->colorBar.width = 10;
15 years ago
const int flags = Qt::AlignHCenter
#if QT_VERSION < 0x040000
| Qt::WordBreak | Qt::ExpandTabs;
15 years ago
#else
| Qt::TextExpandTabs | Qt::TextWordWrap;
15 years ago
#endif
d_data->title.setRenderFlags(flags);
d_data->title.setFont(font());
15 years ago
QSizePolicy policy(QSizePolicy::MinimumExpanding,
QSizePolicy::Fixed);
15 years ago
if ( d_data->scaleDraw->orientation() == Qt::Vertical )
policy.transpose();
setSizePolicy(policy);
15 years ago
#if QT_VERSION >= 0x040000
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
#else
clearWState( WState_OwnSizePolicy );
#endif
}
void QwtScaleWidget::setTitle(const QString &title)
{
if ( d_data->title.text() != title ) {
15 years ago
d_data->title.setText(title);
layoutScale();
}
}
/*!
\brief Give title new text contents
\param title New title
\sa QwtScaleWidget::title
\warning The title flags are interpreted in
direction of the label, AlignTop, AlignBottom can't be set
as the title will always be aligned to the scale.
*/
void QwtScaleWidget::setTitle(const QwtText &title)
{
QwtText t = title;
const int flags = title.renderFlags() & ~(Qt::AlignTop | Qt::AlignBottom);
t.setRenderFlags(flags);
if (t != d_data->title) {
15 years ago
d_data->title = t;
layoutScale();
}
}
/*!
Change the alignment
\param alignment New alignment
\sa QwtScaleWidget::alignment
*/
void QwtScaleWidget::setAlignment(QwtScaleDraw::Alignment alignment)
{
#if QT_VERSION >= 0x040000
if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
#else
if ( !testWState( WState_OwnSizePolicy ) )
#endif
{
QSizePolicy policy(QSizePolicy::MinimumExpanding,
QSizePolicy::Fixed);
15 years ago
if ( d_data->scaleDraw->orientation() == Qt::Vertical )
policy.transpose();
setSizePolicy(policy);
#if QT_VERSION >= 0x040000
setAttribute(Qt::WA_WState_OwnSizePolicy, false);
#else
clearWState( WState_OwnSizePolicy );
#endif
}
if (d_data->scaleDraw)
d_data->scaleDraw->setAlignment(alignment);
layoutScale();
}
/*!
\return position
15 years ago
\sa QwtScaleWidget::setPosition
*/
QwtScaleDraw::Alignment QwtScaleWidget::alignment() const
15 years ago
{
if (!scaleDraw())
return QwtScaleDraw::LeftScale;
return scaleDraw()->alignment();
}
/*!
Specify distances of the scale's endpoints from the
widget's borders. The actual borders will never be less
than minimum border distance.
\param dist1 Left or top Distance
\param dist2 Right or bottom distance
\sa QwtScaleWidget::borderDist
*/
void QwtScaleWidget::setBorderDist(int dist1, int dist2)
{
if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] ) {
15 years ago
d_data->borderDist[0] = dist1;
d_data->borderDist[1] = dist2;
layoutScale();
}
}
/*!
\brief Specify the margin to the colorBar/base line.
\param margin Margin
\sa QwtScaleWidget::margin
*/
void QwtScaleWidget::setMargin(int margin)
{
margin = qwtMax( 0, margin );
if ( margin != d_data->margin ) {
15 years ago
d_data->margin = margin;
layoutScale();
}
}
/*!
\brief Specify the distance between color bar, scale and title
\param spacing Spacing
\sa QwtScaleWidget::spacing
*/
void QwtScaleWidget::setSpacing(int spacing)
{
spacing = qwtMax( 0, spacing );
if ( spacing != d_data->spacing ) {
15 years ago
d_data->spacing = spacing;
layoutScale();
}
}
/*!
\brief Specify the width of the scale pen
\param width Pen width
\sa QwtScaleWidget::penWidth
*/
void QwtScaleWidget::setPenWidth(int width)
{
if ( width < 0 )
width = 0;
if ( width != d_data->penWidth ) {
15 years ago
d_data->penWidth = width;
layoutScale();
}
}
/*!
\brief Change the alignment for the labels.
\sa QwtScaleDraw::setLabelAlignment(), QwtScaleWidget::setLabelRotation()
*/
#if QT_VERSION < 0x040000
void QwtScaleWidget::setLabelAlignment(int alignment)
#else
void QwtScaleWidget::setLabelAlignment(Qt::Alignment alignment)
#endif
{
d_data->scaleDraw->setLabelAlignment(alignment);
layoutScale();
}
/*!
\brief Change the rotation for the labels.
See QwtScaleDraw::setLabelRotation().
\sa QwtScaleDraw::setLabelRotation(), QwtScaleWidget::setLabelFlags()
*/
void QwtScaleWidget::setLabelRotation(double rotation)
{
d_data->scaleDraw->setLabelRotation(rotation);
layoutScale();
}
/*!
\brief Set a scale draw
sd has to be created with new and will be deleted in
QwtScaleWidget::~QwtScale or the next call of QwtScaleWidget::setScaleDraw.
*/
void QwtScaleWidget::setScaleDraw(QwtScaleDraw *sd)
{
if ( sd == NULL || sd == d_data->scaleDraw )
return;
if ( d_data->scaleDraw )
sd->setAlignment(d_data->scaleDraw->alignment());
delete d_data->scaleDraw;
d_data->scaleDraw = sd;
layoutScale();
}
/*!
15 years ago
scaleDraw of this scale
\sa QwtScaleDraw::setScaleDraw
*/
const QwtScaleDraw *QwtScaleWidget::scaleDraw() const
{
return d_data->scaleDraw;
15 years ago
}
/*!
15 years ago
scaleDraw of this scale
\sa QwtScaleDraw::setScaleDraw
*/
QwtScaleDraw *QwtScaleWidget::scaleDraw()
{
return d_data->scaleDraw;
15 years ago
}
/*!
\return title
15 years ago
\sa QwtScaleWidget::setTitle
*/
QwtText QwtScaleWidget::title() const
15 years ago
{
return d_data->title;
}
/*!
\return start border distance
15 years ago
\sa QwtScaleWidget::setBorderDist
*/
int QwtScaleWidget::startBorderDist() const
{
return d_data->borderDist[0];
}
15 years ago
/*!
\return end border distance
15 years ago
\sa QwtScaleWidget::setBorderDist
*/
int QwtScaleWidget::endBorderDist() const
{
return d_data->borderDist[1];
15 years ago
}
/*!
15 years ago
\return margin
\sa QwtScaleWidget::setMargin
*/
int QwtScaleWidget::margin() const
{
return d_data->margin;
15 years ago
}
/*!
15 years ago
\return distance between scale and title
\sa QwtScaleWidget::setMargin
*/
int QwtScaleWidget::spacing() const
{
return d_data->spacing;
15 years ago
}
/*!
15 years ago
\return Scale pen width
\sa QwtScaleWidget::setPenWidth
*/
int QwtScaleWidget::penWidth() const
{
return d_data->penWidth;
}
15 years ago
/*!
\brief paintEvent
*/
void QwtScaleWidget::paintEvent(QPaintEvent *e)
{
const QRect &ur = e->rect();
if ( ur.isValid() ) {
15 years ago
#if QT_VERSION < 0x040000
QwtPaintBuffer paintBuffer(this, ur);
draw(paintBuffer.painter());
#else
QPainter painter(this);
draw(&painter);
#endif
}
}
/*!
\brief draw the scale
*/
void QwtScaleWidget::draw(QPainter *painter) const
{
painter->save();
QPen scalePen = painter->pen();
scalePen.setWidth(d_data->penWidth);
painter->setPen(scalePen);
15 years ago
#if QT_VERSION < 0x040000
d_data->scaleDraw->draw(painter, colorGroup());
#else
d_data->scaleDraw->draw(painter, palette());
#endif
painter->restore();
if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 &&
d_data->colorBar.interval.isValid() ) {
15 years ago
drawColorBar(painter, colorBarRect(rect()));
}
QRect r = rect();
if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) {
15 years ago
r.setLeft(r.left() + d_data->borderDist[0]);
r.setWidth(r.width() - d_data->borderDist[1]);
} else {
15 years ago
r.setTop(r.top() + d_data->borderDist[0]);
r.setHeight(r.height() - d_data->borderDist[1]);
}
if ( !d_data->title.isEmpty() ) {
15 years ago
QRect tr = r;
switch(d_data->scaleDraw->alignment()) {
case QwtScaleDraw::LeftScale:
tr.setRight( r.right() - d_data->titleOffset );
break;
case QwtScaleDraw::RightScale:
tr.setLeft( r.left() + d_data->titleOffset );
break;
case QwtScaleDraw::BottomScale:
tr.setTop( r.top() + d_data->titleOffset );
break;
case QwtScaleDraw::TopScale:
default:
tr.setBottom( r.bottom() - d_data->titleOffset );
break;
15 years ago
}
drawTitle(painter, d_data->scaleDraw->alignment(), tr);
}
}
QRect QwtScaleWidget::colorBarRect(const QRect& rect) const
{
QRect cr = rect;
if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) {
15 years ago
cr.setLeft(cr.left() + d_data->borderDist[0]);
cr.setWidth(cr.width() - d_data->borderDist[1] + 1);
} else {
15 years ago
cr.setTop(cr.top() + d_data->borderDist[0]);
cr.setHeight(cr.height() - d_data->borderDist[1] + 1);
}
switch(d_data->scaleDraw->alignment()) {
case QwtScaleDraw::LeftScale: {
cr.setLeft( cr.right() - d_data->spacing
- d_data->colorBar.width + 1 );
cr.setWidth(d_data->colorBar.width);
break;
}
15 years ago
case QwtScaleDraw::RightScale: {
cr.setLeft( cr.left() + d_data->spacing );
cr.setWidth(d_data->colorBar.width);
break;
}
15 years ago
case QwtScaleDraw::BottomScale: {
cr.setTop( cr.top() + d_data->spacing );
cr.setHeight(d_data->colorBar.width);
break;
}
15 years ago
case QwtScaleDraw::TopScale: {
cr.setTop( cr.bottom() - d_data->spacing
- d_data->colorBar.width + 1 );
cr.setHeight(d_data->colorBar.width);
break;
}
15 years ago
}
return cr;
}
/*!
\brief resizeEvent
*/
void QwtScaleWidget::resizeEvent(QResizeEvent *)
{
layoutScale(false);
}
//! Recalculate the scale's geometry and layout based on
// the current rect and fonts.
// \param update_geometry notify the layout system and call update
// to redraw the scale
void QwtScaleWidget::layoutScale( bool update_geometry )
{
int bd0, bd1;
getBorderDistHint(bd0, bd1);
if ( d_data->borderDist[0] > bd0 )
bd0 = d_data->borderDist[0];
if ( d_data->borderDist[1] > bd1 )
bd1 = d_data->borderDist[1];
int colorBarWidth = 0;
if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
colorBarWidth = d_data->colorBar.width + d_data->spacing;
const QRect r = rect();
int x, y, length;
if ( d_data->scaleDraw->orientation() == Qt::Vertical ) {
15 years ago
y = r.top() + bd0;
length = r.height() - (bd0 + bd1);
if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale )
x = r.right() - d_data->margin - colorBarWidth;
else
x = r.left() + d_data->margin + colorBarWidth;
} else {
x = r.left() + bd0;
15 years ago
length = r.width() - (bd0 + bd1);
if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale )
y = r.top() + d_data->margin + colorBarWidth;
else
y = r.bottom() - d_data->margin - colorBarWidth;
}
d_data->scaleDraw->move(x, y);
d_data->scaleDraw->setLength(length);
d_data->titleOffset = d_data->margin + d_data->spacing +
colorBarWidth +
d_data->scaleDraw->extent(QPen(Qt::black, d_data->penWidth), font());
15 years ago
if ( update_geometry ) {
updateGeometry();
update();
15 years ago
}
}
void QwtScaleWidget::drawColorBar(QPainter *painter, const QRect& rect) const
{
if ( !d_data->colorBar.interval.isValid() )
return;
const QwtScaleDraw* sd = d_data->scaleDraw;
QwtPainter::drawColorBar(painter, *d_data->colorBar.colorMap,
d_data->colorBar.interval.normalized(), sd->map(),
sd->orientation(), rect);
15 years ago
}
/*!
Rotate and paint a title according to its position into a given rectangle.
\param painter Painter
\param align Alignment
\param rect Bounding rectangle
*/
void QwtScaleWidget::drawTitle(QPainter *painter,
QwtScaleDraw::Alignment align, const QRect &rect) const
15 years ago
{
QRect r;
double angle;
int flags = d_data->title.renderFlags() &
~(Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter);
switch(align) {
case QwtScaleDraw::LeftScale:
flags |= Qt::AlignTop;
angle = -90.0;
r.setRect(rect.left(), rect.bottom(), rect.height(), rect.width());
break;
case QwtScaleDraw::RightScale:
flags |= Qt::AlignTop;
angle = 90.0;
r.setRect(rect.right(), rect.top(), rect.height(), rect.width());
break;
case QwtScaleDraw::TopScale:
flags |= Qt::AlignTop;
angle = 0.0;
r = rect;
break;
case QwtScaleDraw::BottomScale:
default:
flags |= Qt::AlignBottom;
angle = 0.0;
r = rect;
break;
15 years ago
}
painter->save();
painter->setFont(font());
#if QT_VERSION < 0x040000
painter->setPen(colorGroup().color(QColorGroup::Text));
#else
painter->setPen(palette().color(QPalette::Text));
#endif
painter->translate(r.x(), r.y());
if (angle != 0.0)
painter->rotate(angle);
QwtText title = d_data->title;
title.setRenderFlags(flags);
title.draw(painter, QRect(0, 0, r.width(), r.height()));
painter->restore();
}
/*!
\brief Notify a change of the scale
This virtual function can be overloaded by derived
classes. The default implementation updates the geometry
and repaints the widget.
*/
void QwtScaleWidget::scaleChange()
{
layoutScale();
}
/*!
\return a size hint
*/
QSize QwtScaleWidget::sizeHint() const
{
return minimumSizeHint();
}
/*!
\return a minimum size hint
*/
QSize QwtScaleWidget::minimumSizeHint() const
{
const Qt::Orientation o = d_data->scaleDraw->orientation();
// Border Distance cannot be less than the scale borderDistHint
// Note, the borderDistHint is already included in minHeight/minWidth
int length = 0;
int mbd1, mbd2;
getBorderDistHint(mbd1, mbd2);
length += qwtMax( 0, d_data->borderDist[0] - mbd1 );
length += qwtMax( 0, d_data->borderDist[1] - mbd2 );
length += d_data->scaleDraw->minLength(
QPen(Qt::black, d_data->penWidth), font());
15 years ago
int dim = dimForLength(length, font());
if ( length < dim ) {
15 years ago
// compensate for long titles
length = dim;
dim = dimForLength(length, font());
}
QSize size(length + 2, dim);
if ( o == Qt::Vertical )
size.transpose();
return size;
}
/*!
\brief Find the height of the title for a given width.
\param width Width
\return height Height
*/
int QwtScaleWidget::titleHeightForWidth(int width) const
{
return d_data->title.heightForWidth(width, font());
}
/*!
\brief Find the minimum dimension for a given length.
dim is the height, length the width seen in
direction of the title.
\param length width for horizontal, height for vertical scales
\param scaleFont Font of the scale
\return height for horizontal, width for vertical scales
*/
int QwtScaleWidget::dimForLength(int length, const QFont &scaleFont) const
{
int dim = d_data->margin;
dim += d_data->scaleDraw->extent(
QPen(Qt::black, d_data->penWidth), scaleFont);
15 years ago
if ( !d_data->title.isEmpty() )
dim += titleHeightForWidth(length) + d_data->spacing;
if ( d_data->colorBar.isEnabled && d_data->colorBar.interval.isValid() )
dim += d_data->colorBar.width + d_data->spacing;
return dim;
}
/*!
\brief Calculate a hint for the border distances.
This member function calculates the distance
of the scale's endpoints from the widget borders which
is required for the mark labels to fit into the widget.
The maximum of this distance an the minimum border distance
is returned.
\warning
<ul> <li>The minimum border distance depends on the font.</ul>
\sa setMinBorderDist(), getMinBorderDist(), setBorderDist()
*/
void QwtScaleWidget::getBorderDistHint(int &start, int &end) const
{
d_data->scaleDraw->getBorderDistHint(font(), start, end);
if ( start < d_data->minBorderDist[0] )
start = d_data->minBorderDist[0];
if ( end < d_data->minBorderDist[1] )
end = d_data->minBorderDist[1];
}
/*!
Set a minimum value for the distances of the scale's endpoints from
15 years ago
the widget borders. This is useful to avoid that the scales
are "jumping", when the tick labels or their positions change
15 years ago
often.
\sa getMinBorderDist(), getBorderDistHint()
*/
void QwtScaleWidget::setMinBorderDist(int start, int end)
{
d_data->minBorderDist[0] = start;
d_data->minBorderDist[1] = end;
}
/*!
Get the minimum value for the distances of the scale's endpoints from
15 years ago
the widget borders.
\sa setMinBorderDist(), getBorderDistHint()
*/
void QwtScaleWidget::getMinBorderDist(int &start, int &end) const
{
start = d_data->minBorderDist[0];
end = d_data->minBorderDist[1];
}
#if QT_VERSION < 0x040000
/*!
\brief Notify a change of the font
This virtual function may be overloaded by derived widgets.
The default implementation resizes the scale and repaints
the widget.
\param oldFont Previous font
*/
void QwtScaleWidget::fontChange(const QFont &oldFont)
{
QWidget::fontChange( oldFont );
layoutScale();
}
#endif
/*!
\brief Assign a scale division
The scale division determines where to set the tick marks.
\param transformation Transformation, needed to translate between
scale and pixal values
\param scaleDiv Scale Division
\sa For more information about scale divisions, see QwtScaleDiv.
*/
void QwtScaleWidget::setScaleDiv(
QwtScaleTransformation *transformation,
const QwtScaleDiv &scaleDiv)
{
QwtScaleDraw *sd = d_data->scaleDraw;
if (sd->scaleDiv() != scaleDiv ||
sd->map().transformation()->type() != transformation->type() ) {
15 years ago
sd->setTransformation(transformation);
sd->setScaleDiv(scaleDiv);
layoutScale();
emit scaleDivChanged();
} else
15 years ago
delete transformation;
}
void QwtScaleWidget::setColorBarEnabled(bool on)
{
if ( on != d_data->colorBar.isEnabled ) {
15 years ago
d_data->colorBar.isEnabled = on;
layoutScale();
}
}
bool QwtScaleWidget::isColorBarEnabled() const
{
return d_data->colorBar.isEnabled;
}
void QwtScaleWidget::setColorBarWidth(int width)
{
if ( width != d_data->colorBar.width ) {
15 years ago
d_data->colorBar.width = width;
if ( isColorBarEnabled() )
layoutScale();
}
}
int QwtScaleWidget::colorBarWidth() const
{
return d_data->colorBar.width;
}
QwtDoubleInterval QwtScaleWidget::colorBarInterval() const
{
return d_data->colorBar.interval;
}
void QwtScaleWidget::setColorMap(const QwtDoubleInterval &interval,
const QwtColorMap &colorMap)
15 years ago
{
d_data->colorBar.interval = interval;
delete d_data->colorBar.colorMap;
d_data->colorBar.colorMap = colorMap.copy();
if ( isColorBarEnabled() )
layoutScale();
}
const QwtColorMap &QwtScaleWidget::colorMap() const
{
return *d_data->colorBar.colorMap;
}