Newer
Older
/* -*- 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_painter.h"
#include "qwt_color_map.h"
#include "qwt_scale_map.h"
#include "qwt_math.h"
#include "qwt_scale_div.h"
#include "qwt_text.h"
#include "qwt_scale_engine.h"
#include <qpainter.h>
#include <qevent.h>
#include <qmath.h>
#include <qstyle.h>
#include <qstyleoption.h>
class QwtScaleWidget::PrivateData
{
public:
PrivateData():
delete scaleDraw;
delete colorBar.colorMap;
}
QwtScaleDraw *scaleDraw;
int borderDist[2];
int minBorderDist[2];
int scaleLength;
int margin;
int titleOffset;
int spacing;
QwtText title;
QwtScaleWidget::LayoutFlags layoutFlags;
struct t_colorBar
{
QwtColorMap *colorMap;
} colorBar;
};
/*!
\brief Create a scale with the position QwtScaleWidget::Left
\param parent Parent widget
*/
QwtScaleWidget::QwtScaleWidget( QWidget *parent ):
QWidget( parent )
\param parent Parent widget
*/
QwtScaleWidget::QwtScaleWidget(
QwtScaleDraw::Alignment align, QWidget *parent ):
QWidget( parent )
}
//! Destructor
QwtScaleWidget::~QwtScaleWidget()
{
delete d_data;
}
//! Initialize the scale
void QwtScaleWidget::initScale( QwtScaleDraw::Alignment align )
d_data->layoutFlags = 0;
if ( align == QwtScaleDraw::RightScale )
d_data->layoutFlags |= TitleInverted;
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->titleOffset = 0;
d_data->spacing = 2;
d_data->scaleDraw = new QwtScaleDraw;
d_data->scaleDraw->setAlignment( align );
d_data->scaleDraw->setLength( 10 );
d_data->scaleDraw->setScaleDiv(
QwtLinearScaleEngine().divideScale( 0.0, 100.0, 10, 5 ) );
d_data->colorBar.colorMap = new QwtLinearColorMap();
d_data->colorBar.isEnabled = false;
d_data->colorBar.width = 10;
| Qt::TextExpandTabs | Qt::TextWordWrap;
d_data->title.setRenderFlags( flags );
d_data->title.setFont( font() );
QSizePolicy policy( QSizePolicy::MinimumExpanding,
QSizePolicy::Fixed );
if ( d_data->scaleDraw->orientation() == Qt::Vertical )
policy.transpose();
setSizePolicy( policy );
setAttribute( Qt::WA_WState_OwnSizePolicy, false );
}
/*!
Toggle an layout flag
\param flag Layout flag
\param on true/false
\sa testLayoutFlag(), LayoutFlag
*/
void QwtScaleWidget::setLayoutFlag( LayoutFlag flag, bool on )
{
if ( ( ( d_data->layoutFlags & flag ) != 0 ) != on )
{
if ( on )
d_data->layoutFlags |= flag;
else
d_data->layoutFlags &= ~flag;
}
}
\param flag Layout flag
\return true/false
\sa setLayoutFlag(), LayoutFlag
*/
bool QwtScaleWidget::testLayoutFlag( LayoutFlag flag ) const
{
return ( d_data->layoutFlags & flag );
/*!
Give title new text contents
\param title New title
\sa title(), setTitle(const QwtText &);
*/
void QwtScaleWidget::setTitle( const QString &title )
if ( d_data->title.text() != title )
{
d_data->title.setText( 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.
*/
const int flags = title.renderFlags() & ~( Qt::AlignTop | Qt::AlignBottom );
t.setRenderFlags( flags );
d_data->title = t;
layoutScale();
}
}
/*!
Change the alignment
\param alignment New alignment
void QwtScaleWidget::setAlignment( QwtScaleDraw::Alignment alignment )
if ( d_data->scaleDraw )
d_data->scaleDraw->setAlignment( alignment );
if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
QSizePolicy policy( QSizePolicy::MinimumExpanding,
QSizePolicy::Fixed );
if ( d_data->scaleDraw->orientation() == Qt::Vertical )
policy.transpose();
setSizePolicy( policy );
setAttribute( Qt::WA_WState_OwnSizePolicy, false );
QwtScaleDraw::Alignment QwtScaleWidget::alignment() const
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
if ( dist1 != d_data->borderDist[0] || dist2 != d_data->borderDist[1] )
{
d_data->borderDist[0] = dist1;
d_data->borderDist[1] = dist2;
layoutScale();
}
}
/*!
\brief Specify the margin to the colorBar/base line.
\param margin Margin
margin = qMax( 0, margin );
if ( margin != d_data->margin )
{
d_data->margin = margin;
layoutScale();
}
}
/*!
\brief Specify the distance between color bar, scale and title
\param spacing Spacing
spacing = qMax( 0, spacing );
if ( spacing != d_data->spacing )
{
d_data->spacing = spacing;
layoutScale();
}
}
/*!
\brief Change the alignment for the labels.
void QwtScaleWidget::setLabelAlignment( Qt::Alignment alignment )
layoutScale();
}
/*!
\brief Change the rotation for the labels.
See QwtScaleDraw::setLabelRotation().
\param rotation Rotation
\sa QwtScaleDraw::setLabelRotation(), setLabelFlags()
Set a scale draw
scaleDraw has to be created with new and will be deleted in
~QwtScaleWidget() or the next call of setScaleDraw().
scaleDraw will be initialized with the attributes of
the previous scaleDraw object.
\param scaleDraw ScaleDraw object
\sa scaleDraw()
void QwtScaleWidget::setScaleDraw( QwtScaleDraw *scaleDraw )
if ( ( scaleDraw == NULL ) || ( scaleDraw == d_data->scaleDraw ) )
const QwtScaleDraw* sd = d_data->scaleDraw;
if ( sd )
{
scaleDraw->setAlignment( sd->alignment() );
scaleDraw->setScaleDiv( sd->scaleDiv() );
QwtTransform *transform = NULL;
if ( sd->scaleMap().transformation() )
transform = sd->scaleMap().transformation()->copy();
scaleDraw->setTransformation( transform );
}
\return scaleDraw of this scale
\sa setScaleDraw(), QwtScaleDraw::setScaleDraw()
const QwtScaleDraw *QwtScaleWidget::scaleDraw() const
{
return d_data->scaleDraw;
\return scaleDraw of this scale
\sa QwtScaleDraw::setScaleDraw()
QwtScaleDraw *QwtScaleWidget::scaleDraw()
{
return d_data->scaleDraw;
QwtText QwtScaleWidget::title() const
/*!
\return start border distance
int QwtScaleWidget::startBorderDist() const
{
return d_data->borderDist[0];
}
/*!
\return end border distance
int QwtScaleWidget::endBorderDist() const
{
return d_data->borderDist[1];
int QwtScaleWidget::margin() const
{
return d_data->margin;
int QwtScaleWidget::spacing() const
{
return d_data->spacing;
QPainter painter( this );
painter.setClipRegion( event->region() );
QStyleOption opt;
opt.init(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
draw( &painter );
void QwtScaleWidget::draw( QPainter *painter ) const
{
d_data->scaleDraw->draw( painter, palette() );
if ( d_data->colorBar.isEnabled && d_data->colorBar.width > 0 &&
d_data->colorBar.interval.isValid() )
{
drawColorBar( painter, colorBarRect( contentsRect() ) );
}
QRect r = contentsRect();
if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
{
r.setLeft( r.left() + d_data->borderDist[0] );
r.setWidth( r.width() - d_data->borderDist[1] );
else
{
r.setTop( r.top() + d_data->borderDist[0] );
r.setHeight( r.height() - d_data->borderDist[1] );
}
if ( !d_data->title.isEmpty() )
drawTitle( painter, d_data->scaleDraw->alignment(), r );
Calculate the the rectangle for the color bar
\param rect Bounding rectangle for all components of the scale
\return Rectangle for the color bar
QRectF QwtScaleWidget::colorBarRect( const QRectF& rect ) const
if ( d_data->scaleDraw->orientation() == Qt::Horizontal )
{
cr.setLeft( cr.left() + d_data->borderDist[0] );
cr.setWidth( cr.width() - d_data->borderDist[1] + 1 );
else
{
cr.setTop( cr.top() + d_data->borderDist[0] );
cr.setHeight( cr.height() - d_data->borderDist[1] + 1 );
{
cr.setLeft( cr.right() - d_data->margin
- d_data->colorBar.width );
cr.setWidth( d_data->colorBar.width );
case QwtScaleDraw::RightScale:
{
cr.setLeft( cr.left() + d_data->margin );
cr.setWidth( d_data->colorBar.width );
case QwtScaleDraw::BottomScale:
{
cr.setTop( cr.top() + d_data->margin );
cr.setHeight( d_data->colorBar.width );
{
cr.setTop( cr.bottom() - d_data->margin
- d_data->colorBar.width );
cr.setHeight( d_data->colorBar.width );
Event handler for resize events
\param event Resize event
/*!
Recalculate the scale's geometry and layout based on
the current geometry 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;
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;
if ( d_data->scaleDraw->orientation() == Qt::Vertical )
{
if ( d_data->scaleDraw->alignment() == QwtScaleDraw::LeftScale )
if ( d_data->scaleDraw->alignment() == QwtScaleDraw::BottomScale )
y = r.top() + d_data->margin + colorBarWidth;
else
d_data->scaleDraw->move( x, y );
d_data->scaleDraw->setLength( length );
const int extent = qCeil( d_data->scaleDraw->extent( font() ) );
d_data->titleOffset =
d_data->margin + d_data->spacing + colorBarWidth + extent;
if ( update_geometry )
{
/*!
Draw the color bar of the scale widget
\param painter Painter
\param rect Bounding rectangle for the color bar
\sa setColorBarEnabled()
*/
void QwtScaleWidget::drawColorBar( QPainter *painter, const QRectF& 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->scaleMap(),
sd->orientation(), rect );
}
/*!
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 QRectF &rect ) const
int flags = d_data->title.renderFlags() &
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
~( Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter );
switch ( align )
{
case QwtScaleDraw::LeftScale:
angle = -90.0;
flags |= Qt::AlignTop;
r.setRect( r.left(), r.bottom(),
r.height(), r.width() - d_data->titleOffset );
break;
case QwtScaleDraw::RightScale:
angle = -90.0;
flags |= Qt::AlignTop;
r.setRect( r.left() + d_data->titleOffset, r.bottom(),
r.height(), r.width() - d_data->titleOffset );
break;
case QwtScaleDraw::BottomScale:
angle = 0.0;
flags |= Qt::AlignBottom;
r.setTop( r.top() + d_data->titleOffset );
break;
case QwtScaleDraw::TopScale:
default:
angle = 0.0;
flags |= Qt::AlignTop;
r.setBottom( r.bottom() - d_data->titleOffset );
break;
}
if ( d_data->layoutFlags & TitleInverted )
{
if ( align == QwtScaleDraw::LeftScale
|| align == QwtScaleDraw::RightScale )
{
angle = -angle;
r.setRect( r.x() + r.height(), r.y() - r.width(),
r.width(), r.height() );
}
painter->setFont( font() );
painter->setPen( palette().color( QPalette::Text ) );
painter->translate( r.x(), r.y() );
if ( angle != 0.0 )
painter->rotate( angle );
title.setRenderFlags( flags );
title.draw( painter, QRectF( 0.0, 0.0, r.width(), r.height() ) );
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
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 += qMax( 0, d_data->borderDist[0] - mbd1 );
length += qMax( 0, d_data->borderDist[1] - mbd2 );
length += d_data->scaleDraw->minLength( font() );
int dim = dimForLength( length, font() );
if ( length < dim )
{
int left, right, top, bottom;
getContentsMargins( &left, &top, &right, &bottom );
return size + QSize( left + right, top + bottom );
}
/*!
\brief Find the height of the title for a given width.
\param width Width
\return height Height
*/
return qCeil( 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
const int extent = qCeil( d_data->scaleDraw->extent( scaleFont ) );
int dim = d_data->margin + extent + 1;
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.
\param start Return parameter for the border width at
the beginning of the scale
\param end Return parameter for the border width at the
end of the scale
\warning
<ul> <li>The minimum border distance depends on the font.</ul>
\sa setMinBorderDist(), getMinBorderDist(), setBorderDist()
*/
void QwtScaleWidget::getBorderDistHint( int &start, int &end ) const
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
are "jumping", when the tick labels or their positions change
\param start Minimum for the start border
\param end Minimum for the end border
{
d_data->minBorderDist[0] = start;
d_data->minBorderDist[1] = end;
}
/*!
Get the minimum value for the distances of the scale's endpoints from
\param start Return parameter for the border width at
the beginning of the scale
\param end Return parameter for the border width at the
end of the scale
void QwtScaleWidget::getMinBorderDist( int &start, int &end ) const
{
start = d_data->minBorderDist[0];
end = d_data->minBorderDist[1];
}
/*!
\brief Assign a scale division
The scale division determines where to set the tick marks.
\param scaleDiv Scale Division
\sa For more information about scale divisions, see QwtScaleDiv.
*/
void QwtScaleWidget::setScaleDiv( const QwtScaleDiv &scaleDiv )
if ( sd->scaleDiv() != scaleDiv )
{
sd->setScaleDiv( scaleDiv );
/*!
Set the transformation
\param transformation Transformation
\sa QwtAbstractScaleDraw::scaleDraw(), QwtScaleMap
*/
void QwtScaleWidget::setTransformation( QwtTransform *transformation )
d_data->scaleDraw->setTransformation( transformation );
layoutScale();
}
/*!
En/disable a color bar associated to the scale
\sa isColorBarEnabled(), setColorBarWidth()
*/
void QwtScaleWidget::setColorBarEnabled( bool on )
{
if ( on != d_data->colorBar.isEnabled )
{
d_data->colorBar.isEnabled = on;
layoutScale();
}
}
/*!
\return true, when the color bar is enabled
\sa setColorBarEnabled(), setColorBarWidth()
*/
bool QwtScaleWidget::isColorBarEnabled() const
{
return d_data->colorBar.isEnabled;
}
\param width Width
\sa colorBarWidth(), setColorBarEnabled()
*/
void QwtScaleWidget::setColorBarWidth( int width )
d_data->colorBar.width = width;
if ( isColorBarEnabled() )
layoutScale();
}
}
/*!
\return Width of the color bar
\sa setColorBarEnabled(), setColorBarEnabled()
*/
int QwtScaleWidget::colorBarWidth() const
{
return d_data->colorBar.width;
}
/*!
\return Value interval for the color bar
\sa setColorMap(), colorMap()
*/
QwtInterval QwtScaleWidget::colorBarInterval() const
/*!
Set the color map and value interval, that are used for displaying
the color bar.
\param interval Value interval
\param colorMap Color map
\sa colorMap(), colorBarInterval()
*/
void QwtScaleWidget::setColorMap(
const QwtInterval &interval, QwtColorMap *colorMap )
if ( colorMap != d_data->colorBar.colorMap )
{
delete d_data->colorBar.colorMap;
d_data->colorBar.colorMap = colorMap;
}
/*!
\return Color map
\sa setColorMap(), colorBarInterval()
*/
const QwtColorMap *QwtScaleWidget::colorMap() const