AVT相机arm版本SDK

This commit is contained in:
zhangpeng
2025-04-30 09:26:04 +08:00
parent 837c870f18
commit 78a1c63a95
705 changed files with 148770 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_H
#define QWT_H
#include "qwt_global.h"
/*!
Some constants for use within Qwt.
*/
namespace Qwt
{
}
#endif

View File

@@ -0,0 +1,38 @@
/* -*- 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_abstract_legend.h"
/*!
Constructor
\param parent Parent widget
*/
QwtAbstractLegend::QwtAbstractLegend( QWidget *parent ):
QFrame( parent )
{
}
//! Destructor
QwtAbstractLegend::~QwtAbstractLegend()
{
}
/*!
Return the extent, that is needed for elements to scroll
the legend ( usually scrollbars ),
\param orientation Orientation
\return Extent of the corresponding scroll element
*/
int QwtAbstractLegend::scrollExtent( Qt::Orientation orientation ) const
{
Q_UNUSED( orientation );
return 0;
}

View File

@@ -0,0 +1,71 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ABSTRACT_LEGEND_H
#define QWT_ABSTRACT_LEGEND_H
#include "qwt_global.h"
#include "qwt_legend_data.h"
#include <qframe.h>
#include <qlist.h>
class QVariant;
/*!
\brief Abstract base class for legend widgets
Legends, that need to be under control of the QwtPlot layout system
need to be derived from QwtAbstractLegend.
\note Other type of legends can be implemented by connecting to
the QwtPlot::legendDataChanged() signal. But as these legends
are unknown to the plot layout system the layout code
( on screen and for QwtPlotRenderer ) need to be organized
in application code.
\sa QwtLegend
*/
class QWT_EXPORT QwtAbstractLegend : public QFrame
{
Q_OBJECT
public:
explicit QwtAbstractLegend( QWidget *parent = NULL );
virtual ~QwtAbstractLegend();
/*!
Render the legend into a given rectangle.
\param painter Painter
\param rect Bounding rectangle
\param fillBackground When true, fill rect with the widget background
\sa renderLegend() is used by QwtPlotRenderer
*/
virtual void renderLegend( QPainter *painter,
const QRectF &rect, bool fillBackground ) const = 0;
//! \return True, when no plot item is inserted
virtual bool isEmpty() const = 0;
virtual int scrollExtent( Qt::Orientation ) const;
public Q_SLOTS:
/*!
\brief Update the entries for a plot item
\param itemInfo Info about an item
\param data List of legend entry attributes for the item
*/
virtual void updateLegend( const QVariant &itemInfo,
const QList<QwtLegendData> &data ) = 0;
};
#endif

View File

@@ -0,0 +1,449 @@
/* -*- 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_abstract_scale.h"
#include "qwt_scale_engine.h"
#include "qwt_scale_draw.h"
#include "qwt_scale_div.h"
#include "qwt_scale_map.h"
#include "qwt_interval.h"
class QwtAbstractScale::PrivateData
{
public:
PrivateData():
maxMajor( 5 ),
maxMinor( 3 ),
stepSize( 0.0 )
{
scaleEngine = new QwtLinearScaleEngine();
scaleDraw = new QwtScaleDraw();
}
~PrivateData()
{
delete scaleEngine;
delete scaleDraw;
}
QwtScaleEngine *scaleEngine;
QwtAbstractScaleDraw *scaleDraw;
int maxMajor;
int maxMinor;
double stepSize;
};
/*!
Constructor
\param parent Parent widget
Creates a default QwtScaleDraw and a QwtLinearScaleEngine.
The initial scale boundaries are set to [ 0.0, 100.0 ]
The scaleStepSize() is initialized to 0.0, scaleMaxMajor() to 5
and scaleMaxMajor to 3.
*/
QwtAbstractScale::QwtAbstractScale( QWidget *parent ):
QWidget( parent )
{
d_data = new PrivateData;
rescale( 0.0, 100.0, d_data->stepSize );
}
//! Destructor
QwtAbstractScale::~QwtAbstractScale()
{
delete d_data;
}
/*!
Set the lower bound of the scale
\param value Lower bound
\sa lowerBound(), setScale(), setUpperBound()
\note For inverted scales the lower bound
is greater than the upper bound
*/
void QwtAbstractScale::setLowerBound( double value )
{
setScale( value, upperBound() );
}
/*!
\return Lower bound of the scale
\sa setLowerBound(), setScale(), upperBound()
*/
double QwtAbstractScale::lowerBound() const
{
return d_data->scaleDraw->scaleDiv().lowerBound();
}
/*!
Set the upper bound of the scale
\param value Upper bound
\sa upperBound(), setScale(), setLowerBound()
\note For inverted scales the lower bound
is greater than the upper bound
*/
void QwtAbstractScale::setUpperBound( double value )
{
setScale( lowerBound(), value );
}
/*!
\return Upper bound of the scale
\sa setUpperBound(), setScale(), lowerBound()
*/
double QwtAbstractScale::upperBound() const
{
return d_data->scaleDraw->scaleDiv().upperBound();
}
/*!
\brief Specify a scale.
Define a scale by an interval
The ticks are calculated using scaleMaxMinor(),
scaleMaxMajor() and scaleStepSize().
\param lowerBound lower limit of the scale interval
\param upperBound upper limit of the scale interval
\note For inverted scales the lower bound
is greater than the upper bound
*/
void QwtAbstractScale::setScale( double lowerBound, double upperBound )
{
rescale( lowerBound, upperBound, d_data->stepSize );
}
/*!
\brief Specify a scale.
Define a scale by an interval
The ticks are calculated using scaleMaxMinor(),
scaleMaxMajor() and scaleStepSize().
\param interval Interval
*/
void QwtAbstractScale::setScale( const QwtInterval &interval )
{
setScale( interval.minValue(), interval.maxValue() );
}
/*!
\brief Specify a scale.
scaleMaxMinor(), scaleMaxMajor() and scaleStepSize() and have no effect.
\param scaleDiv Scale division
\sa setAutoScale()
*/
void QwtAbstractScale::setScale( const QwtScaleDiv &scaleDiv )
{
if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
{
#if 1
if ( d_data->scaleEngine )
{
d_data->scaleDraw->setTransformation(
d_data->scaleEngine->transformation() );
}
#endif
d_data->scaleDraw->setScaleDiv( scaleDiv );
scaleChange();
}
}
/*!
\brief Set the maximum number of major tick intervals.
The scale's major ticks are calculated automatically such that
the number of major intervals does not exceed ticks.
The default value is 5.
\param ticks Maximal number of major ticks.
\sa scaleMaxMajor(), setScaleMaxMinor(),
setScaleStepSize(), QwtScaleEngine::divideInterval()
*/
void QwtAbstractScale::setScaleMaxMajor( int ticks )
{
if ( ticks != d_data->maxMajor )
{
d_data->maxMajor = ticks;
updateScaleDraw();
}
}
/*!
\return Maximal number of major tick intervals
\sa setScaleMaxMajor(), scaleMaxMinor()
*/
int QwtAbstractScale::scaleMaxMajor() const
{
return d_data->maxMajor;
}
/*!
\brief Set the maximum number of minor tick intervals
The scale's minor ticks are calculated automatically such that
the number of minor intervals does not exceed ticks.
The default value is 3.
\param ticks Maximal number of minor ticks.
\sa scaleMaxMajor(), setScaleMaxMinor(),
setScaleStepSize(), QwtScaleEngine::divideInterval()
*/
void QwtAbstractScale::setScaleMaxMinor( int ticks )
{
if ( ticks != d_data->maxMinor )
{
d_data->maxMinor = ticks;
updateScaleDraw();
}
}
/*!
\return Maximal number of minor tick intervals
\sa setScaleMaxMinor(), scaleMaxMajor()
*/
int QwtAbstractScale::scaleMaxMinor() const
{
return d_data->maxMinor;
}
/*!
\brief Set the step size used for calculating a scale division
The step size is hint for calculating the intervals for
the major ticks of the scale. A value of 0.0 is interpreted
as no hint.
\param stepSize Hint for the step size of the scale
\sa scaleStepSize(), QwtScaleEngine::divideScale()
\note Position and distance between the major ticks also
depends on scaleMaxMajor().
*/
void QwtAbstractScale::setScaleStepSize( double stepSize )
{
if ( stepSize != d_data->stepSize )
{
d_data->stepSize = stepSize;
updateScaleDraw();
}
}
/*!
\return Hint for the step size of the scale
\sa setScaleStepSize(), QwtScaleEngine::divideScale()
*/
double QwtAbstractScale::scaleStepSize() const
{
return d_data->stepSize;
}
/*!
\brief Set a scale draw
scaleDraw has to be created with new and will be deleted in
the destructor or the next call of setAbstractScaleDraw().
\sa abstractScaleDraw()
*/
void QwtAbstractScale::setAbstractScaleDraw( QwtAbstractScaleDraw *scaleDraw )
{
if ( scaleDraw == NULL || scaleDraw == d_data->scaleDraw )
return;
if ( d_data->scaleDraw != NULL )
scaleDraw->setScaleDiv( d_data->scaleDraw->scaleDiv() );
delete d_data->scaleDraw;
d_data->scaleDraw = scaleDraw;
}
/*!
\return Scale draw
\sa setAbstractScaleDraw()
*/
QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw()
{
return d_data->scaleDraw;
}
/*!
\return Scale draw
\sa setAbstractScaleDraw()
*/
const QwtAbstractScaleDraw *QwtAbstractScale::abstractScaleDraw() const
{
return d_data->scaleDraw;
}
/*!
\brief Set a scale engine
The scale engine is responsible for calculating the scale division
and provides a transformation between scale and widget coordinates.
scaleEngine has to be created with new and will be deleted in
the destructor or the next call of setScaleEngine.
*/
void QwtAbstractScale::setScaleEngine( QwtScaleEngine *scaleEngine )
{
if ( scaleEngine != NULL && scaleEngine != d_data->scaleEngine )
{
delete d_data->scaleEngine;
d_data->scaleEngine = scaleEngine;
}
}
/*!
\return Scale engine
\sa setScaleEngine()
*/
const QwtScaleEngine *QwtAbstractScale::scaleEngine() const
{
return d_data->scaleEngine;
}
/*!
\return Scale engine
\sa setScaleEngine()
*/
QwtScaleEngine *QwtAbstractScale::scaleEngine()
{
return d_data->scaleEngine;
}
/*!
\return Scale boundaries and positions of the ticks
The scale division might have been assigned explicitly
or calculated implicitly by rescale().
*/
const QwtScaleDiv &QwtAbstractScale::scaleDiv() const
{
return d_data->scaleDraw->scaleDiv();
}
/*!
\return Map to translate between scale and widget coordinates
*/
const QwtScaleMap &QwtAbstractScale::scaleMap() const
{
return d_data->scaleDraw->scaleMap();
}
/*!
Translate a scale value into a widget coordinate
\param value Scale value
\return Corresponding widget coordinate for value
\sa scaleMap(), invTransform()
*/
int QwtAbstractScale::transform( double value ) const
{
return qRound( d_data->scaleDraw->scaleMap().transform( value ) );
}
/*!
Translate a widget coordinate into a scale value
\param value Widget coordinate
\return Corresponding scale coordinate for value
\sa scaleMap(), transform()
*/
double QwtAbstractScale::invTransform( int value ) const
{
return d_data->scaleDraw->scaleMap().invTransform( value );
}
/*!
\return True, when the scale is increasing in opposite direction
to the widget coordinates
*/
bool QwtAbstractScale::isInverted() const
{
return d_data->scaleDraw->scaleMap().isInverting();
}
/*!
\return The boundary with the smaller value
\sa maximum(), lowerBound(), upperBound()
*/
double QwtAbstractScale::minimum() const
{
return qMin( d_data->scaleDraw->scaleDiv().lowerBound(),
d_data->scaleDraw->scaleDiv().upperBound() );
}
/*!
\return The boundary with the larger value
\sa minimum(), lowerBound(), upperBound()
*/
double QwtAbstractScale::maximum() const
{
return qMax( d_data->scaleDraw->scaleDiv().lowerBound(),
d_data->scaleDraw->scaleDiv().upperBound() );
}
//! Notify changed scale
void QwtAbstractScale::scaleChange()
{
}
/*!
Recalculate the scale division and update the scale.
\param lowerBound Lower limit of the scale interval
\param upperBound Upper limit of the scale interval
\param stepSize Major step size
\sa scaleChange()
*/
void QwtAbstractScale::rescale(
double lowerBound, double upperBound, double stepSize )
{
const QwtScaleDiv scaleDiv = d_data->scaleEngine->divideScale(
lowerBound, upperBound, d_data->maxMajor, d_data->maxMinor, stepSize );
if ( scaleDiv != d_data->scaleDraw->scaleDiv() )
{
#if 1
d_data->scaleDraw->setTransformation(
d_data->scaleEngine->transformation() );
#endif
d_data->scaleDraw->setScaleDiv( scaleDiv );
scaleChange();
}
}
void QwtAbstractScale::updateScaleDraw()
{
rescale( d_data->scaleDraw->scaleDiv().lowerBound(),
d_data->scaleDraw->scaleDiv().upperBound(), d_data->stepSize );
}

View File

@@ -0,0 +1,105 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ABSTRACT_SCALE_H
#define QWT_ABSTRACT_SCALE_H
#include "qwt_global.h"
#include <qwidget.h>
class QwtScaleEngine;
class QwtAbstractScaleDraw;
class QwtScaleDiv;
class QwtScaleMap;
class QwtInterval;
/*!
\brief An abstract base class for widgets having a scale
The scale of an QwtAbstractScale is determined by a QwtScaleDiv
definition, that contains the boundaries and the ticks of the scale.
The scale is painted using a QwtScaleDraw object.
The scale division might be assigned explicitly - but usually
it is calculated from the boundaries using a QwtScaleEngine.
The scale engine also decides the type of transformation of the scale
( linear, logarithmic ... ).
*/
class QWT_EXPORT QwtAbstractScale: public QWidget
{
Q_OBJECT
Q_PROPERTY( double lowerBound READ lowerBound WRITE setLowerBound )
Q_PROPERTY( double upperBound READ upperBound WRITE setUpperBound )
Q_PROPERTY( int scaleMaxMajor READ scaleMaxMajor WRITE setScaleMaxMajor )
Q_PROPERTY( int scaleMaxMinor READ scaleMaxMinor WRITE setScaleMaxMinor )
Q_PROPERTY( double scaleStepSize READ scaleStepSize WRITE setScaleStepSize )
public:
QwtAbstractScale( QWidget *parent = NULL );
virtual ~QwtAbstractScale();
void setScale( double lowerBound, double upperBound );
void setScale( const QwtInterval & );
void setScale( const QwtScaleDiv & );
const QwtScaleDiv& scaleDiv() const;
void setLowerBound( double value );
double lowerBound() const;
void setUpperBound( double value );
double upperBound() const;
void setScaleStepSize( double stepSize );
double scaleStepSize() const;
void setScaleMaxMajor( int ticks );
int scaleMaxMinor() const;
void setScaleMaxMinor( int ticks );
int scaleMaxMajor() const;
void setScaleEngine( QwtScaleEngine * );
const QwtScaleEngine *scaleEngine() const;
QwtScaleEngine *scaleEngine();
int transform( double ) const;
double invTransform( int ) const;
bool isInverted() const;
double minimum() const;
double maximum() const;
const QwtScaleMap &scaleMap() const;
protected:
void rescale( double lowerBound,
double upperBound, double stepSize );
void setAbstractScaleDraw( QwtAbstractScaleDraw * );
const QwtAbstractScaleDraw *abstractScaleDraw() const;
QwtAbstractScaleDraw *abstractScaleDraw();
virtual void scaleChange();
private:
void updateScaleDraw();
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,420 @@
/* -*- 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_abstract_scale_draw.h"
#include "qwt_math.h"
#include "qwt_text.h"
#include "qwt_painter.h"
#include "qwt_scale_map.h"
#include <qpainter.h>
#include <qpalette.h>
#include <qmap.h>
#include <qlocale.h>
class QwtAbstractScaleDraw::PrivateData
{
public:
PrivateData():
spacing( 4.0 ),
penWidth( 0 ),
minExtent( 0.0 )
{
components = QwtAbstractScaleDraw::Backbone
| QwtAbstractScaleDraw::Ticks
| QwtAbstractScaleDraw::Labels;
tickLength[QwtScaleDiv::MinorTick] = 4.0;
tickLength[QwtScaleDiv::MediumTick] = 6.0;
tickLength[QwtScaleDiv::MajorTick] = 8.0;
}
ScaleComponents components;
QwtScaleMap map;
QwtScaleDiv scaleDiv;
double spacing;
double tickLength[QwtScaleDiv::NTickTypes];
int penWidth;
double minExtent;
QMap<double, QwtText> labelCache;
};
/*!
\brief Constructor
The range of the scale is initialized to [0, 100],
The spacing (distance between ticks and labels) is
set to 4, the tick lengths are set to 4,6 and 8 pixels
*/
QwtAbstractScaleDraw::QwtAbstractScaleDraw()
{
d_data = new QwtAbstractScaleDraw::PrivateData;
}
//! Destructor
QwtAbstractScaleDraw::~QwtAbstractScaleDraw()
{
delete d_data;
}
/*!
En/Disable a component of the scale
\param component Scale component
\param enable On/Off
\sa hasComponent()
*/
void QwtAbstractScaleDraw::enableComponent(
ScaleComponent component, bool enable )
{
if ( enable )
d_data->components |= component;
else
d_data->components &= ~component;
}
/*!
Check if a component is enabled
\param component Component type
\return true, when component is enabled
\sa enableComponent()
*/
bool QwtAbstractScaleDraw::hasComponent( ScaleComponent component ) const
{
return ( d_data->components & component );
}
/*!
Change the scale division
\param scaleDiv New scale division
*/
void QwtAbstractScaleDraw::setScaleDiv( const QwtScaleDiv &scaleDiv )
{
d_data->scaleDiv = scaleDiv;
d_data->map.setScaleInterval( scaleDiv.lowerBound(), scaleDiv.upperBound() );
d_data->labelCache.clear();
}
/*!
Change the transformation of the scale
\param transformation New scale transformation
*/
void QwtAbstractScaleDraw::setTransformation(
QwtTransform *transformation )
{
d_data->map.setTransformation( transformation );
}
//! \return Map how to translate between scale and pixel values
const QwtScaleMap &QwtAbstractScaleDraw::scaleMap() const
{
return d_data->map;
}
//! \return Map how to translate between scale and pixel values
QwtScaleMap &QwtAbstractScaleDraw::scaleMap()
{
return d_data->map;
}
//! \return scale division
const QwtScaleDiv& QwtAbstractScaleDraw::scaleDiv() const
{
return d_data->scaleDiv;
}
/*!
\brief Specify the width of the scale pen
\param width Pen width
\sa penWidth()
*/
void QwtAbstractScaleDraw::setPenWidth( int width )
{
if ( width < 0 )
width = 0;
if ( width != d_data->penWidth )
d_data->penWidth = width;
}
/*!
\return Scale pen width
\sa setPenWidth()
*/
int QwtAbstractScaleDraw::penWidth() const
{
return d_data->penWidth;
}
/*!
\brief Draw the scale
\param painter The painter
\param palette Palette, text color is used for the labels,
foreground color for ticks and backbone
*/
void QwtAbstractScaleDraw::draw( QPainter *painter,
const QPalette& palette ) const
{
painter->save();
QPen pen = painter->pen();
pen.setWidth( d_data->penWidth );
pen.setCosmetic( false );
painter->setPen( pen );
if ( hasComponent( QwtAbstractScaleDraw::Labels ) )
{
painter->save();
painter->setPen( palette.color( QPalette::Text ) ); // ignore pen style
const QList<double> &majorTicks =
d_data->scaleDiv.ticks( QwtScaleDiv::MajorTick );
for ( int i = 0; i < majorTicks.count(); i++ )
{
const double v = majorTicks[i];
if ( d_data->scaleDiv.contains( v ) )
drawLabel( painter, v );
}
painter->restore();
}
if ( hasComponent( QwtAbstractScaleDraw::Ticks ) )
{
painter->save();
QPen pen = painter->pen();
pen.setColor( palette.color( QPalette::WindowText ) );
pen.setCapStyle( Qt::FlatCap );
painter->setPen( pen );
for ( int tickType = QwtScaleDiv::MinorTick;
tickType < QwtScaleDiv::NTickTypes; tickType++ )
{
const double tickLen = d_data->tickLength[tickType];
if ( tickLen <= 0.0 )
continue;
const QList<double> &ticks = d_data->scaleDiv.ticks( tickType );
for ( int i = 0; i < ticks.count(); i++ )
{
const double v = ticks[i];
if ( d_data->scaleDiv.contains( v ) )
drawTick( painter, v, tickLen );
}
}
painter->restore();
}
if ( hasComponent( QwtAbstractScaleDraw::Backbone ) )
{
painter->save();
QPen pen = painter->pen();
pen.setColor( palette.color( QPalette::WindowText ) );
pen.setCapStyle( Qt::FlatCap );
painter->setPen( pen );
drawBackbone( painter );
painter->restore();
}
painter->restore();
}
/*!
\brief Set the spacing between tick and labels
The spacing is the distance between ticks and labels.
The default spacing is 4 pixels.
\param spacing Spacing
\sa spacing()
*/
void QwtAbstractScaleDraw::setSpacing( double spacing )
{
if ( spacing < 0 )
spacing = 0;
d_data->spacing = spacing;
}
/*!
\brief Get the spacing
The spacing is the distance between ticks and labels.
The default spacing is 4 pixels.
\return Spacing
\sa setSpacing()
*/
double QwtAbstractScaleDraw::spacing() const
{
return d_data->spacing;
}
/*!
\brief Set a minimum for the extent
The extent is calculated from the components of the
scale draw. In situations, where the labels are
changing and the layout depends on the extent (f.e scrolling
a scale), setting an upper limit as minimum extent will
avoid jumps of the layout.
\param minExtent Minimum extent
\sa extent(), minimumExtent()
*/
void QwtAbstractScaleDraw::setMinimumExtent( double minExtent )
{
if ( minExtent < 0.0 )
minExtent = 0.0;
d_data->minExtent = minExtent;
}
/*!
Get the minimum extent
\return Minimum extent
\sa extent(), setMinimumExtent()
*/
double QwtAbstractScaleDraw::minimumExtent() const
{
return d_data->minExtent;
}
/*!
Set the length of the ticks
\param tickType Tick type
\param length New length
\warning the length is limited to [0..1000]
*/
void QwtAbstractScaleDraw::setTickLength(
QwtScaleDiv::TickType tickType, double length )
{
if ( tickType < QwtScaleDiv::MinorTick ||
tickType > QwtScaleDiv::MajorTick )
{
return;
}
if ( length < 0.0 )
length = 0.0;
const double maxTickLen = 1000.0;
if ( length > maxTickLen )
length = maxTickLen;
d_data->tickLength[tickType] = length;
}
/*!
\return Length of the ticks
\sa setTickLength(), maxTickLength()
*/
double QwtAbstractScaleDraw::tickLength( QwtScaleDiv::TickType tickType ) const
{
if ( tickType < QwtScaleDiv::MinorTick ||
tickType > QwtScaleDiv::MajorTick )
{
return 0;
}
return d_data->tickLength[tickType];
}
/*!
\return Length of the longest tick
Useful for layout calculations
\sa tickLength(), setTickLength()
*/
double QwtAbstractScaleDraw::maxTickLength() const
{
double length = 0.0;
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
length = qMax( length, d_data->tickLength[i] );
return length;
}
/*!
\brief Convert a value into its representing label
The value is converted to a plain text using
QLocale().toString(value).
This method is often overloaded by applications to have individual
labels.
\param value Value
\return Label string.
*/
QwtText QwtAbstractScaleDraw::label( double value ) const
{
return QLocale().toString( value );
}
/*!
\brief Convert a value into its representing label and cache it.
The conversion between value and label is called very often
in the layout and painting code. Unfortunately the
calculation of the label sizes might be slow (really slow
for rich text in Qt4), so it's necessary to cache the labels.
\param font Font
\param value Value
\return Tick label
*/
const QwtText &QwtAbstractScaleDraw::tickLabel(
const QFont &font, double value ) const
{
QMap<double, QwtText>::const_iterator it = d_data->labelCache.find( value );
if ( it == d_data->labelCache.end() )
{
QwtText lbl = label( value );
lbl.setRenderFlags( 0 );
lbl.setLayoutAttribute( QwtText::MinimumLayout );
( void )lbl.textSize( font ); // initialize the internal cache
it = d_data->labelCache.insert( value, lbl );
}
return ( *it );
}
/*!
Invalidate the cache used by tickLabel()
The cache is invalidated, when a new QwtScaleDiv is set. If
the labels need to be changed. while the same QwtScaleDiv is set,
invalidateCache() needs to be called manually.
*/
void QwtAbstractScaleDraw::invalidateCache()
{
d_data->labelCache.clear();
}

View File

@@ -0,0 +1,141 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ABSTRACT_SCALE_DRAW_H
#define QWT_ABSTRACT_SCALE_DRAW_H
#include "qwt_global.h"
#include "qwt_scale_div.h"
#include "qwt_text.h"
class QPalette;
class QPainter;
class QFont;
class QwtTransform;
class QwtScaleMap;
/*!
\brief A abstract base class for drawing scales
QwtAbstractScaleDraw can be used to draw linear or logarithmic scales.
After a scale division has been specified as a QwtScaleDiv object
using setScaleDiv(), the scale can be drawn with the draw() member.
*/
class QWT_EXPORT QwtAbstractScaleDraw
{
public:
/*!
Components of a scale
\sa enableComponent(), hasComponent
*/
enum ScaleComponent
{
//! Backbone = the line where the ticks are located
Backbone = 0x01,
//! Ticks
Ticks = 0x02,
//! Labels
Labels = 0x04
};
//! Scale components
typedef QFlags<ScaleComponent> ScaleComponents;
QwtAbstractScaleDraw();
virtual ~QwtAbstractScaleDraw();
void setScaleDiv( const QwtScaleDiv &s );
const QwtScaleDiv& scaleDiv() const;
void setTransformation( QwtTransform * );
const QwtScaleMap &scaleMap() const;
QwtScaleMap &scaleMap();
void enableComponent( ScaleComponent, bool enable = true );
bool hasComponent( ScaleComponent ) const;
void setTickLength( QwtScaleDiv::TickType, double length );
double tickLength( QwtScaleDiv::TickType ) const;
double maxTickLength() const;
void setSpacing( double margin );
double spacing() const;
void setPenWidth( int width );
int penWidth() const;
virtual void draw( QPainter *, const QPalette & ) const;
virtual QwtText label( double ) const;
/*!
Calculate the extent
The extent is the distance from the baseline to the outermost
pixel of the scale draw in opposite to its orientation.
It is at least minimumExtent() pixels.
\param font Font used for drawing the tick labels
\return Number of pixels
\sa setMinimumExtent(), minimumExtent()
*/
virtual double extent( const QFont &font ) const = 0;
void setMinimumExtent( double );
double minimumExtent() const;
protected:
/*!
Draw a tick
\param painter Painter
\param value Value of the tick
\param len Length of the tick
\sa drawBackbone(), drawLabel()
*/
virtual void drawTick( QPainter *painter, double value, double len ) const = 0;
/*!
Draws the baseline of the scale
\param painter Painter
\sa drawTick(), drawLabel()
*/
virtual void drawBackbone( QPainter *painter ) const = 0;
/*!
Draws the label for a major scale tick
\param painter Painter
\param value Value
\sa drawTick(), drawBackbone()
*/
virtual void drawLabel( QPainter *painter, double value ) const = 0;
void invalidateCache();
const QwtText &tickLabel( const QFont &, double value ) const;
private:
QwtAbstractScaleDraw( const QwtAbstractScaleDraw & );
QwtAbstractScaleDraw &operator=( const QwtAbstractScaleDraw & );
class PrivateData;
PrivateData *d_data;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtAbstractScaleDraw::ScaleComponents )
#endif

View File

@@ -0,0 +1,822 @@
/* -*- 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_abstract_slider.h"
#include "qwt_abstract_scale_draw.h"
#include "qwt_math.h"
#include "qwt_scale_map.h"
#include <qevent.h>
#if QT_VERSION < 0x040601
#define qFabs(x) ::fabs(x)
#endif
static double qwtAlignToScaleDiv(
const QwtAbstractSlider *slider, double value )
{
const QwtScaleDiv &sd = slider->scaleDiv();
const int tValue = slider->transform( value );
if ( tValue == slider->transform( sd.lowerBound() ) )
return sd.lowerBound();
if ( tValue == slider->transform( sd.lowerBound() ) )
return sd.upperBound();
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
{
const QList<double> ticks = sd.ticks( i );
for ( int j = 0; j < ticks.size(); j++ )
{
if ( slider->transform( ticks[ j ] ) == tValue )
return ticks[ j ];
}
}
return value;
}
class QwtAbstractSlider::PrivateData
{
public:
PrivateData():
isScrolling( false ),
isTracking( true ),
pendingValueChanged( false ),
readOnly( false ),
totalSteps( 100 ),
singleSteps( 1 ),
pageSteps( 10 ),
stepAlignment( true ),
isValid( false ),
value( 0.0 ),
wrapping( false ),
invertedControls( false )
{
}
bool isScrolling;
bool isTracking;
bool pendingValueChanged;
bool readOnly;
uint totalSteps;
uint singleSteps;
uint pageSteps;
bool stepAlignment;
bool isValid;
double value;
bool wrapping;
bool invertedControls;
};
/*!
\brief Constructor
The scale is initialized to [0.0, 100.0], the
number of steps is set to 100 with 1 and 10 and single
an page step sizes. Step alignment is enabled.
The initial value is invalid.
\param parent Parent widget
*/
QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
QwtAbstractScale( parent )
{
d_data = new QwtAbstractSlider::PrivateData;
setScale( 0.0, 100.0 );
setFocusPolicy( Qt::StrongFocus );
}
//! Destructor
QwtAbstractSlider::~QwtAbstractSlider()
{
delete d_data;
}
/*!
Set the value to be valid/invalid
\param on When true, the value is invalidated
\sa setValue()
*/
void QwtAbstractSlider::setValid( bool on )
{
if ( on != d_data->isValid )
{
d_data->isValid = on;
sliderChange();
Q_EMIT valueChanged( d_data->value );
}
}
//! \return True, when the value is invalid
bool QwtAbstractSlider::isValid() const
{
return d_data->isValid;
}
/*!
En/Disable read only mode
In read only mode the slider can't be controlled by mouse
or keyboard.
\param on Enables in case of true
\sa isReadOnly()
\warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus
*/
void QwtAbstractSlider::setReadOnly( bool on )
{
if ( d_data->readOnly != on )
{
d_data->readOnly = on;
setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
update();
}
}
/*!
In read only mode the slider can't be controlled by mouse
or keyboard.
\return true if read only
\sa setReadOnly()
*/
bool QwtAbstractSlider::isReadOnly() const
{
return d_data->readOnly;
}
/*!
\brief Enables or disables tracking.
If tracking is enabled, the slider emits the valueChanged()
signal while the movable part of the slider is being dragged.
If tracking is disabled, the slider emits the valueChanged() signal
only when the user releases the slider.
Tracking is enabled by default.
\param on \c true (enable) or \c false (disable) tracking.
\sa isTracking(), sliderMoved()
*/
void QwtAbstractSlider::setTracking( bool on )
{
d_data->isTracking = on;
}
/*!
\return True, when tracking has been enabled
\sa setTracking()
*/
bool QwtAbstractSlider::isTracking() const
{
return d_data->isTracking;
}
/*!
Mouse press event handler
\param event Mouse event
*/
void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
{
if ( isReadOnly() )
{
event->ignore();
return;
}
if ( !d_data->isValid || lowerBound() == upperBound() )
return;
d_data->isScrolling = isScrollPosition( event->pos() );
if ( d_data->isScrolling )
{
d_data->pendingValueChanged = false;
Q_EMIT sliderPressed();
}
}
/*!
Mouse Move Event handler
\param event Mouse event
*/
void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
{
if ( isReadOnly() )
{
event->ignore();
return;
}
if ( d_data->isValid && d_data->isScrolling )
{
double value = scrolledTo( event->pos() );
if ( value != d_data->value )
{
value = boundedValue( value );
if ( d_data->stepAlignment )
{
value = alignedValue( value );
}
else
{
value = qwtAlignToScaleDiv( this, value );
}
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
Q_EMIT sliderMoved( d_data->value );
if ( d_data->isTracking )
Q_EMIT valueChanged( d_data->value );
else
d_data->pendingValueChanged = true;
}
}
}
}
/*!
Mouse Release Event handler
\param event Mouse event
*/
void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
{
if ( isReadOnly() )
{
event->ignore();
return;
}
if ( d_data->isScrolling && d_data->isValid )
{
d_data->isScrolling = false;
if ( d_data->pendingValueChanged )
Q_EMIT valueChanged( d_data->value );
Q_EMIT sliderReleased();
}
}
/*!
Wheel Event handler
In/decreases the value by s number of steps. The direction
depends on the invertedControls() property.
When the control or shift modifier is pressed the wheel delta
( divided by 120 ) is mapped to an increment according to
pageSteps(). Otherwise it is mapped to singleSteps().
\param event Wheel event
*/
void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
{
if ( isReadOnly() )
{
event->ignore();
return;
}
if ( !d_data->isValid || d_data->isScrolling )
return;
int numSteps = 0;
if ( ( event->modifiers() & Qt::ControlModifier) ||
( event->modifiers() & Qt::ShiftModifier ) )
{
// one page regardless of delta
numSteps = d_data->pageSteps;
if ( event->delta() < 0 )
numSteps = -numSteps;
}
else
{
const int numTurns = ( event->delta() / 120 );
numSteps = numTurns * d_data->singleSteps;
}
if ( d_data->invertedControls )
numSteps = -numSteps;
const double value = incrementedValue( d_data->value, numSteps );
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
Q_EMIT sliderMoved( d_data->value );
Q_EMIT valueChanged( d_data->value );
}
}
/*!
Handles key events
QwtAbstractSlider handles the following keys:
- Qt::Key_Left\n
Add/Subtract singleSteps() in direction to lowerBound();
- Qt::Key_Right\n
Add/Subtract singleSteps() in direction to upperBound();
- Qt::Key_Down\n
Subtract singleSteps(), when invertedControls() is false
- Qt::Key_Up\n
Add singleSteps(), when invertedControls() is false
- Qt::Key_PageDown\n
Subtract pageSteps(), when invertedControls() is false
- Qt::Key_PageUp\n
Add pageSteps(), when invertedControls() is false
- Qt::Key_Home\n
Set the value to the minimum()
- Qt::Key_End\n
Set the value to the maximum()
\param event Key event
\sa isReadOnly()
*/
void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
{
if ( isReadOnly() )
{
event->ignore();
return;
}
if ( !d_data->isValid || d_data->isScrolling )
return;
int numSteps = 0;
double value = d_data->value;
switch ( event->key() )
{
case Qt::Key_Left:
{
numSteps = -static_cast<int>( d_data->singleSteps );
if ( isInverted() )
numSteps = -numSteps;
break;
}
case Qt::Key_Right:
{
numSteps = d_data->singleSteps;
if ( isInverted() )
numSteps = -numSteps;
break;
}
case Qt::Key_Down:
{
numSteps = -static_cast<int>( d_data->singleSteps );
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_Up:
{
numSteps = d_data->singleSteps;
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_PageUp:
{
numSteps = d_data->pageSteps;
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_PageDown:
{
numSteps = -static_cast<int>( d_data->pageSteps );
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_Home:
{
value = minimum();
break;
}
case Qt::Key_End:
{
value = maximum();
break;
}
default:;
{
event->ignore();
}
}
if ( numSteps != 0 )
{
value = incrementedValue( d_data->value, numSteps );
}
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
Q_EMIT sliderMoved( d_data->value );
Q_EMIT valueChanged( d_data->value );
}
}
/*!
\brief Set the number of steps
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
The default setting is 100.
\param stepCount Number of steps
\sa totalSteps(), setSingleSteps(), setPageSteps()
*/
void QwtAbstractSlider::setTotalSteps( uint stepCount )
{
d_data->totalSteps = stepCount;
}
/*!
\return Number of steps
\sa setTotalSteps(), singleSteps(), pageSteps()
*/
uint QwtAbstractSlider::totalSteps() const
{
return d_data->totalSteps;
}
/*!
\brief Set the number of steps for a single increment
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
\param stepCount Number of steps
\sa singleSteps(), setTotalSteps(), setPageSteps()
*/
void QwtAbstractSlider::setSingleSteps( uint stepCount )
{
d_data->singleSteps = stepCount;
}
/*!
\return Number of steps
\sa setSingleSteps(), totalSteps(), pageSteps()
*/
uint QwtAbstractSlider::singleSteps() const
{
return d_data->singleSteps;
}
/*!
\brief Set the number of steps for a page increment
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
\param stepCount Number of steps
\sa pageSteps(), setTotalSteps(), setSingleSteps()
*/
void QwtAbstractSlider::setPageSteps( uint stepCount )
{
d_data->pageSteps = stepCount;
}
/*!
\return Number of steps
\sa setPageSteps(), totalSteps(), singleSteps()
*/
uint QwtAbstractSlider::pageSteps() const
{
return d_data->pageSteps;
}
/*!
\brief Enable step alignment
When step alignment is enabled values resulting from slider
movements are aligned to the step size.
\param on Enable step alignment when true
\sa stepAlignment()
*/
void QwtAbstractSlider::setStepAlignment( bool on )
{
if ( on != d_data->stepAlignment )
{
d_data->stepAlignment = on;
}
}
/*!
\return True, when step alignment is enabled
\sa setStepAlignment()
*/
bool QwtAbstractSlider::stepAlignment() const
{
return d_data->stepAlignment;
}
/*!
Set the slider to the specified value
\param value New value
\sa setValid(), sliderChange(), valueChanged()
*/
void QwtAbstractSlider::setValue( double value )
{
value = qBound( minimum(), value, maximum() );
const bool changed = ( d_data->value != value ) || !d_data->isValid;
d_data->value = value;
d_data->isValid = true;
if ( changed )
{
sliderChange();
Q_EMIT valueChanged( d_data->value );
}
}
//! Returns the current value.
double QwtAbstractSlider::value() const
{
return d_data->value;
}
/*!
If wrapping is true stepping up from upperBound() value will
take you to the minimum() value and vice versa.
\param on En/Disable wrapping
\sa wrapping()
*/
void QwtAbstractSlider::setWrapping( bool on )
{
d_data->wrapping = on;
}
/*!
\return True, when wrapping is set
\sa setWrapping()
*/
bool QwtAbstractSlider::wrapping() const
{
return d_data->wrapping;
}
/*!
Invert wheel and key events
Usually scrolling the mouse wheel "up" and using keys like page
up will increase the slider's value towards its maximum.
When invertedControls() is enabled the value is scrolled
towards its minimum.
Inverting the controls might be f.e. useful for a vertical slider
with an inverted scale ( decreasing from top to bottom ).
\param on Invert controls, when true
\sa invertedControls(), keyEvent(), wheelEvent()
*/
void QwtAbstractSlider::setInvertedControls( bool on )
{
d_data->invertedControls = on;
}
/*!
\return True, when the controls are inverted
\sa setInvertedControls()
*/
bool QwtAbstractSlider::invertedControls() const
{
return d_data->invertedControls;
}
/*!
Increment the slider
The step size depends on the number of totalSteps()
\param stepCount Number of steps
\sa setTotalSteps(), incrementedValue()
*/
void QwtAbstractSlider::incrementValue( int stepCount )
{
const double value = incrementedValue(
d_data->value, stepCount );
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
}
}
/*!
Increment a value
\param value Value
\param stepCount Number of steps
\return Incremented value
*/
double QwtAbstractSlider::incrementedValue(
double value, int stepCount ) const
{
if ( d_data->totalSteps == 0 )
return value;
const QwtTransform *transformation =
scaleMap().transformation();
if ( transformation == NULL )
{
const double range = maximum() - minimum();
value += stepCount * range / d_data->totalSteps;
}
else
{
QwtScaleMap map = scaleMap();
map.setPaintInterval( 0, d_data->totalSteps );
// we need equidant steps according to
// paint device coordinates
const double range = transformation->transform( maximum() )
- transformation->transform( minimum() );
const double stepSize = range / d_data->totalSteps;
double v = transformation->transform( value );
v = qRound( v / stepSize ) * stepSize;
v += stepCount * range / d_data->totalSteps;
value = transformation->invTransform( v );
}
value = boundedValue( value );
if ( d_data->stepAlignment )
value = alignedValue( value );
return value;
}
double QwtAbstractSlider::boundedValue( double value ) const
{
const double vmin = minimum();
const double vmax = maximum();
if ( d_data->wrapping && vmin != vmax )
{
const int fullCircle = 360 * 16;
const double pd = scaleMap().pDist();
if ( int( pd / fullCircle ) * fullCircle == pd )
{
// full circle scales: min and max are the same
const double range = vmax - vmin;
if ( value < vmin )
{
value += ::ceil( ( vmin - value ) / range ) * range;
}
else if ( value > vmax )
{
value -= ::ceil( ( value - vmax ) / range ) * range;
}
}
else
{
if ( value < vmin )
value = vmax;
else if ( value > vmax )
value = vmin;
}
}
else
{
value = qBound( vmin, value, vmax );
}
return value;
}
double QwtAbstractSlider::alignedValue( double value ) const
{
if ( d_data->totalSteps == 0 )
return value;
double stepSize;
if ( scaleMap().transformation() == NULL )
{
stepSize = ( maximum() - minimum() ) / d_data->totalSteps;
if ( stepSize > 0.0 )
{
value = lowerBound() +
qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
}
}
else
{
stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps;
if ( stepSize > 0.0 )
{
double v = scaleMap().transform( value );
v = scaleMap().p1() +
qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
value = scaleMap().invTransform( v );
}
}
if ( qAbs( stepSize ) > 1e-12 )
{
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
{
// correct rounding error if value = 0
value = 0.0;
}
else
{
// correct rounding error at the border
if ( qFuzzyCompare( value, upperBound() ) )
value = upperBound();
else if ( qFuzzyCompare( value, lowerBound() ) )
value = lowerBound();
}
}
return value;
}
/*!
Update the slider according to modifications of the scale
*/
void QwtAbstractSlider::scaleChange()
{
const double value = qBound( minimum(), d_data->value, maximum() );
const bool changed = ( value != d_data->value );
if ( changed )
{
d_data->value = value;
}
if ( d_data->isValid || changed )
Q_EMIT valueChanged( d_data->value );
updateGeometry();
update();
}
//! Calling update()
void QwtAbstractSlider::sliderChange()
{
update();
}

View File

@@ -0,0 +1,167 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ABSTRACT_SLIDER_H
#define QWT_ABSTRACT_SLIDER_H
#include "qwt_global.h"
#include "qwt_abstract_scale.h"
/*!
\brief An abstract base class for slider widgets with a scale
A slider widget displays a value according to a scale.
The class is designed as a common super class for widgets like
QwtKnob, QwtDial and QwtSlider.
When the slider is nor readOnly() its value can be modified
by keyboard, mouse and wheel inputs.
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
Only for linear scales the number of steps correspond with
a fixed step size.
*/
class QWT_EXPORT QwtAbstractSlider: public QwtAbstractScale
{
Q_OBJECT
Q_PROPERTY( double value READ value WRITE setValue )
Q_PROPERTY( uint totalSteps READ totalSteps WRITE setTotalSteps )
Q_PROPERTY( uint singleSteps READ singleSteps WRITE setSingleSteps )
Q_PROPERTY( uint pageSteps READ pageSteps WRITE setPageSteps )
Q_PROPERTY( bool stepAlignment READ stepAlignment WRITE setStepAlignment )
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
Q_PROPERTY( bool tracking READ isTracking WRITE setTracking )
Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
Q_PROPERTY( bool invertedControls READ invertedControls WRITE setInvertedControls )
public:
explicit QwtAbstractSlider( QWidget *parent = NULL );
virtual ~QwtAbstractSlider();
void setValid( bool );
bool isValid() const;
double value() const;
void setWrapping( bool );
bool wrapping() const;
void setTotalSteps( uint );
uint totalSteps() const;
void setSingleSteps( uint );
uint singleSteps() const;
void setPageSteps( uint );
uint pageSteps() const;
void setStepAlignment( bool );
bool stepAlignment() const;
void setTracking( bool );
bool isTracking() const;
void setReadOnly( bool );
bool isReadOnly() const;
void setInvertedControls( bool );
bool invertedControls() const;
public Q_SLOTS:
void setValue( double val );
Q_SIGNALS:
/*!
\brief Notify a change of value.
When tracking is enabled (default setting),
this signal will be emitted every time the value changes.
\param value New value
\sa setTracking(), sliderMoved()
*/
void valueChanged( double value );
/*!
This signal is emitted when the user presses the
movable part of the slider.
*/
void sliderPressed();
/*!
This signal is emitted when the user releases the
movable part of the slider.
*/
void sliderReleased();
/*!
This signal is emitted when the user moves the
slider with the mouse.
\param value New value
\sa valueChanged()
*/
void sliderMoved( double value );
protected:
virtual void mousePressEvent( QMouseEvent * );
virtual void mouseReleaseEvent( QMouseEvent * );
virtual void mouseMoveEvent( QMouseEvent * );
virtual void keyPressEvent( QKeyEvent * );
virtual void wheelEvent( QWheelEvent * );
/*!
\brief Determine what to do when the user presses a mouse button.
\param pos Mouse position
\retval True, when pos is a valid scroll position
\sa scrolledTo()
*/
virtual bool isScrollPosition( const QPoint &pos ) const = 0;
/*!
\brief Determine the value for a new position of the
movable part of the slider
\param pos Mouse position
\return Value for the mouse position
\sa isScrollPosition()
*/
virtual double scrolledTo( const QPoint &pos ) const = 0;
void incrementValue( int numSteps );
virtual void scaleChange();
protected:
virtual void sliderChange();
double incrementedValue(
double value, int stepCount ) const;
private:
double alignedValue( double ) const;
double boundedValue( double ) const;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,244 @@
/* -*- 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_analog_clock.h"
#include "qwt_round_scale_draw.h"
#include <qmath.h>
#include <qlocale.h>
class QwtAnalogClockScaleDraw: public QwtRoundScaleDraw
{
public:
QwtAnalogClockScaleDraw()
{
setSpacing( 8 );
enableComponent( QwtAbstractScaleDraw::Backbone, false );
setTickLength( QwtScaleDiv::MinorTick, 2 );
setTickLength( QwtScaleDiv::MediumTick, 4 );
setTickLength( QwtScaleDiv::MajorTick, 8 );
setPenWidth( 1 );
}
virtual QwtText label( double value ) const
{
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
value = 60.0 * 60.0 * 12.0;
return QLocale().toString( qRound( value / ( 60.0 * 60.0 ) ) );
}
};
/*!
Constructor
\param parent Parent widget
*/
QwtAnalogClock::QwtAnalogClock( QWidget *parent ):
QwtDial( parent )
{
setWrapping( true );
setReadOnly( true );
setOrigin( 270.0 );
setScaleDraw( new QwtAnalogClockScaleDraw() );
setTotalSteps( 60 );
const int secondsPerHour = 60.0 * 60.0;
QList<double> majorTicks;
QList<double> minorTicks;
for ( int i = 0; i < 12; i++ )
{
majorTicks += i * secondsPerHour;
for ( int j = 1; j < 5; j++ )
minorTicks += i * secondsPerHour + j * secondsPerHour / 5.0;
}
QwtScaleDiv scaleDiv;
scaleDiv.setInterval( 0.0, 12.0 * secondsPerHour );
scaleDiv.setTicks( QwtScaleDiv::MajorTick, majorTicks );
scaleDiv.setTicks( QwtScaleDiv::MinorTick, minorTicks );
setScale( scaleDiv );
QColor knobColor = palette().color( QPalette::Active, QPalette::Text );
knobColor = knobColor.dark( 120 );
QColor handColor;
int width;
for ( int i = 0; i < NHands; i++ )
{
if ( i == SecondHand )
{
width = 2;
handColor = knobColor.dark( 120 );
}
else
{
width = 8;
handColor = knobColor;
}
QwtDialSimpleNeedle *hand = new QwtDialSimpleNeedle(
QwtDialSimpleNeedle::Arrow, true, handColor, knobColor );
hand->setWidth( width );
d_hand[i] = NULL;
setHand( static_cast<Hand>( i ), hand );
}
}
//! Destructor
QwtAnalogClock::~QwtAnalogClock()
{
for ( int i = 0; i < NHands; i++ )
delete d_hand[i];
}
/*!
Nop method, use setHand() instead
\sa setHand()
*/
void QwtAnalogClock::setNeedle( QwtDialNeedle * )
{
// no op
return;
}
/*!
Set a clock hand
\param hand Specifies the type of hand
\param needle Hand
\sa hand()
*/
void QwtAnalogClock::setHand( Hand hand, QwtDialNeedle *needle )
{
if ( hand >= 0 && hand < NHands )
{
delete d_hand[hand];
d_hand[hand] = needle;
}
}
/*!
\return Clock hand
\param hd Specifies the type of hand
\sa setHand()
*/
QwtDialNeedle *QwtAnalogClock::hand( Hand hd )
{
if ( hd < 0 || hd >= NHands )
return NULL;
return d_hand[hd];
}
/*!
\return Clock hand
\param hd Specifies the type of hand
\sa setHand()
*/
const QwtDialNeedle *QwtAnalogClock::hand( Hand hd ) const
{
return const_cast<QwtAnalogClock *>( this )->hand( hd );
}
/*!
\brief Set the current time
*/
void QwtAnalogClock::setCurrentTime()
{
setTime( QTime::currentTime() );
}
/*!
Set a time
\param time Time to display
*/
void QwtAnalogClock::setTime( const QTime &time )
{
if ( time.isValid() )
{
setValue( ( time.hour() % 12 ) * 60.0 * 60.0
+ time.minute() * 60.0 + time.second() );
}
else
setValid( false );
}
/*!
\brief Draw the needle
A clock has no single needle but three hands instead. drawNeedle()
translates value() into directions for the hands and calls
drawHand().
\param painter Painter
\param center Center of the clock
\param radius Maximum length for the hands
\param dir Dummy, not used.
\param colorGroup ColorGroup
\sa drawHand()
*/
void QwtAnalogClock::drawNeedle( QPainter *painter, const QPointF &center,
double radius, double dir, QPalette::ColorGroup colorGroup ) const
{
Q_UNUSED( dir );
if ( isValid() )
{
const double hours = value() / ( 60.0 * 60.0 );
const double minutes =
( value() - qFloor(hours) * 60.0 * 60.0 ) / 60.0;
const double seconds = value() - qFloor(hours) * 60.0 * 60.0
- qFloor(minutes) * 60.0;
double angle[NHands];
angle[HourHand] = 360.0 * hours / 12.0;
angle[MinuteHand] = 360.0 * minutes / 60.0;
angle[SecondHand] = 360.0 * seconds / 60.0;
for ( int hand = 0; hand < NHands; hand++ )
{
const double d = 360.0 - angle[hand] - origin();
drawHand( painter, static_cast<Hand>( hand ),
center, radius, d, colorGroup );
}
}
}
/*!
Draw a clock hand
\param painter Painter
\param hd Specify the type of hand
\param center Center of the clock
\param radius Maximum length for the hands
\param direction Direction of the hand in degrees, counter clockwise
\param cg ColorGroup
*/
void QwtAnalogClock::drawHand( QPainter *painter, Hand hd,
const QPointF &center, double radius, double direction,
QPalette::ColorGroup cg ) const
{
const QwtDialNeedle *needle = hand( hd );
if ( needle )
{
if ( hd == HourHand )
radius = qRound( 0.8 * radius );
needle->draw( painter, center, radius, direction, cg );
}
}

View File

@@ -0,0 +1,93 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ANALOG_CLOCK_H
#define QWT_ANALOG_CLOCK_H
#include "qwt_global.h"
#include "qwt_dial.h"
#include "qwt_dial_needle.h"
#include <qdatetime.h>
/*!
\brief An analog clock
\image html analogclock.png
\par Example
\code
#include <qwt_analog_clock.h>
QwtAnalogClock *clock = new QwtAnalogClock(...);
clock->scaleDraw()->setPenWidth(3);
clock->setLineWidth(6);
clock->setFrameShadow(QwtDial::Sunken);
clock->setTime();
// update the clock every second
QTimer *timer = new QTimer(clock);
timer->connect(timer, SIGNAL(timeout()), clock, SLOT(setCurrentTime()));
timer->start(1000);
\endcode
\note The examples/dials example shows how to use QwtAnalogClock.
*/
class QWT_EXPORT QwtAnalogClock: public QwtDial
{
Q_OBJECT
public:
/*!
Hand type
\sa setHand(), hand()
*/
enum Hand
{
//! Needle displaying the seconds
SecondHand,
//! Needle displaying the minutes
MinuteHand,
//! Needle displaying the hours
HourHand,
//! Number of needles
NHands
};
explicit QwtAnalogClock( QWidget* parent = NULL );
virtual ~QwtAnalogClock();
void setHand( Hand, QwtDialNeedle * );
const QwtDialNeedle *hand( Hand ) const;
QwtDialNeedle *hand( Hand );
public Q_SLOTS:
void setCurrentTime();
void setTime( const QTime & );
protected:
virtual void drawNeedle( QPainter *, const QPointF &,
double radius, double direction, QPalette::ColorGroup ) const;
virtual void drawHand( QPainter *, Hand, const QPointF &,
double radius, double direction, QPalette::ColorGroup ) const;
private:
// use setHand instead
void setNeedle( QwtDialNeedle * );
QwtDialNeedle *d_hand[NHands];
};
#endif

View File

@@ -0,0 +1,333 @@
/* -*- 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_arrow_button.h"
#include "qwt_math.h"
#include <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qevent.h>
#include <qapplication.h>
static const int MaxNum = 3;
static const int Margin = 2;
static const int Spacing = 1;
class QwtArrowButton::PrivateData
{
public:
int num;
Qt::ArrowType arrowType;
};
static QStyleOptionButton styleOpt( const QwtArrowButton* btn )
{
QStyleOptionButton option;
option.init( btn );
option.features = QStyleOptionButton::None;
if ( btn->isFlat() )
option.features |= QStyleOptionButton::Flat;
if ( btn->menu() )
option.features |= QStyleOptionButton::HasMenu;
if ( btn->autoDefault() || btn->isDefault() )
option.features |= QStyleOptionButton::AutoDefaultButton;
if ( btn->isDefault() )
option.features |= QStyleOptionButton::DefaultButton;
if ( btn->isDown() )
option.state |= QStyle::State_Sunken;
if ( !btn->isFlat() && !btn->isDown() )
option.state |= QStyle::State_Raised;
return option;
}
/*!
\param num Number of arrows
\param arrowType see Qt::ArrowType in the Qt docs.
\param parent Parent widget
*/
QwtArrowButton::QwtArrowButton( int num,
Qt::ArrowType arrowType, QWidget *parent ):
QPushButton( parent )
{
d_data = new PrivateData;
d_data->num = qBound( 1, num, MaxNum );
d_data->arrowType = arrowType;
setAutoRepeat( true );
setAutoDefault( false );
switch ( d_data->arrowType )
{
case Qt::LeftArrow:
case Qt::RightArrow:
setSizePolicy( QSizePolicy::Expanding,
QSizePolicy::Fixed );
break;
default:
setSizePolicy( QSizePolicy::Fixed,
QSizePolicy::Expanding );
}
}
//! Destructor
QwtArrowButton::~QwtArrowButton()
{
delete d_data;
d_data = NULL;
}
/*!
\brief The direction of the arrows
*/
Qt::ArrowType QwtArrowButton::arrowType() const
{
return d_data->arrowType;
}
/*!
\brief The number of arrows
*/
int QwtArrowButton::num() const
{
return d_data->num;
}
/*!
\return the bounding rectangle for the label
*/
QRect QwtArrowButton::labelRect() const
{
const int m = Margin;
QRect r = rect();
r.setRect( r.x() + m, r.y() + m,
r.width() - 2 * m, r.height() - 2 * m );
if ( isDown() )
{
QStyleOptionButton option = styleOpt( this );
const int ph = style()->pixelMetric(
QStyle::PM_ButtonShiftHorizontal, &option, this );
const int pv = style()->pixelMetric(
QStyle::PM_ButtonShiftVertical, &option, this );
r.translate( ph, pv );
}
return r;
}
/*!
Paint event handler
\param event Paint event
*/
void QwtArrowButton::paintEvent( QPaintEvent *event )
{
QPushButton::paintEvent( event );
QPainter painter( this );
drawButtonLabel( &painter );
}
/*!
\brief Draw the button label
\param painter Painter
\sa The Qt Manual for QPushButton
*/
void QwtArrowButton::drawButtonLabel( QPainter *painter )
{
const bool isVertical = d_data->arrowType == Qt::UpArrow ||
d_data->arrowType == Qt::DownArrow;
const QRect r = labelRect();
QSize boundingSize = labelRect().size();
if ( isVertical )
boundingSize.transpose();
const int w =
( boundingSize.width() - ( MaxNum - 1 ) * Spacing ) / MaxNum;
QSize arrow = arrowSize( Qt::RightArrow,
QSize( w, boundingSize.height() ) );
if ( isVertical )
arrow.transpose();
QRect contentsSize; // aligned rect where to paint all arrows
if ( d_data->arrowType == Qt::LeftArrow || d_data->arrowType == Qt::RightArrow )
{
contentsSize.setWidth( d_data->num * arrow.width()
+ ( d_data->num - 1 ) * Spacing );
contentsSize.setHeight( arrow.height() );
}
else
{
contentsSize.setWidth( arrow.width() );
contentsSize.setHeight( d_data->num * arrow.height()
+ ( d_data->num - 1 ) * Spacing );
}
QRect arrowRect( contentsSize );
arrowRect.moveCenter( r.center() );
arrowRect.setSize( arrow );
painter->save();
for ( int i = 0; i < d_data->num; i++ )
{
drawArrow( painter, arrowRect, d_data->arrowType );
int dx = 0;
int dy = 0;
if ( isVertical )
dy = arrow.height() + Spacing;
else
dx = arrow.width() + Spacing;
arrowRect.translate( dx, dy );
}
painter->restore();
if ( hasFocus() )
{
QStyleOptionFocusRect option;
option.init( this );
option.backgroundColor = palette().color( QPalette::Window );
style()->drawPrimitive( QStyle::PE_FrameFocusRect,
&option, painter, this );
}
}
/*!
Draw an arrow int a bounding rectangle
\param painter Painter
\param r Rectangle where to paint the arrow
\param arrowType Arrow type
*/
void QwtArrowButton::drawArrow( QPainter *painter,
const QRect &r, Qt::ArrowType arrowType ) const
{
QPolygon pa( 3 );
switch ( arrowType )
{
case Qt::UpArrow:
pa.setPoint( 0, r.bottomLeft() );
pa.setPoint( 1, r.bottomRight() );
pa.setPoint( 2, r.center().x(), r.top() );
break;
case Qt::DownArrow:
pa.setPoint( 0, r.topLeft() );
pa.setPoint( 1, r.topRight() );
pa.setPoint( 2, r.center().x(), r.bottom() );
break;
case Qt::RightArrow:
pa.setPoint( 0, r.topLeft() );
pa.setPoint( 1, r.bottomLeft() );
pa.setPoint( 2, r.right(), r.center().y() );
break;
case Qt::LeftArrow:
pa.setPoint( 0, r.topRight() );
pa.setPoint( 1, r.bottomRight() );
pa.setPoint( 2, r.left(), r.center().y() );
break;
default:
break;
}
painter->save();
painter->setRenderHint( QPainter::Antialiasing, true );
painter->setPen( Qt::NoPen );
painter->setBrush( palette().brush( QPalette::ButtonText ) );
painter->drawPolygon( pa );
painter->restore();
}
/*!
\return a size hint
*/
QSize QwtArrowButton::sizeHint() const
{
const QSize hint = minimumSizeHint();
return hint.expandedTo( QApplication::globalStrut() );
}
/*!
\brief Return a minimum size hint
*/
QSize QwtArrowButton::minimumSizeHint() const
{
const QSize asz = arrowSize( Qt::RightArrow, QSize() );
QSize sz(
2 * Margin + ( MaxNum - 1 ) * Spacing + MaxNum * asz.width(),
2 * Margin + asz.height()
);
if ( d_data->arrowType == Qt::UpArrow || d_data->arrowType == Qt::DownArrow )
sz.transpose();
QStyleOption styleOption;
styleOption.init( this );
sz = style()->sizeFromContents( QStyle::CT_PushButton,
&styleOption, sz, this );
return sz;
}
/*!
Calculate the size for a arrow that fits into a rectangle of a given size
\param arrowType Arrow type
\param boundingSize Bounding size
\return Size of the arrow
*/
QSize QwtArrowButton::arrowSize( Qt::ArrowType arrowType,
const QSize &boundingSize ) const
{
QSize bs = boundingSize;
if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
bs.transpose();
const int MinLen = 2;
const QSize sz = bs.expandedTo(
QSize( MinLen, 2 * MinLen - 1 ) ); // minimum
int w = sz.width();
int h = 2 * w - 1;
if ( h > sz.height() )
{
h = sz.height();
w = ( h + 1 ) / 2;
}
QSize arrSize( w, h );
if ( arrowType == Qt::UpArrow || arrowType == Qt::DownArrow )
arrSize.transpose();
return arrSize;
}
/*!
\brief autoRepeat for the space keys
*/
void QwtArrowButton::keyPressEvent( QKeyEvent *event )
{
if ( event->isAutoRepeat() && event->key() == Qt::Key_Space )
Q_EMIT clicked();
QPushButton::keyPressEvent( event );
}

View File

@@ -0,0 +1,52 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_ARROW_BUTTON_H
#define QWT_ARROW_BUTTON_H
#include "qwt_global.h"
#include <qpushbutton.h>
/*!
\brief Arrow Button
A push button with one or more filled triangles on its front.
An Arrow button can have 1 to 3 arrows in a row, pointing
up, down, left or right.
*/
class QWT_EXPORT QwtArrowButton : public QPushButton
{
public:
explicit QwtArrowButton ( int num, Qt::ArrowType, QWidget *parent = NULL );
virtual ~QwtArrowButton();
Qt::ArrowType arrowType() const;
int num() const;
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
protected:
virtual void paintEvent( QPaintEvent *event );
virtual void drawButtonLabel( QPainter *p );
virtual void drawArrow( QPainter *,
const QRect &, Qt::ArrowType ) const;
virtual QRect labelRect() const;
virtual QSize arrowSize( Qt::ArrowType,
const QSize &boundingSize ) const;
virtual void keyPressEvent( QKeyEvent * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,510 @@
/* -*- 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_clipper.h"
#include "qwt_point_polar.h"
#include <qrect.h>
#include <string.h>
#include <stdlib.h>
#if QT_VERSION < 0x040601
#define qAtan(x) ::atan(x)
#endif
namespace QwtClip
{
// some templates used for inlining
template <class Point, typename T> class LeftEdge;
template <class Point, typename T> class RightEdge;
template <class Point, typename T> class TopEdge;
template <class Point, typename T> class BottomEdge;
template <class Point> class PointBuffer;
}
template <class Point, typename Value>
class QwtClip::LeftEdge
{
public:
inline LeftEdge( Value x1, Value, Value, Value ):
d_x1( x1 )
{
}
inline bool isInside( const Point &p ) const
{
return p.x() >= d_x1;
}
inline Point intersection( const Point &p1, const Point &p2 ) const
{
double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
return Point( d_x1, static_cast< Value >( p2.y() + ( d_x1 - p2.x() ) * dy ) );
}
private:
const Value d_x1;
};
template <class Point, typename Value>
class QwtClip::RightEdge
{
public:
inline RightEdge( Value, Value x2, Value, Value ):
d_x2( x2 )
{
}
inline bool isInside( const Point &p ) const
{
return p.x() <= d_x2;
}
inline Point intersection( const Point &p1, const Point &p2 ) const
{
double dy = ( p1.y() - p2.y() ) / double( p1.x() - p2.x() );
return Point( d_x2, static_cast<Value>( p2.y() + ( d_x2 - p2.x() ) * dy ) );
}
private:
const Value d_x2;
};
template <class Point, typename Value>
class QwtClip::TopEdge
{
public:
inline TopEdge( Value, Value, Value y1, Value ):
d_y1( y1 )
{
}
inline bool isInside( const Point &p ) const
{
return p.y() >= d_y1;
}
inline Point intersection( const Point &p1, const Point &p2 ) const
{
double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
return Point( static_cast<Value>( p2.x() + ( d_y1 - p2.y() ) * dx ), d_y1 );
}
private:
const Value d_y1;
};
template <class Point, typename Value>
class QwtClip::BottomEdge
{
public:
inline BottomEdge( Value, Value, Value, Value y2 ):
d_y2( y2 )
{
}
inline bool isInside( const Point &p ) const
{
return p.y() <= d_y2;
}
inline Point intersection( const Point &p1, const Point &p2 ) const
{
double dx = ( p1.x() - p2.x() ) / double( p1.y() - p2.y() );
return Point( static_cast<Value>( p2.x() + ( d_y2 - p2.y() ) * dx ), d_y2 );
}
private:
const Value d_y2;
};
template<class Point>
class QwtClip::PointBuffer
{
public:
PointBuffer( int capacity = 0 ):
m_capacity( 0 ),
m_size( 0 ),
m_buffer( NULL )
{
if ( capacity > 0 )
reserve( capacity );
}
~PointBuffer()
{
if ( m_buffer )
::free( m_buffer );
}
inline void setPoints( int numPoints, const Point *points )
{
reserve( numPoints );
m_size = numPoints;
::memcpy( m_buffer, points, m_size * sizeof( Point ) );
}
inline void reset()
{
m_size = 0;
}
inline int size() const
{
return m_size;
}
inline Point *data() const
{
return m_buffer;
}
inline Point &operator[]( int i )
{
return m_buffer[i];
}
inline const Point &operator[]( int i ) const
{
return m_buffer[i];
}
inline void add( const Point &point )
{
if ( m_capacity <= m_size )
reserve( m_size + 1 );
m_buffer[m_size++] = point;
}
private:
inline void reserve( int size )
{
if ( m_capacity == 0 )
m_capacity = 1;
while ( m_capacity < size )
m_capacity *= 2;
m_buffer = static_cast<Point *>(
::realloc( m_buffer, m_capacity * sizeof( Point ) ) );
}
int m_capacity;
int m_size;
Point *m_buffer;
};
using namespace QwtClip;
template <class Polygon, class Rect, class Point, typename T>
class QwtPolygonClipper
{
public:
QwtPolygonClipper( const Rect &clipRect ):
d_clipRect( clipRect )
{
}
Polygon clipPolygon( const Polygon &polygon, bool closePolygon ) const
{
#if 0
if ( d_clipRect.contains( polygon.boundingRect() ) )
return polygon;
#endif
PointBuffer<Point> points1;
PointBuffer<Point> points2( qMin( 256, polygon.size() ) );
points1.setPoints( polygon.size(), polygon.data() );
clipEdge< LeftEdge<Point, T> >( closePolygon, points1, points2 );
clipEdge< RightEdge<Point, T> >( closePolygon, points2, points1 );
clipEdge< TopEdge<Point, T> >( closePolygon, points1, points2 );
clipEdge< BottomEdge<Point, T> >( closePolygon, points2, points1 );
Polygon p;
p.resize( points1.size() );
::memcpy( p.data(), points1.data(), points1.size() * sizeof( Point ) );
return p;
}
private:
template <class Edge>
inline void clipEdge( bool closePolygon,
PointBuffer<Point> &points, PointBuffer<Point> &clippedPoints ) const
{
clippedPoints.reset();
if ( points.size() < 2 )
{
if ( points.size() == 1 )
clippedPoints.add( points[0] );
return;
}
const Edge edge( d_clipRect.x(), d_clipRect.x() + d_clipRect.width(),
d_clipRect.y(), d_clipRect.y() + d_clipRect.height() );
int lastPos, start;
if ( closePolygon )
{
start = 0;
lastPos = points.size() - 1;
}
else
{
start = 1;
lastPos = 0;
if ( edge.isInside( points[0] ) )
clippedPoints.add( points[0] );
}
const uint nPoints = points.size();
for ( uint i = start; i < nPoints; i++ )
{
const Point &p1 = points[i];
const Point &p2 = points[lastPos];
if ( edge.isInside( p1 ) )
{
if ( edge.isInside( p2 ) )
{
clippedPoints.add( p1 );
}
else
{
clippedPoints.add( edge.intersection( p1, p2 ) );
clippedPoints.add( p1 );
}
}
else
{
if ( edge.isInside( p2 ) )
{
clippedPoints.add( edge.intersection( p1, p2 ) );
}
}
lastPos = i;
}
}
const Rect d_clipRect;
};
class QwtCircleClipper
{
public:
QwtCircleClipper( const QRectF &r );
QVector<QwtInterval> clipCircle( const QPointF &, double radius ) const;
private:
enum Edge
{
Left,
Top,
Right,
Bottom,
NEdges
};
QList<QPointF> cuttingPoints(
Edge, const QPointF &pos, double radius ) const;
double toAngle( const QPointF &, const QPointF & ) const;
const QRectF d_rect;
};
QwtCircleClipper::QwtCircleClipper( const QRectF &r ):
d_rect( r )
{
}
QVector<QwtInterval> QwtCircleClipper::clipCircle(
const QPointF &pos, double radius ) const
{
QList<QPointF> points;
for ( int edge = 0; edge < NEdges; edge++ )
points += cuttingPoints( static_cast<Edge>(edge), pos, radius );
QVector<QwtInterval> intv;
if ( points.size() <= 0 )
{
QRectF cRect( 0, 0, 2 * radius, 2 * radius );
cRect.moveCenter( pos );
if ( d_rect.contains( cRect ) )
intv += QwtInterval( 0.0, 2 * M_PI );
}
else
{
QList<double> angles;
for ( int i = 0; i < points.size(); i++ )
angles += toAngle( pos, points[i] );
qSort( angles );
const int in = d_rect.contains( qwtPolar2Pos( pos, radius,
angles[0] + ( angles[1] - angles[0] ) / 2 ) );
if ( in )
{
for ( int i = 0; i < angles.size() - 1; i += 2 )
intv += QwtInterval( angles[i], angles[i+1] );
}
else
{
for ( int i = 1; i < angles.size() - 1; i += 2 )
intv += QwtInterval( angles[i], angles[i+1] );
intv += QwtInterval( angles.last(), angles.first() );
}
}
return intv;
}
double QwtCircleClipper::toAngle(
const QPointF &from, const QPointF &to ) const
{
if ( from.x() == to.x() )
return from.y() <= to.y() ? M_PI / 2.0 : 3 * M_PI / 2.0;
const double m = qAbs( ( to.y() - from.y() ) / ( to.x() - from.x() ) );
double angle = qAtan( m );
if ( to.x() > from.x() )
{
if ( to.y() > from.y() )
angle = 2 * M_PI - angle;
}
else
{
if ( to.y() > from.y() )
angle = M_PI + angle;
else
angle = M_PI - angle;
}
return angle;
}
QList<QPointF> QwtCircleClipper::cuttingPoints(
Edge edge, const QPointF &pos, double radius ) const
{
QList<QPointF> points;
if ( edge == Left || edge == Right )
{
const double x = ( edge == Left ) ? d_rect.left() : d_rect.right();
if ( qAbs( pos.x() - x ) < radius )
{
const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.x() - x ) );
const double m_y1 = pos.y() + off;
if ( m_y1 >= d_rect.top() && m_y1 <= d_rect.bottom() )
points += QPointF( x, m_y1 );
const double m_y2 = pos.y() - off;
if ( m_y2 >= d_rect.top() && m_y2 <= d_rect.bottom() )
points += QPointF( x, m_y2 );
}
}
else
{
const double y = ( edge == Top ) ? d_rect.top() : d_rect.bottom();
if ( qAbs( pos.y() - y ) < radius )
{
const double off = qSqrt( qwtSqr( radius ) - qwtSqr( pos.y() - y ) );
const double x1 = pos.x() + off;
if ( x1 >= d_rect.left() && x1 <= d_rect.right() )
points += QPointF( x1, y );
const double m_x2 = pos.x() - off;
if ( m_x2 >= d_rect.left() && m_x2 <= d_rect.right() )
points += QPointF( m_x2, y );
}
}
return points;
}
/*!
Sutherland-Hodgman polygon clipping
\param clipRect Clip rectangle
\param polygon Polygon
\param closePolygon True, when the polygon is closed
\return Clipped polygon
*/
QPolygon QwtClipper::clipPolygon(
const QRectF &clipRect, const QPolygon &polygon, bool closePolygon )
{
const int minX = qCeil( clipRect.left() );
const int maxX = qFloor( clipRect.right() );
const int minY = qCeil( clipRect.top() );
const int maxY = qFloor( clipRect.bottom() );
const QRect r( minX, minY, maxX - minX, maxY - minY );
QwtPolygonClipper<QPolygon, QRect, QPoint, int> clipper( r );
return clipper.clipPolygon( polygon, closePolygon );
}
/*!
Sutherland-Hodgman polygon clipping
\param clipRect Clip rectangle
\param polygon Polygon
\param closePolygon True, when the polygon is closed
\return Clipped polygon
*/
QPolygon QwtClipper::clipPolygon(
const QRect &clipRect, const QPolygon &polygon, bool closePolygon )
{
QwtPolygonClipper<QPolygon, QRect, QPoint, int> clipper( clipRect );
return clipper.clipPolygon( polygon, closePolygon );
}
/*!
Sutherland-Hodgman polygon clipping
\param clipRect Clip rectangle
\param polygon Polygon
\param closePolygon True, when the polygon is closed
\return Clipped polygon
*/
QPolygonF QwtClipper::clipPolygonF(
const QRectF &clipRect, const QPolygonF &polygon, bool closePolygon )
{
QwtPolygonClipper<QPolygonF, QRectF, QPointF, double> clipper( clipRect );
return clipper.clipPolygon( polygon, closePolygon );
}
/*!
Circle clipping
clipCircle() divides a circle into intervals of angles representing arcs
of the circle. When the circle is completely inside the clip rectangle
an interval [0.0, 2 * M_PI] is returned.
\param clipRect Clip rectangle
\param center Center of the circle
\param radius Radius of the circle
\return Arcs of the circle
*/
QVector<QwtInterval> QwtClipper::clipCircle( const QRectF &clipRect,
const QPointF &center, double radius )
{
QwtCircleClipper clipper( clipRect );
return clipper.clipCircle( center, radius );
}

View File

@@ -0,0 +1,40 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_CLIPPER_H
#define QWT_CLIPPER_H
#include "qwt_global.h"
#include "qwt_interval.h"
#include <qpolygon.h>
#include <qvector.h>
class QRect;
class QRectF;
/*!
\brief Some clipping algorithms
*/
class QWT_EXPORT QwtClipper
{
public:
static QPolygon clipPolygon( const QRect &,
const QPolygon &, bool closePolygon = false );
static QPolygon clipPolygon( const QRectF &,
const QPolygon &, bool closePolygon = false );
static QPolygonF clipPolygonF( const QRectF &,
const QPolygonF &, bool closePolygon = false );
static QVector<QwtInterval> clipCircle(
const QRectF &, const QPointF &, double radius );
};
#endif

View File

@@ -0,0 +1,499 @@
/* -*- 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_color_map.h"
#include "qwt_math.h"
#include "qwt_interval.h"
#include <qnumeric.h>
class QwtLinearColorMap::ColorStops
{
public:
ColorStops():
d_doAlpha( false )
{
d_stops.reserve( 256 );
}
void insert( double pos, const QColor &color );
QRgb rgb( QwtLinearColorMap::Mode, double pos ) const;
QVector<double> stops() const;
private:
class ColorStop
{
public:
ColorStop():
pos( 0.0 ),
rgb( 0 )
{
};
ColorStop( double p, const QColor &c ):
pos( p ),
rgb( c.rgba() )
{
r = qRed( rgb );
g = qGreen( rgb );
b = qBlue( rgb );
a = qAlpha( rgb );
/*
when mapping a value to rgb we will have to calcualate:
- const int v = int( ( s1.v0 + ratio * s1.vStep ) + 0.5 );
Thus adding 0.5 ( for rounding ) can be done in advance
*/
r0 = r + 0.5;
g0 = g + 0.5;
b0 = b + 0.5;
a0 = a + 0.5;
rStep = gStep = bStep = aStep = 0.0;
posStep = 0.0;
}
void updateSteps( const ColorStop &nextStop )
{
rStep = nextStop.r - r;
gStep = nextStop.g - g;
bStep = nextStop.b - b;
aStep = nextStop.a - a;
posStep = nextStop.pos - pos;
}
double pos;
QRgb rgb;
int r, g, b, a;
// precalculated values
double rStep, gStep, bStep, aStep;
double r0, g0, b0, a0;
double posStep;
};
inline int findUpper( double pos ) const;
QVector<ColorStop> d_stops;
bool d_doAlpha;
};
void QwtLinearColorMap::ColorStops::insert( double pos, const QColor &color )
{
// Lookups need to be very fast, insertions are not so important.
// Anyway, a balanced tree is what we need here. TODO ...
if ( pos < 0.0 || pos > 1.0 )
return;
int index;
if ( d_stops.size() == 0 )
{
index = 0;
d_stops.resize( 1 );
}
else
{
index = findUpper( pos );
if ( index == d_stops.size() ||
qAbs( d_stops[index].pos - pos ) >= 0.001 )
{
d_stops.resize( d_stops.size() + 1 );
for ( int i = d_stops.size() - 1; i > index; i-- )
d_stops[i] = d_stops[i-1];
}
}
d_stops[index] = ColorStop( pos, color );
if ( color.alpha() != 255 )
d_doAlpha = true;
if ( index > 0 )
d_stops[index-1].updateSteps( d_stops[index] );
if ( index < d_stops.size() - 1 )
d_stops[index].updateSteps( d_stops[index+1] );
}
inline QVector<double> QwtLinearColorMap::ColorStops::stops() const
{
QVector<double> positions( d_stops.size() );
for ( int i = 0; i < d_stops.size(); i++ )
positions[i] = d_stops[i].pos;
return positions;
}
inline int QwtLinearColorMap::ColorStops::findUpper( double pos ) const
{
int index = 0;
int n = d_stops.size();
const ColorStop *stops = d_stops.data();
while ( n > 0 )
{
const int half = n >> 1;
const int middle = index + half;
if ( stops[middle].pos <= pos )
{
index = middle + 1;
n -= half + 1;
}
else
n = half;
}
return index;
}
inline QRgb QwtLinearColorMap::ColorStops::rgb(
QwtLinearColorMap::Mode mode, double pos ) const
{
if ( pos <= 0.0 )
return d_stops[0].rgb;
if ( pos >= 1.0 )
return d_stops[ d_stops.size() - 1 ].rgb;
const int index = findUpper( pos );
if ( mode == FixedColors )
{
return d_stops[index-1].rgb;
}
else
{
const ColorStop &s1 = d_stops[index-1];
const double ratio = ( pos - s1.pos ) / ( s1.posStep );
const int r = int( s1.r0 + ratio * s1.rStep );
const int g = int( s1.g0 + ratio * s1.gStep );
const int b = int( s1.b0 + ratio * s1.bStep );
if ( d_doAlpha )
{
if ( s1.aStep )
{
const int a = int( s1.a0 + ratio * s1.aStep );
return qRgba( r, g, b, a );
}
else
{
return qRgba( r, g, b, s1.a );
}
}
else
{
return qRgb( r, g, b );
}
}
}
//! Constructor
QwtColorMap::QwtColorMap( Format format ):
d_format( format )
{
}
//! Destructor
QwtColorMap::~QwtColorMap()
{
}
/*!
Build and return a color map of 256 colors
The color table is needed for rendering indexed images in combination
with using colorIndex().
\param interval Range for the values
\return A color table, that can be used for a QImage
*/
QVector<QRgb> QwtColorMap::colorTable( const QwtInterval &interval ) const
{
QVector<QRgb> table( 256 );
if ( interval.isValid() )
{
const double step = interval.width() / ( table.size() - 1 );
for ( int i = 0; i < table.size(); i++ )
table[i] = rgb( interval, interval.minValue() + step * i );
}
return table;
}
class QwtLinearColorMap::PrivateData
{
public:
ColorStops colorStops;
QwtLinearColorMap::Mode mode;
};
/*!
Build a color map with two stops at 0.0 and 1.0. The color
at 0.0 is Qt::blue, at 1.0 it is Qt::yellow.
\param format Preferred format of the color map
*/
QwtLinearColorMap::QwtLinearColorMap( QwtColorMap::Format format ):
QwtColorMap( format )
{
d_data = new PrivateData;
d_data->mode = ScaledColors;
setColorInterval( Qt::blue, Qt::yellow );
}
/*!
Build a color map with two stops at 0.0 and 1.0.
\param color1 Color used for the minimum value of the value interval
\param color2 Color used for the maximum value of the value interval
\param format Preferred format for the color map
*/
QwtLinearColorMap::QwtLinearColorMap( const QColor &color1,
const QColor &color2, QwtColorMap::Format format ):
QwtColorMap( format )
{
d_data = new PrivateData;
d_data->mode = ScaledColors;
setColorInterval( color1, color2 );
}
//! Destructor
QwtLinearColorMap::~QwtLinearColorMap()
{
delete d_data;
}
/*!
\brief Set the mode of the color map
FixedColors means the color is calculated from the next lower
color stop. ScaledColors means the color is calculated
by interpolating the colors of the adjacent stops.
\sa mode()
*/
void QwtLinearColorMap::setMode( Mode mode )
{
d_data->mode = mode;
}
/*!
\return Mode of the color map
\sa setMode()
*/
QwtLinearColorMap::Mode QwtLinearColorMap::mode() const
{
return d_data->mode;
}
/*!
Set the color range
Add stops at 0.0 and 1.0.
\param color1 Color used for the minimum value of the value interval
\param color2 Color used for the maximum value of the value interval
\sa color1(), color2()
*/
void QwtLinearColorMap::setColorInterval(
const QColor &color1, const QColor &color2 )
{
d_data->colorStops = ColorStops();
d_data->colorStops.insert( 0.0, color1 );
d_data->colorStops.insert( 1.0, color2 );
}
/*!
Add a color stop
The value has to be in the range [0.0, 1.0].
F.e. a stop at position 17.0 for a range [10.0,20.0] must be
passed as: (17.0 - 10.0) / (20.0 - 10.0)
\param value Value between [0.0, 1.0]
\param color Color stop
*/
void QwtLinearColorMap::addColorStop( double value, const QColor& color )
{
if ( value >= 0.0 && value <= 1.0 )
d_data->colorStops.insert( value, color );
}
/*!
\return Positions of color stops in increasing order
*/
QVector<double> QwtLinearColorMap::colorStops() const
{
return d_data->colorStops.stops();
}
/*!
\return the first color of the color range
\sa setColorInterval()
*/
QColor QwtLinearColorMap::color1() const
{
return QColor( d_data->colorStops.rgb( d_data->mode, 0.0 ) );
}
/*!
\return the second color of the color range
\sa setColorInterval()
*/
QColor QwtLinearColorMap::color2() const
{
return QColor( d_data->colorStops.rgb( d_data->mode, 1.0 ) );
}
/*!
Map a value of a given interval into a RGB value
\param interval Range for all values
\param value Value to map into a RGB value
\return RGB value for value
*/
QRgb QwtLinearColorMap::rgb(
const QwtInterval &interval, double value ) const
{
if ( qIsNaN(value) )
return 0u;
const double width = interval.width();
if ( width <= 0.0 )
return 0u;
const double ratio = ( value - interval.minValue() ) / width;
return d_data->colorStops.rgb( d_data->mode, ratio );
}
/*!
\brief Map a value of a given interval into a color index
\param interval Range for all values
\param value Value to map into a color index
\return Index, between 0 and 255
*/
unsigned char QwtLinearColorMap::colorIndex(
const QwtInterval &interval, double value ) const
{
const double width = interval.width();
if ( qIsNaN(value) || width <= 0.0 || value <= interval.minValue() )
return 0;
if ( value >= interval.maxValue() )
return 255;
const double ratio = ( value - interval.minValue() ) / width;
unsigned char index;
if ( d_data->mode == FixedColors )
index = static_cast<unsigned char>( ratio * 255 ); // always floor
else
index = static_cast<unsigned char>( ratio * 255 + 0.5 );
return index;
}
class QwtAlphaColorMap::PrivateData
{
public:
QColor color;
QRgb rgb;
QRgb rgbMax;
};
/*!
Constructor
\param color Color of the map
*/
QwtAlphaColorMap::QwtAlphaColorMap( const QColor &color ):
QwtColorMap( QwtColorMap::RGB )
{
d_data = new PrivateData;
setColor( color );
}
//! Destructor
QwtAlphaColorMap::~QwtAlphaColorMap()
{
delete d_data;
}
/*!
Set the color
\param color Color
\sa color()
*/
void QwtAlphaColorMap::setColor( const QColor &color )
{
d_data->color = color;
d_data->rgb = color.rgb() & qRgba( 255, 255, 255, 0 );
d_data->rgbMax = d_data->rgb | ( 255 << 24 );
}
/*!
\return the color
\sa setColor()
*/
QColor QwtAlphaColorMap::color() const
{
return d_data->color;
}
/*!
\brief Map a value of a given interval into a alpha value
alpha := (value - interval.minValue()) / interval.width();
\param interval Range for all values
\param value Value to map into a RGB value
\return RGB value, with an alpha value
*/
QRgb QwtAlphaColorMap::rgb( const QwtInterval &interval, double value ) const
{
if ( qIsNaN(value) )
return 0u;
const double width = interval.width();
if ( width <= 0.0 )
return 0u;
if ( value <= interval.minValue() )
return d_data->rgb;
if ( value >= interval.maxValue() )
return d_data->rgbMax;
const double ratio = ( value - interval.minValue() ) / width;
return d_data->rgb | ( qRound( 255 * ratio ) << 24 );
}
/*!
Dummy function, needed to be implemented as it is pure virtual
in QwtColorMap. Color indices make no sense in combination with
an alpha channel.
\return Always 0
*/
unsigned char QwtAlphaColorMap::colorIndex(
const QwtInterval &, double ) const
{
return 0;
}

View File

@@ -0,0 +1,200 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_COLOR_MAP_H
#define QWT_COLOR_MAP_H
#include "qwt_global.h"
#include "qwt_interval.h"
#include <qcolor.h>
#include <qvector.h>
/*!
\brief QwtColorMap is used to map values into colors.
For displaying 3D data on a 2D plane the 3rd dimension is often
displayed using colors, like f.e in a spectrogram.
Each color map is optimized to return colors for only one of the
following image formats:
- QImage::Format_Indexed8\n
- QImage::Format_ARGB32\n
\sa QwtPlotSpectrogram, QwtScaleWidget
*/
class QWT_EXPORT QwtColorMap
{
public:
/*!
Format for color mapping
\sa rgb(), colorIndex(), colorTable()
*/
enum Format
{
//! The map is intended to map into RGB values.
RGB,
/*!
The map is intended to map into 8 bit values, that
are indices into the color table.
*/
Indexed
};
QwtColorMap( Format = QwtColorMap::RGB );
virtual ~QwtColorMap();
Format format() const;
/*!
Map a value of a given interval into a RGB value.
\param interval Range for the values
\param value Value
\return RGB value, corresponding to value
*/
virtual QRgb rgb( const QwtInterval &interval,
double value ) const = 0;
/*!
Map a value of a given interval into a color index
\param interval Range for the values
\param value Value
\return color index, corresponding to value
*/
virtual unsigned char colorIndex(
const QwtInterval &interval, double value ) const = 0;
QColor color( const QwtInterval &, double value ) const;
virtual QVector<QRgb> colorTable( const QwtInterval & ) const;
private:
Format d_format;
};
/*!
\brief QwtLinearColorMap builds a color map from color stops.
A color stop is a color at a specific position. The valid
range for the positions is [0.0, 1.0]. When mapping a value
into a color it is translated into this interval according to mode().
*/
class QWT_EXPORT QwtLinearColorMap: public QwtColorMap
{
public:
/*!
Mode of color map
\sa setMode(), mode()
*/
enum Mode
{
//! Return the color from the next lower color stop
FixedColors,
//! Interpolating the colors of the adjacent stops.
ScaledColors
};
QwtLinearColorMap( QwtColorMap::Format = QwtColorMap::RGB );
QwtLinearColorMap( const QColor &from, const QColor &to,
QwtColorMap::Format = QwtColorMap::RGB );
virtual ~QwtLinearColorMap();
void setMode( Mode );
Mode mode() const;
void setColorInterval( const QColor &color1, const QColor &color2 );
void addColorStop( double value, const QColor& );
QVector<double> colorStops() const;
QColor color1() const;
QColor color2() const;
virtual QRgb rgb( const QwtInterval &, double value ) const;
virtual unsigned char colorIndex(
const QwtInterval &, double value ) const;
class ColorStops;
private:
// Disabled copy constructor and operator=
QwtLinearColorMap( const QwtLinearColorMap & );
QwtLinearColorMap &operator=( const QwtLinearColorMap & );
class PrivateData;
PrivateData *d_data;
};
/*!
\brief QwtAlphaColorMap varies the alpha value of a color
*/
class QWT_EXPORT QwtAlphaColorMap: public QwtColorMap
{
public:
QwtAlphaColorMap( const QColor & = QColor( Qt::gray ) );
virtual ~QwtAlphaColorMap();
void setColor( const QColor & );
QColor color() const;
virtual QRgb rgb( const QwtInterval &, double value ) const;
private:
QwtAlphaColorMap( const QwtAlphaColorMap & );
QwtAlphaColorMap &operator=( const QwtAlphaColorMap & );
virtual unsigned char colorIndex(
const QwtInterval &, double value ) const;
class PrivateData;
PrivateData *d_data;
};
/*!
Map a value into a color
\param interval Valid interval for values
\param value Value
\return Color corresponding to value
\warning This method is slow for Indexed color maps. If it is
necessary to map many values, its better to get the
color table once and find the color using colorIndex().
*/
inline QColor QwtColorMap::color(
const QwtInterval &interval, double value ) const
{
if ( d_format == RGB )
{
return QColor::fromRgba( rgb( interval, value ) );
}
else
{
const unsigned int index = colorIndex( interval, value );
return colorTable( interval )[index]; // slow
}
}
/*!
\return Intended format of the color map
\sa Format
*/
inline QwtColorMap::Format QwtColorMap::format() const
{
return d_format;
}
#endif

View File

@@ -0,0 +1,293 @@
/* -*- 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_column_symbol.h"
#include "qwt_math.h"
#include "qwt_painter.h"
#include <qpainter.h>
#include <qpalette.h>
static void qwtDrawBox( QPainter *p, const QRectF &rect,
const QPalette &pal, double lw )
{
if ( lw > 0.0 )
{
if ( rect.width() == 0.0 )
{
p->setPen( pal.dark().color() );
p->drawLine( rect.topLeft(), rect.bottomLeft() );
return;
}
if ( rect.height() == 0.0 )
{
p->setPen( pal.dark().color() );
p->drawLine( rect.topLeft(), rect.topRight() );
return;
}
lw = qMin( lw, rect.height() / 2.0 - 1.0 );
lw = qMin( lw, rect.width() / 2.0 - 1.0 );
const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 );
QPolygonF polygon( outerRect );
if ( outerRect.width() > 2 * lw &&
outerRect.height() > 2 * lw )
{
const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw );
polygon = polygon.subtracted( innerRect );
}
p->setPen( Qt::NoPen );
p->setBrush( pal.dark() );
p->drawPolygon( polygon );
}
const QRectF windowRect = rect.adjusted( lw, lw, -lw + 1, -lw + 1 );
if ( windowRect.isValid() )
p->fillRect( windowRect, pal.window() );
}
static void qwtDrawPanel( QPainter *painter, const QRectF &rect,
const QPalette &pal, double lw )
{
if ( lw > 0.0 )
{
if ( rect.width() == 0.0 )
{
painter->setPen( pal.window().color() );
painter->drawLine( rect.topLeft(), rect.bottomLeft() );
return;
}
if ( rect.height() == 0.0 )
{
painter->setPen( pal.window().color() );
painter->drawLine( rect.topLeft(), rect.topRight() );
return;
}
lw = qMin( lw, rect.height() / 2.0 - 1.0 );
lw = qMin( lw, rect.width() / 2.0 - 1.0 );
const QRectF outerRect = rect.adjusted( 0, 0, 1, 1 );
const QRectF innerRect = outerRect.adjusted( lw, lw, -lw, -lw );
QPolygonF lines[2];
lines[0] += outerRect.bottomLeft();
lines[0] += outerRect.topLeft();
lines[0] += outerRect.topRight();
lines[0] += innerRect.topRight();
lines[0] += innerRect.topLeft();
lines[0] += innerRect.bottomLeft();
lines[1] += outerRect.topRight();
lines[1] += outerRect.bottomRight();
lines[1] += outerRect.bottomLeft();
lines[1] += innerRect.bottomLeft();
lines[1] += innerRect.bottomRight();
lines[1] += innerRect.topRight();
painter->setPen( Qt::NoPen );
painter->setBrush( pal.light() );
painter->drawPolygon( lines[0] );
painter->setBrush( pal.dark() );
painter->drawPolygon( lines[1] );
}
painter->fillRect( rect.adjusted( lw, lw, -lw + 1, -lw + 1 ), pal.window() );
}
class QwtColumnSymbol::PrivateData
{
public:
PrivateData():
style( QwtColumnSymbol::Box ),
frameStyle( QwtColumnSymbol::Raised ),
lineWidth( 2 )
{
palette = QPalette( Qt::gray );
}
QwtColumnSymbol::Style style;
QwtColumnSymbol::FrameStyle frameStyle;
QPalette palette;
int lineWidth;
};
/*!
Constructor
\param style Style of the symbol
\sa setStyle(), style(), Style
*/
QwtColumnSymbol::QwtColumnSymbol( Style style )
{
d_data = new PrivateData();
d_data->style = style;
}
//! Destructor
QwtColumnSymbol::~QwtColumnSymbol()
{
delete d_data;
}
/*!
Specify the symbol style
\param style Style
\sa style(), setPalette()
*/
void QwtColumnSymbol::setStyle( Style style )
{
d_data->style = style;
}
/*!
\return Current symbol style
\sa setStyle()
*/
QwtColumnSymbol::Style QwtColumnSymbol::style() const
{
return d_data->style;
}
/*!
Assign a palette for the symbol
\param palette Palette
\sa palette(), setStyle()
*/
void QwtColumnSymbol::setPalette( const QPalette &palette )
{
d_data->palette = palette;
}
/*!
\return Current palette
\sa setPalette()
*/
const QPalette& QwtColumnSymbol::palette() const
{
return d_data->palette;
}
/*!
Set the frame, that is used for the Box style.
\param frameStyle Frame style
\sa frameStyle(), setLineWidth(), setStyle()
*/
void QwtColumnSymbol::setFrameStyle( FrameStyle frameStyle )
{
d_data->frameStyle = frameStyle;
}
/*!
\return Current frame style, that is used for the Box style.
\sa setFrameStyle(), lineWidth(), setStyle()
*/
QwtColumnSymbol::FrameStyle QwtColumnSymbol::frameStyle() const
{
return d_data->frameStyle;
}
/*!
Set the line width of the frame, that is used for the Box style.
\param width Width
\sa lineWidth(), setFrameStyle()
*/
void QwtColumnSymbol::setLineWidth( int width )
{
if ( width < 0 )
width = 0;
d_data->lineWidth = width;
}
/*!
\return Line width of the frame, that is used for the Box style.
\sa setLineWidth(), frameStyle(), setStyle()
*/
int QwtColumnSymbol::lineWidth() const
{
return d_data->lineWidth;
}
/*!
Draw the symbol depending on its style.
\param painter Painter
\param rect Directed rectangle
\sa drawBox()
*/
void QwtColumnSymbol::draw( QPainter *painter,
const QwtColumnRect &rect ) const
{
painter->save();
switch ( d_data->style )
{
case QwtColumnSymbol::Box:
{
drawBox( painter, rect );
break;
}
default:;
}
painter->restore();
}
/*!
Draw the symbol when it is in Box style.
\param painter Painter
\param rect Directed rectangle
\sa draw()
*/
void QwtColumnSymbol::drawBox( QPainter *painter,
const QwtColumnRect &rect ) const
{
QRectF r = rect.toRect();
if ( QwtPainter::roundingAlignment( painter ) )
{
r.setLeft( qRound( r.left() ) );
r.setRight( qRound( r.right() ) );
r.setTop( qRound( r.top() ) );
r.setBottom( qRound( r.bottom() ) );
}
switch ( d_data->frameStyle )
{
case QwtColumnSymbol::Raised:
{
qwtDrawPanel( painter, r, d_data->palette, d_data->lineWidth );
break;
}
case QwtColumnSymbol::Plain:
{
qwtDrawBox( painter, r, d_data->palette, d_data->lineWidth );
break;
}
default:
{
painter->fillRect( r, d_data->palette.window() );
}
}
}

View File

@@ -0,0 +1,161 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_COLUMN_SYMBOL_H
#define QWT_COLUMN_SYMBOL_H
#include "qwt_global.h"
#include "qwt_interval.h"
#include <qpen.h>
#include <qsize.h>
#include <qrect.h>
class QPainter;
class QPalette;
class QRect;
class QwtText;
/*!
\brief Directed rectangle representing bounding rectangle and orientation
of a column.
*/
class QWT_EXPORT QwtColumnRect
{
public:
//! Direction of the column
enum Direction
{
//! From left to right
LeftToRight,
//! From right to left
RightToLeft,
//! From bottom to top
BottomToTop,
//! From top to bottom
TopToBottom
};
//! Build an rectangle with invalid intervals directed BottomToTop.
QwtColumnRect():
direction( BottomToTop )
{
}
//! \return A normalized QRect built from the intervals
QRectF toRect() const
{
QRectF r( hInterval.minValue(), vInterval.minValue(),
hInterval.maxValue() - hInterval.minValue(),
vInterval.maxValue() - vInterval.minValue() );
r = r.normalized();
if ( hInterval.borderFlags() & QwtInterval::ExcludeMinimum )
r.adjust( 1, 0, 0, 0 );
if ( hInterval.borderFlags() & QwtInterval::ExcludeMaximum )
r.adjust( 0, 0, -1, 0 );
if ( vInterval.borderFlags() & QwtInterval::ExcludeMinimum )
r.adjust( 0, 1, 0, 0 );
if ( vInterval.borderFlags() & QwtInterval::ExcludeMaximum )
r.adjust( 0, 0, 0, -1 );
return r;
}
//! \return Orientation
Qt::Orientation orientation() const
{
if ( direction == LeftToRight || direction == RightToLeft )
return Qt::Horizontal;
return Qt::Vertical;
}
//! Interval for the horizontal coordinates
QwtInterval hInterval;
//! Interval for the vertical coordinates
QwtInterval vInterval;
//! Direction
Direction direction;
};
//! A drawing primitive for columns
class QWT_EXPORT QwtColumnSymbol
{
public:
/*!
Style
\sa setStyle(), style()
*/
enum Style
{
//! No Style, the symbol draws nothing
NoStyle = -1,
/*!
The column is painted with a frame depending on the frameStyle()
and lineWidth() using the palette().
*/
Box,
/*!
Styles >= QwtColumnSymbol::UserStyle are reserved for derived
classes of QwtColumnSymbol that overload draw() with
additional application specific symbol types.
*/
UserStyle = 1000
};
/*!
Frame Style used in Box style().
\sa Style, setFrameStyle(), frameStyle(), setStyle(), setPalette()
*/
enum FrameStyle
{
//! No frame
NoFrame,
//! A plain frame style
Plain,
//! A raised frame style
Raised
};
public:
QwtColumnSymbol( Style = NoStyle );
virtual ~QwtColumnSymbol();
void setFrameStyle( FrameStyle style );
FrameStyle frameStyle() const;
void setLineWidth( int width );
int lineWidth() const;
void setPalette( const QPalette & );
const QPalette &palette() const;
void setStyle( Style );
Style style() const;
virtual void draw( QPainter *, const QwtColumnRect & ) const;
protected:
void drawBox( QPainter *, const QwtColumnRect & ) const;
private:
class PrivateData;
PrivateData* d_data;
};
#endif

View File

@@ -0,0 +1,308 @@
/* -*- 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_compass.h"
#include "qwt_compass_rose.h"
#include "qwt_math.h"
#include "qwt_scale_draw.h"
#include "qwt_painter.h"
#include "qwt_dial_needle.h"
#include <qpainter.h>
#include <qpixmap.h>
#include <qevent.h>
/*!
\brief Constructor
Initializes a label map for multiples of 45 degrees
*/
QwtCompassScaleDraw::QwtCompassScaleDraw()
{
enableComponent( QwtAbstractScaleDraw::Backbone, false );
enableComponent( QwtAbstractScaleDraw::Ticks, false );
d_labelMap.insert( 0.0, QString::fromLatin1( "N" ) );
d_labelMap.insert( 45.0, QString::fromLatin1( "NE" ) );
d_labelMap.insert( 90.0, QString::fromLatin1( "E" ) );
d_labelMap.insert( 135.0, QString::fromLatin1( "SE" ) );
d_labelMap.insert( 180.0, QString::fromLatin1( "S" ) );
d_labelMap.insert( 225.0, QString::fromLatin1( "SW" ) );
d_labelMap.insert( 270.0, QString::fromLatin1( "W" ) );
d_labelMap.insert( 315.0, QString::fromLatin1( "NW" ) );
#if 0
d_labelMap.insert( 22.5, QString::fromLatin1( "NNE" ) );
d_labelMap.insert( 67.5, QString::fromLatin1( "NEE" ) );
d_labelMap.insert( 112.5, QString::fromLatin1( "SEE" ) );
d_labelMap.insert( 157.5, QString::fromLatin1( "SSE" ) );
d_labelMap.insert( 202.5, QString::fromLatin1( "SSW" ) );
d_labelMap.insert( 247.5, QString::fromLatin1( "SWW" ) );
d_labelMap.insert( 292.5, QString::fromLatin1( "NWW" ) );
d_labelMap.insert( 337.5, QString::fromLatin1( "NNW" ) );
#endif
}
/*!
\brief Constructor
\param map Value to label map
*/
QwtCompassScaleDraw::QwtCompassScaleDraw( const QMap<double, QString> &map ):
d_labelMap( map )
{
enableComponent( QwtAbstractScaleDraw::Backbone, false );
enableComponent( QwtAbstractScaleDraw::Ticks, false );
}
/*!
\brief Set a map, mapping values to labels
\param map Value to label map
The values of the major ticks are found by looking into this
map. The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
\warning The map will have no effect for values that are no major
tick values. Major ticks can be changed by QwtScaleDraw::setScale
\sa labelMap(), scaleDraw(), setScale()
*/
void QwtCompassScaleDraw::setLabelMap( const QMap<double, QString> &map )
{
d_labelMap = map;
}
/*!
\return map, mapping values to labels
\sa setLabelMap()
*/
QMap<double, QString> QwtCompassScaleDraw::labelMap() const
{
return d_labelMap;
}
/*!
Map a value to a corresponding label
\param value Value that will be mapped
label() looks in the labelMap() for a corresponding label for value
or returns an null text.
\return Label, or QString::null
\sa labelMap(), setLabelMap()
*/
QwtText QwtCompassScaleDraw::label( double value ) const
{
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
value = 0.0;
if ( value < 0.0 )
value += 360.0;
if ( d_labelMap.contains( value ) )
return d_labelMap[value];
return QwtText();
}
class QwtCompass::PrivateData
{
public:
PrivateData():
rose( NULL )
{
}
~PrivateData()
{
delete rose;
}
QwtCompassRose *rose;
};
/*!
\brief Constructor
\param parent Parent widget
Create a compass widget with a scale, no needle and no rose.
The default origin is 270.0 with no valid value. It accepts
mouse and keyboard inputs and has no step size. The default mode
is QwtDial::RotateNeedle.
*/
QwtCompass::QwtCompass( QWidget* parent ):
QwtDial( parent )
{
d_data = new PrivateData;
setScaleDraw( new QwtCompassScaleDraw() );
setOrigin( 270.0 );
setWrapping( true );
setScaleMaxMajor( 36 );
setScaleMaxMinor( 10 );
setScale( 0.0, 360.0 ); // degrees as default
setTotalSteps( 360 );
}
//! Destructor
QwtCompass::~QwtCompass()
{
delete d_data;
}
/*!
Draw the contents of the scale
\param painter Painter
\param center Center of the content circle
\param radius Radius of the content circle
*/
void QwtCompass::drawScaleContents( QPainter *painter,
const QPointF &center, double radius ) const
{
QPalette::ColorGroup cg;
if ( isEnabled() )
cg = hasFocus() ? QPalette::Active : QPalette::Inactive;
else
cg = QPalette::Disabled;
double north = origin();
if ( isValid() )
{
if ( mode() == RotateScale )
north -= value();
}
const int margin = 4;
drawRose( painter, center, radius - margin, 360.0 - north, cg );
}
/*!
Draw the compass rose
\param painter Painter
\param center Center of the compass
\param radius of the circle, where to paint the rose
\param north Direction pointing north, in degrees counter clockwise
\param cg Color group
*/
void QwtCompass::drawRose( QPainter *painter, const QPointF &center,
double radius, double north, QPalette::ColorGroup cg ) const
{
if ( d_data->rose )
d_data->rose->draw( painter, center, radius, north, cg );
}
/*!
Set a rose for the compass
\param rose Compass rose
\warning The rose will be deleted, when a different rose is
set or in ~QwtCompass
\sa rose()
*/
void QwtCompass::setRose( QwtCompassRose *rose )
{
if ( rose != d_data->rose )
{
if ( d_data->rose )
delete d_data->rose;
d_data->rose = rose;
update();
}
}
/*!
\return rose
\sa setRose()
*/
const QwtCompassRose *QwtCompass::rose() const
{
return d_data->rose;
}
/*!
\return rose
\sa setRose()
*/
QwtCompassRose *QwtCompass::rose()
{
return d_data->rose;
}
/*!
Handles key events
Beside the keys described in QwtDial::keyPressEvent numbers
from 1-9 (without 5) set the direction according to their
position on the num pad.
\sa isReadOnly()
*/
void QwtCompass::keyPressEvent( QKeyEvent *kev )
{
if ( isReadOnly() )
return;
#if 0
if ( kev->key() == Key_5 )
{
invalidate(); // signal ???
return;
}
#endif
double newValue = value();
if ( kev->key() >= Qt::Key_1 && kev->key() <= Qt::Key_9 )
{
if ( mode() != RotateNeedle || kev->key() == Qt::Key_5 )
return;
switch ( kev->key() )
{
case Qt::Key_6:
newValue = 180.0 * 0.0;
break;
case Qt::Key_3:
newValue = 180.0 * 0.25;
break;
case Qt::Key_2:
newValue = 180.0 * 0.5;
break;
case Qt::Key_1:
newValue = 180.0 * 0.75;
break;
case Qt::Key_4:
newValue = 180.0 * 1.0;
break;
case Qt::Key_7:
newValue = 180.0 * 1.25;
break;
case Qt::Key_8:
newValue = 180.0 * 1.5;
break;
case Qt::Key_9:
newValue = 180.0 * 1.75;
break;
}
newValue -= origin();
setValue( newValue );
}
else
{
QwtDial::keyPressEvent( kev );
}
}

View File

@@ -0,0 +1,83 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_COMPASS_H
#define QWT_COMPASS_H 1
#include "qwt_global.h"
#include "qwt_dial.h"
#include "qwt_round_scale_draw.h"
#include <qstring.h>
#include <qmap.h>
class QwtCompassRose;
/*!
\brief A special scale draw made for QwtCompass
QwtCompassScaleDraw maps values to strings using
a special map, that can be modified by the application
The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
\sa QwtCompass
*/
class QWT_EXPORT QwtCompassScaleDraw: public QwtRoundScaleDraw
{
public:
explicit QwtCompassScaleDraw();
explicit QwtCompassScaleDraw( const QMap<double, QString> &map );
void setLabelMap( const QMap<double, QString> &map );
QMap<double, QString> labelMap() const;
virtual QwtText label( double value ) const;
private:
QMap<double, QString> d_labelMap;
};
/*!
\brief A Compass Widget
QwtCompass is a widget to display and enter directions. It consists
of a scale, an optional needle and rose.
\image html dials1.png
\note The examples/dials example shows how to use QwtCompass.
*/
class QWT_EXPORT QwtCompass: public QwtDial
{
Q_OBJECT
public:
explicit QwtCompass( QWidget* parent = NULL );
virtual ~QwtCompass();
void setRose( QwtCompassRose *rose );
const QwtCompassRose *rose() const;
QwtCompassRose *rose();
protected:
virtual void drawRose( QPainter *, const QPointF &center,
double radius, double north, QPalette::ColorGroup ) const;
virtual void drawScaleContents( QPainter *,
const QPointF &center, double radius ) const;
virtual void keyPressEvent( QKeyEvent * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,269 @@
/* -*- 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_compass_rose.h"
#include "qwt_point_polar.h"
#include "qwt_painter.h"
#include <qpainter.h>
static QPointF qwtIntersection(
QPointF p11, QPointF p12, QPointF p21, QPointF p22 )
{
const QLineF line1( p11, p12 );
const QLineF line2( p21, p22 );
QPointF pos;
if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection )
return QPointF();
return pos;
}
class QwtSimpleCompassRose::PrivateData
{
public:
PrivateData():
width( 0.2 ),
numThorns( 8 ),
numThornLevels( -1 ),
shrinkFactor( 0.9 )
{
}
double width;
int numThorns;
int numThornLevels;
double shrinkFactor;
};
/*!
Constructor
\param numThorns Number of thorns
\param numThornLevels Number of thorn levels
*/
QwtSimpleCompassRose::QwtSimpleCompassRose(
int numThorns, int numThornLevels )
{
d_data = new PrivateData();
d_data->numThorns = numThorns;
d_data->numThornLevels = numThornLevels;
const QColor dark( 128, 128, 255 );
const QColor light( 192, 255, 255 );
QPalette palette;
palette.setColor( QPalette::Dark, dark );
palette.setColor( QPalette::Light, light );
setPalette( palette );
}
//! Destructor
QwtSimpleCompassRose::~QwtSimpleCompassRose()
{
delete d_data;
}
/*!
Set the Factor how to shrink the thorns with each level
The default value is 0.9.
\param factor Shrink factor
\sa shrinkFactor()
*/
void QwtSimpleCompassRose::setShrinkFactor( double factor )
{
d_data->shrinkFactor = factor;
}
/*!
\return Factor how to shrink the thorns with each level
\sa setShrinkFactor()
*/
double QwtSimpleCompassRose::shrinkFactor() const
{
return d_data->shrinkFactor;
}
/*!
Draw the rose
\param painter Painter
\param center Center point
\param radius Radius of the rose
\param north Position
\param cg Color group
*/
void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF &center,
double radius, double north, QPalette::ColorGroup cg ) const
{
QPalette pal = palette();
pal.setCurrentColorGroup( cg );
drawRose( painter, pal, center, radius, north, d_data->width,
d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor );
}
/*!
Draw the rose
\param painter Painter
\param palette Palette
\param center Center of the rose
\param radius Radius of the rose
\param north Position pointing to north
\param width Width of the rose
\param numThorns Number of thorns
\param numThornLevels Number of thorn levels
\param shrinkFactor Factor to shrink the thorns with each level
*/
void QwtSimpleCompassRose::drawRose(
QPainter *painter,
const QPalette &palette,
const QPointF &center, double radius, double north, double width,
int numThorns, int numThornLevels, double shrinkFactor )
{
if ( numThorns < 4 )
numThorns = 4;
if ( numThorns % 4 )
numThorns += 4 - numThorns % 4;
if ( numThornLevels <= 0 )
numThornLevels = numThorns / 4;
if ( shrinkFactor >= 1.0 )
shrinkFactor = 1.0;
if ( shrinkFactor <= 0.5 )
shrinkFactor = 0.5;
painter->save();
painter->setPen( Qt::NoPen );
for ( int j = 1; j <= numThornLevels; j++ )
{
double step = qPow( 2.0, j ) * M_PI / numThorns;
if ( step > M_PI_2 )
break;
double r = radius;
for ( int k = 0; k < 3; k++ )
{
if ( j + k < numThornLevels )
r *= shrinkFactor;
}
double leafWidth = r * width;
if ( 2.0 * M_PI / step > 32 )
leafWidth = 16;
const double origin = qwtRadians( north );
for ( double angle = origin;
angle < 2.0 * M_PI + origin; angle += step )
{
const QPointF p = qwtPolar2Pos( center, r, angle );
const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 );
const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 );
const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 );
const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 );
QPainterPath darkPath;
darkPath.moveTo( center );
darkPath.lineTo( p );
darkPath.lineTo( qwtIntersection( center, p3, p1, p ) );
painter->setBrush( palette.brush( QPalette::Dark ) );
painter->drawPath( darkPath );
QPainterPath lightPath;
lightPath.moveTo( center );
lightPath.lineTo( p );
lightPath.lineTo( qwtIntersection( center, p4, p2, p ) );
painter->setBrush( palette.brush( QPalette::Light ) );
painter->drawPath( lightPath );
}
}
painter->restore();
}
/*!
Set the width of the rose heads. Lower value make thinner heads.
The range is limited from 0.03 to 0.4.
\param width Width
*/
void QwtSimpleCompassRose::setWidth( double width )
{
d_data->width = width;
if ( d_data->width < 0.03 )
d_data->width = 0.03;
if ( d_data->width > 0.4 )
d_data->width = 0.4;
}
/*!
\return Width of the rose
\sa setWidth()
*/
double QwtSimpleCompassRose::width() const
{
return d_data->width;
}
/*!
Set the number of thorns on one level
The number is aligned to a multiple of 4, with a minimum of 4
\param numThorns Number of thorns
\sa numThorns(), setNumThornLevels()
*/
void QwtSimpleCompassRose::setNumThorns( int numThorns )
{
if ( numThorns < 4 )
numThorns = 4;
if ( numThorns % 4 )
numThorns += 4 - numThorns % 4;
d_data->numThorns = numThorns;
}
/*!
\return Number of thorns
\sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThorns() const
{
return d_data->numThorns;
}
/*!
Set the of thorns levels
\param numThornLevels Number of thorns levels
\sa setNumThorns(), numThornLevels()
*/
void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels )
{
d_data->numThornLevels = numThornLevels;
}
/*!
\return Number of thorn levels
\sa setNumThorns(), setNumThornLevels()
*/
int QwtSimpleCompassRose::numThornLevels() const
{
return d_data->numThornLevels;
}

View File

@@ -0,0 +1,89 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_COMPASS_ROSE_H
#define QWT_COMPASS_ROSE_H 1
#include "qwt_global.h"
#include <qpalette.h>
class QPainter;
/*!
\brief Abstract base class for a compass rose
*/
class QWT_EXPORT QwtCompassRose
{
public:
//! Destructor
virtual ~QwtCompassRose() {};
//! Assign a palette
virtual void setPalette( const QPalette &p )
{
d_palette = p;
}
//! \return Current palette
const QPalette &palette() const
{
return d_palette;
}
/*!
Draw the rose
\param painter Painter
\param center Center point
\param radius Radius of the rose
\param north Position
\param colorGroup Color group
*/
virtual void draw( QPainter *painter,
const QPointF &center, double radius, double north,
QPalette::ColorGroup colorGroup = QPalette::Active ) const = 0;
private:
QPalette d_palette;
};
/*!
\brief A simple rose for QwtCompass
*/
class QWT_EXPORT QwtSimpleCompassRose: public QwtCompassRose
{
public:
QwtSimpleCompassRose( int numThorns = 8, int numThornLevels = -1 );
virtual ~QwtSimpleCompassRose();
void setWidth( double w );
double width() const;
void setNumThorns( int count );
int numThorns() const;
void setNumThornLevels( int count );
int numThornLevels() const;
void setShrinkFactor( double factor );
double shrinkFactor() const;
virtual void draw( QPainter *, const QPointF &center, double radius,
double north, QPalette::ColorGroup = QPalette::Active ) const;
static void drawRose( QPainter *, const QPalette &,
const QPointF &center, double radius, double origin, double width,
int numThorns, int numThornLevels, double shrinkFactor );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,42 @@
/* -*- 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
*****************************************************************************/
#ifndef _QWT_COMPAT_H_
#define _QWT_COMPAT_H_
#include "qwt_global.h"
#include "qwt_interval.h"
#include "qwt_point_3d.h"
#include <qlist.h>
#include <qvector.h>
#include <qpoint.h>
#include <qsize.h>
#include <qrect.h>
#include <qpolygon.h>
// A couple of definition for Qwt5 compatibility
#define qwtMax qMax
#define qwtMin qMin
#define qwtAbs qAbs
#define qwtRound qRound
#define QwtArray QVector
typedef QList<double> QwtValueList;
typedef QPointF QwtDoublePoint;
typedef QSizeF QwtDoubleSize;
typedef QRectF QwtDoubleRect;
typedef QPolygon QwtPolygon;
typedef QPolygonF QwtPolygonF;
typedef QwtInterval QwtDoubleInterval;
typedef QwtPoint3D QwtDoublePoint3D;
#endif

View File

@@ -0,0 +1,785 @@
/* -*- 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_arrow_button.h"
#include "qwt_math.h"
#include "qwt_counter.h"
#include <qlayout.h>
#include <qlineedit.h>
#include <qvalidator.h>
#include <qevent.h>
#include <qstyle.h>
class QwtCounter::PrivateData
{
public:
PrivateData():
minimum( 0.0 ),
maximum( 0.0 ),
singleStep( 1.0 ),
isValid( false ),
value( 0.0 ),
wrapping( false )
{
increment[Button1] = 1;
increment[Button2] = 10;
increment[Button3] = 100;
}
QwtArrowButton *buttonDown[ButtonCnt];
QwtArrowButton *buttonUp[ButtonCnt];
QLineEdit *valueEdit;
int increment[ButtonCnt];
int numButtons;
double minimum;
double maximum;
double singleStep;
bool isValid;
double value;
bool wrapping;
};
/*!
The counter is initialized with a range is set to [0.0, 1.0] with
0.01 as single step size. The value is invalid.
The default number of buttons is set to 2. The default increments are:
\li Button 1: 1 step
\li Button 2: 10 steps
\li Button 3: 100 steps
\param parent
*/
QwtCounter::QwtCounter( QWidget *parent ):
QWidget( parent )
{
initCounter();
}
void QwtCounter::initCounter()
{
d_data = new PrivateData;
QHBoxLayout *layout = new QHBoxLayout( this );
layout->setSpacing( 0 );
layout->setMargin( 0 );
for ( int i = ButtonCnt - 1; i >= 0; i-- )
{
QwtArrowButton *btn =
new QwtArrowButton( i + 1, Qt::DownArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
btn->installEventFilter( this );
layout->addWidget( btn );
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
d_data->buttonDown[i] = btn;
}
d_data->valueEdit = new QLineEdit( this );
d_data->valueEdit->setReadOnly( false );
d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
layout->addWidget( d_data->valueEdit );
connect( d_data->valueEdit, SIGNAL( editingFinished() ),
SLOT( textChanged() ) );
layout->setStretchFactor( d_data->valueEdit, 10 );
for ( int i = 0; i < ButtonCnt; i++ )
{
QwtArrowButton *btn =
new QwtArrowButton( i + 1, Qt::UpArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
btn->installEventFilter( this );
layout->addWidget( btn );
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
d_data->buttonUp[i] = btn;
}
setNumButtons( 2 );
setRange( 0.0, 1.0 );
setSingleStep( 0.001 );
setValue( 0.0 );
setSizePolicy(
QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
setFocusProxy( d_data->valueEdit );
setFocusPolicy( Qt::StrongFocus );
}
//! Destructor
QwtCounter::~QwtCounter()
{
delete d_data;
}
/*!
Set the counter to be in valid/invalid state
When the counter is set to invalid, no numbers are displayed and
the buttons are disabled.
\param on If true the counter will be set as valid
\sa setValue(), isValid()
*/
void QwtCounter::setValid( bool on )
{
if ( on != d_data->isValid )
{
d_data->isValid = on;
updateButtons();
if ( d_data->isValid )
{
showNumber( value() );
Q_EMIT valueChanged( value() );
}
else
{
d_data->valueEdit->setText( QString::null );
}
}
}
/*!
\return True, if the value is valid
\sa setValid(), setValue()
*/
bool QwtCounter::isValid() const
{
return d_data->isValid;
}
/*!
\brief Allow/disallow the user to manually edit the value
\param on True disable editing
\sa isReadOnly()
*/
void QwtCounter::setReadOnly( bool on )
{
d_data->valueEdit->setReadOnly( on );
}
/*!
\return True, when the line line edit is read only. (default is no)
\sa setReadOnly()
*/
bool QwtCounter::isReadOnly() const
{
return d_data->valueEdit->isReadOnly();
}
/*!
\brief Set a new value without adjusting to the step raster
The state of the counter is set to be valid.
\param value New value
\sa isValid(), value(), valueChanged()
\warning The value is clipped when it lies outside the range.
*/
void QwtCounter::setValue( double value )
{
const double vmin = qMin( d_data->minimum, d_data->maximum );
const double vmax = qMax( d_data->minimum, d_data->maximum );
value = qBound( vmin, value, vmax );
if ( !d_data->isValid || value != d_data->value )
{
d_data->isValid = true;
d_data->value = value;
showNumber( value );
updateButtons();
Q_EMIT valueChanged( value );
}
}
/*!
\return Current value of the counter
\sa setValue(), valueChanged()
*/
double QwtCounter::value() const
{
return d_data->value;
}
/*!
\brief Set the minimum and maximum values
The maximum is adjusted if necessary to ensure that the range remains valid.
The value might be modified to be inside of the range.
\param min Minimum value
\param max Maximum value
\sa minimum(), maximum()
*/
void QwtCounter::setRange( double min, double max )
{
max = qMax( min, max );
if ( d_data->maximum == max && d_data->minimum == min )
return;
d_data->minimum = min;
d_data->maximum = max;
setSingleStep( singleStep() );
const double value = qBound( min, d_data->value, max );
if ( value != d_data->value )
{
d_data->value = value;
if ( d_data->isValid )
{
showNumber( value );
Q_EMIT valueChanged( value );
}
}
updateButtons();
}
/*!
Set the minimum value of the range
\param value Minimum value
\sa setRange(), setMaximum(), minimum()
\note The maximum is adjusted if necessary to ensure that the range remains valid.
*/
void QwtCounter::setMinimum( double value )
{
setRange( value, maximum() );
}
/*!
\return The minimum of the range
\sa setRange(), setMinimum(), maximum()
*/
double QwtCounter::minimum() const
{
return d_data->minimum;
}
/*!
Set the maximum value of the range
\param value Maximum value
\sa setRange(), setMinimum(), maximum()
*/
void QwtCounter::setMaximum( double value )
{
setRange( minimum(), value );
}
/*!
\return The maximum of the range
\sa setRange(), setMaximum(), minimum()
*/
double QwtCounter::maximum() const
{
return d_data->maximum;
}
/*!
\brief Set the step size of the counter
A value <= 0.0 disables stepping
\param stepSize Single step size
\sa singleStep()
*/
void QwtCounter::setSingleStep( double stepSize )
{
d_data->singleStep = qMax( stepSize, 0.0 );
}
/*!
\return Single step size
\sa setSingleStep()
*/
double QwtCounter::singleStep() const
{
return d_data->singleStep;
}
/*!
\brief En/Disable wrapping
If wrapping is true stepping up from maximum() value will take
you to the minimum() value and vice versa.
\param on En/Disable wrapping
\sa wrapping()
*/
void QwtCounter::setWrapping( bool on )
{
d_data->wrapping = on;
}
/*!
\return True, when wrapping is set
\sa setWrapping()
*/
bool QwtCounter::wrapping() const
{
return d_data->wrapping;
}
/*!
Specify the number of buttons on each side of the label
\param numButtons Number of buttons
\sa numButtons()
*/
void QwtCounter::setNumButtons( int numButtons )
{
if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
return;
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
{
if ( i < numButtons )
{
d_data->buttonDown[i]->show();
d_data->buttonUp[i]->show();
}
else
{
d_data->buttonDown[i]->hide();
d_data->buttonUp[i]->hide();
}
}
d_data->numButtons = numButtons;
}
/*!
\return The number of buttons on each side of the widget.
\sa setNumButtons()
*/
int QwtCounter::numButtons() const
{
return d_data->numButtons;
}
/*!
Specify the number of steps by which the value
is incremented or decremented when a specified button
is pushed.
\param button Button index
\param numSteps Number of steps
\sa incSteps()
*/
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
d_data->increment[ button ] = numSteps;
}
/*!
\return The number of steps by which a specified button increments the value
or 0 if the button is invalid.
\param button Button index
\sa setIncSteps()
*/
int QwtCounter::incSteps( QwtCounter::Button button ) const
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
return d_data->increment[ button ];
return 0;
}
/*!
Set the number of increment steps for button 1
\param nSteps Number of steps
*/
void QwtCounter::setStepButton1( int nSteps )
{
setIncSteps( QwtCounter::Button1, nSteps );
}
//! returns the number of increment steps for button 1
int QwtCounter::stepButton1() const
{
return incSteps( QwtCounter::Button1 );
}
/*!
Set the number of increment steps for button 2
\param nSteps Number of steps
*/
void QwtCounter::setStepButton2( int nSteps )
{
setIncSteps( QwtCounter::Button2, nSteps );
}
//! returns the number of increment steps for button 2
int QwtCounter::stepButton2() const
{
return incSteps( QwtCounter::Button2 );
}
/*!
Set the number of increment steps for button 3
\param nSteps Number of steps
*/
void QwtCounter::setStepButton3( int nSteps )
{
setIncSteps( QwtCounter::Button3, nSteps );
}
//! returns the number of increment steps for button 3
int QwtCounter::stepButton3() const
{
return incSteps( QwtCounter::Button3 );
}
//! Set from lineedit
void QwtCounter::textChanged()
{
bool converted = false;
const double value = d_data->valueEdit->text().toDouble( &converted );
if ( converted )
setValue( value );
}
/*!
Handle QEvent::PolishRequest events
\param event Event
\return see QWidget::event()
*/
bool QwtCounter::event( QEvent *event )
{
if ( event->type() == QEvent::PolishRequest )
{
const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
for ( int i = 0; i < ButtonCnt; i++ )
{
d_data->buttonDown[i]->setMinimumWidth( w );
d_data->buttonUp[i]->setMinimumWidth( w );
}
}
return QWidget::event( event );
}
/*!
Handle key events
- Ctrl + Qt::Key_Home\n
Step to minimum()
- Ctrl + Qt::Key_End\n
Step to maximum()
- Qt::Key_Up\n
Increment by incSteps(QwtCounter::Button1)
- Qt::Key_Down\n
Decrement by incSteps(QwtCounter::Button1)
- Qt::Key_PageUp\n
Increment by incSteps(QwtCounter::Button2)
- Qt::Key_PageDown\n
Decrement by incSteps(QwtCounter::Button2)
- Shift + Qt::Key_PageUp\n
Increment by incSteps(QwtCounter::Button3)
- Shift + Qt::Key_PageDown\n
Decrement by incSteps(QwtCounter::Button3)
\param event Key event
*/
void QwtCounter::keyPressEvent ( QKeyEvent *event )
{
bool accepted = true;
switch ( event->key() )
{
case Qt::Key_Home:
{
if ( event->modifiers() & Qt::ControlModifier )
setValue( minimum() );
else
accepted = false;
break;
}
case Qt::Key_End:
{
if ( event->modifiers() & Qt::ControlModifier )
setValue( maximum() );
else
accepted = false;
break;
}
case Qt::Key_Up:
{
incrementValue( d_data->increment[0] );
break;
}
case Qt::Key_Down:
{
incrementValue( -d_data->increment[0] );
break;
}
case Qt::Key_PageUp:
case Qt::Key_PageDown:
{
int increment = d_data->increment[0];
if ( d_data->numButtons >= 2 )
increment = d_data->increment[1];
if ( d_data->numButtons >= 3 )
{
if ( event->modifiers() & Qt::ShiftModifier )
increment = d_data->increment[2];
}
if ( event->key() == Qt::Key_PageDown )
increment = -increment;
incrementValue( increment );
break;
}
default:
{
accepted = false;
}
}
if ( accepted )
{
event->accept();
return;
}
QWidget::keyPressEvent ( event );
}
/*!
Handle wheel events
\param event Wheel event
*/
void QwtCounter::wheelEvent( QWheelEvent *event )
{
event->accept();
if ( d_data->numButtons <= 0 )
return;
int increment = d_data->increment[0];
if ( d_data->numButtons >= 2 )
{
if ( event->modifiers() & Qt::ControlModifier )
increment = d_data->increment[1];
}
if ( d_data->numButtons >= 3 )
{
if ( event->modifiers() & Qt::ShiftModifier )
increment = d_data->increment[2];
}
for ( int i = 0; i < d_data->numButtons; i++ )
{
if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
d_data->buttonUp[i]->geometry().contains( event->pos() ) )
{
increment = d_data->increment[i];
}
}
const int wheel_delta = 120;
#if 1
int delta = event->delta();
if ( delta >= 2 * wheel_delta )
delta /= 2; // Never saw an abs(delta) < 240
#endif
incrementValue( delta / wheel_delta * increment );
}
void QwtCounter::incrementValue( int numSteps )
{
const double min = d_data->minimum;
const double max = d_data->maximum;
double stepSize = d_data->singleStep;
if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
return;
#if 1
stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
#endif
double value = d_data->value + numSteps * stepSize;
if ( d_data->wrapping )
{
const double range = max - min;
if ( value < min )
{
value += ::ceil( ( min - value ) / range ) * range;
}
else if ( value > max )
{
value -= ::ceil( ( value - max ) / range ) * range;
}
}
else
{
value = qBound( min, value, max );
}
value = min + qRound( ( value - min ) / stepSize ) * stepSize;
if ( stepSize > 1e-12 )
{
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
{
// correct rounding error if value = 0
value = 0.0;
}
else if ( qFuzzyCompare( value, max ) )
{
// correct rounding error at the border
value = max;
}
}
if ( value != d_data->value )
{
d_data->value = value;
showNumber( d_data->value );
updateButtons();
Q_EMIT valueChanged( d_data->value );
}
}
/*!
\brief Update buttons according to the current value
When the QwtCounter under- or over-flows, the focus is set to the smallest
up- or down-button and counting is disabled.
Counting is re-enabled on a button release event (mouse or space bar).
*/
void QwtCounter::updateButtons()
{
if ( d_data->isValid )
{
// 1. save enabled state of the smallest down- and up-button
// 2. change enabled state on under- or over-flow
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
{
d_data->buttonDown[i]->setEnabled( value() > minimum() );
d_data->buttonUp[i]->setEnabled( value() < maximum() );
}
}
else
{
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
{
d_data->buttonDown[i]->setEnabled( false );
d_data->buttonUp[i]->setEnabled( false );
}
}
}
/*!
Display number string
\param number Number
*/
void QwtCounter::showNumber( double number )
{
QString text;
text.setNum( number );
const int cursorPos = d_data->valueEdit->cursorPosition();
d_data->valueEdit->setText( text );
d_data->valueEdit->setCursorPosition( cursorPos );
}
//! Button clicked
void QwtCounter::btnClicked()
{
for ( int i = 0; i < ButtonCnt; i++ )
{
if ( d_data->buttonUp[i] == sender() )
incrementValue( d_data->increment[i] );
if ( d_data->buttonDown[i] == sender() )
incrementValue( -d_data->increment[i] );
}
}
//! Button released
void QwtCounter::btnReleased()
{
Q_EMIT buttonReleased( value() );
}
//! A size hint
QSize QwtCounter::sizeHint() const
{
QString tmp;
int w = tmp.setNum( minimum() ).length();
int w1 = tmp.setNum( maximum() ).length();
if ( w1 > w )
w = w1;
w1 = tmp.setNum( minimum() + singleStep() ).length();
if ( w1 > w )
w = w1;
w1 = tmp.setNum( maximum() - singleStep() ).length();
if ( w1 > w )
w = w1;
tmp.fill( '9', w );
QFontMetrics fm( d_data->valueEdit->font() );
w = fm.width( tmp ) + 2;
if ( d_data->valueEdit->hasFrame() )
w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
// Now we replace default sizeHint contribution of d_data->valueEdit by
// what we really need.
w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
const int h = qMin( QWidget::sizeHint().height(),
d_data->valueEdit->minimumSizeHint().height() );
return QSize( w, h );
}

View File

@@ -0,0 +1,161 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_COUNTER_H
#define QWT_COUNTER_H
#include "qwt_global.h"
#include <qwidget.h>
/*!
\brief The Counter Widget
A Counter consists of a label displaying a number and
one ore more (up to three) push buttons on each side
of the label which can be used to increment or decrement
the counter's value.
A counter has a range from a minimum value to a maximum value
and a step size. When the wrapping property is set
the counter is circular.
The number of steps by which a button increments or decrements the value
can be specified using setIncSteps(). The number of buttons can be
changed with setNumButtons().
Example:
\code
#include <qwt_counter.h>
QwtCounter *counter = new QwtCounter(parent);
counter->setRange(0.0, 100.0); // From 0.0 to 100
counter->setSingleStep( 1.0 ); // Step size 1.0
counter->setNumButtons(2); // Two buttons each side
counter->setIncSteps(QwtCounter::Button1, 1); // Button 1 increments 1 step
counter->setIncSteps(QwtCounter::Button2, 20); // Button 2 increments 20 steps
connect(counter, SIGNAL(valueChanged(double)), myClass, SLOT(newValue(double)));
\endcode
*/
class QWT_EXPORT QwtCounter : public QWidget
{
Q_OBJECT
Q_PROPERTY( double value READ value WRITE setValue )
Q_PROPERTY( double minimum READ minimum WRITE setMinimum )
Q_PROPERTY( double maximum READ maximum WRITE setMaximum )
Q_PROPERTY( double singleStep READ singleStep WRITE setSingleStep )
Q_PROPERTY( int numButtons READ numButtons WRITE setNumButtons )
Q_PROPERTY( int stepButton1 READ stepButton1 WRITE setStepButton1 )
Q_PROPERTY( int stepButton2 READ stepButton2 WRITE setStepButton2 )
Q_PROPERTY( int stepButton3 READ stepButton3 WRITE setStepButton3 )
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
public:
//! Button index
enum Button
{
//! Button intended for minor steps
Button1,
//! Button intended for medium steps
Button2,
//! Button intended for large steps
Button3,
//! Number of buttons
ButtonCnt
};
explicit QwtCounter( QWidget *parent = NULL );
virtual ~QwtCounter();
void setValid( bool );
bool isValid() const;
void setWrapping( bool );
bool wrapping() const;
bool isReadOnly() const;
void setReadOnly( bool );
void setNumButtons( int n );
int numButtons() const;
void setIncSteps( QwtCounter::Button btn, int nSteps );
int incSteps( QwtCounter::Button btn ) const;
virtual QSize sizeHint() const;
double singleStep() const;
void setSingleStep( double s );
void setRange( double min, double max );
double minimum() const;
void setMinimum( double min );
double maximum() const;
void setMaximum( double max );
void setStepButton1( int nSteps );
int stepButton1() const;
void setStepButton2( int nSteps );
int stepButton2() const;
void setStepButton3( int nSteps );
int stepButton3() const;
double value() const;
public Q_SLOTS:
void setValue( double );
Q_SIGNALS:
/*!
This signal is emitted when a button has been released
\param value The new value
*/
void buttonReleased ( double value );
/*!
This signal is emitted when the counter's value has changed
\param value The new value
*/
void valueChanged ( double value );
protected:
virtual bool event( QEvent * );
virtual void wheelEvent( QWheelEvent * );
virtual void keyPressEvent( QKeyEvent * );
private Q_SLOTS:
void btnReleased();
void btnClicked();
void textChanged();
private:
void incrementValue( int numSteps );
void initCounter();
void updateButtons();
void showNumber( double );
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,453 @@
/* -*- 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_curve_fitter.h"
#include "qwt_math.h"
#include "qwt_spline.h"
#include <qstack.h>
#include <qvector.h>
#if QT_VERSION < 0x040601
#define qFabs(x) ::fabs(x)
#endif
//! Constructor
QwtCurveFitter::QwtCurveFitter()
{
}
//! Destructor
QwtCurveFitter::~QwtCurveFitter()
{
}
class QwtSplineCurveFitter::PrivateData
{
public:
PrivateData():
fitMode( QwtSplineCurveFitter::Auto ),
splineSize( 250 )
{
}
QwtSpline spline;
QwtSplineCurveFitter::FitMode fitMode;
int splineSize;
};
//! Constructor
QwtSplineCurveFitter::QwtSplineCurveFitter()
{
d_data = new PrivateData;
}
//! Destructor
QwtSplineCurveFitter::~QwtSplineCurveFitter()
{
delete d_data;
}
/*!
Select the algorithm used for building the spline
\param mode Mode representing a spline algorithm
\sa fitMode()
*/
void QwtSplineCurveFitter::setFitMode( FitMode mode )
{
d_data->fitMode = mode;
}
/*!
\return Mode representing a spline algorithm
\sa setFitMode()
*/
QwtSplineCurveFitter::FitMode QwtSplineCurveFitter::fitMode() const
{
return d_data->fitMode;
}
/*!
Assign a spline
\param spline Spline
\sa spline()
*/
void QwtSplineCurveFitter::setSpline( const QwtSpline &spline )
{
d_data->spline = spline;
d_data->spline.reset();
}
/*!
\return Spline
\sa setSpline()
*/
const QwtSpline &QwtSplineCurveFitter::spline() const
{
return d_data->spline;
}
/*!
\return Spline
\sa setSpline()
*/
QwtSpline &QwtSplineCurveFitter::spline()
{
return d_data->spline;
}
/*!
Assign a spline size ( has to be at least 10 points )
\param splineSize Spline size
\sa splineSize()
*/
void QwtSplineCurveFitter::setSplineSize( int splineSize )
{
d_data->splineSize = qMax( splineSize, 10 );
}
/*!
\return Spline size
\sa setSplineSize()
*/
int QwtSplineCurveFitter::splineSize() const
{
return d_data->splineSize;
}
/*!
Find a curve which has the best fit to a series of data points
\param points Series of data points
\return Curve points
*/
QPolygonF QwtSplineCurveFitter::fitCurve( const QPolygonF &points ) const
{
const int size = points.size();
if ( size <= 2 )
return points;
FitMode fitMode = d_data->fitMode;
if ( fitMode == Auto )
{
fitMode = Spline;
const QPointF *p = points.data();
for ( int i = 1; i < size; i++ )
{
if ( p[i].x() <= p[i-1].x() )
{
fitMode = ParametricSpline;
break;
}
};
}
if ( fitMode == ParametricSpline )
return fitParametric( points );
else
return fitSpline( points );
}
QPolygonF QwtSplineCurveFitter::fitSpline( const QPolygonF &points ) const
{
d_data->spline.setPoints( points );
if ( !d_data->spline.isValid() )
return points;
QPolygonF fittedPoints( d_data->splineSize );
const double x1 = points[0].x();
const double x2 = points[int( points.size() - 1 )].x();
const double dx = x2 - x1;
const double delta = dx / ( d_data->splineSize - 1 );
for ( int i = 0; i < d_data->splineSize; i++ )
{
QPointF &p = fittedPoints[i];
const double v = x1 + i * delta;
const double sv = d_data->spline.value( v );
p.setX( v );
p.setY( sv );
}
d_data->spline.reset();
return fittedPoints;
}
QPolygonF QwtSplineCurveFitter::fitParametric( const QPolygonF &points ) const
{
int i;
const int size = points.size();
QPolygonF fittedPoints( d_data->splineSize );
QPolygonF splinePointsX( size );
QPolygonF splinePointsY( size );
const QPointF *p = points.data();
QPointF *spX = splinePointsX.data();
QPointF *spY = splinePointsY.data();
double param = 0.0;
for ( i = 0; i < size; i++ )
{
const double x = p[i].x();
const double y = p[i].y();
if ( i > 0 )
{
const double delta = qSqrt( qwtSqr( x - spX[i-1].y() )
+ qwtSqr( y - spY[i-1].y() ) );
param += qMax( delta, 1.0 );
}
spX[i].setX( param );
spX[i].setY( x );
spY[i].setX( param );
spY[i].setY( y );
}
d_data->spline.setPoints( splinePointsX );
if ( !d_data->spline.isValid() )
return points;
const double deltaX =
splinePointsX[size - 1].x() / ( d_data->splineSize - 1 );
for ( i = 0; i < d_data->splineSize; i++ )
{
const double dtmp = i * deltaX;
fittedPoints[i].setX( d_data->spline.value( dtmp ) );
}
d_data->spline.setPoints( splinePointsY );
if ( !d_data->spline.isValid() )
return points;
const double deltaY =
splinePointsY[size - 1].x() / ( d_data->splineSize - 1 );
for ( i = 0; i < d_data->splineSize; i++ )
{
const double dtmp = i * deltaY;
fittedPoints[i].setY( d_data->spline.value( dtmp ) );
}
return fittedPoints;
}
class QwtWeedingCurveFitter::PrivateData
{
public:
PrivateData():
tolerance( 1.0 ),
chunkSize( 0 )
{
}
double tolerance;
uint chunkSize;
};
class QwtWeedingCurveFitter::Line
{
public:
Line( int i1 = 0, int i2 = 0 ):
from( i1 ),
to( i2 )
{
}
int from;
int to;
};
/*!
Constructor
\param tolerance Tolerance
\sa setTolerance(), tolerance()
*/
QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance )
{
d_data = new PrivateData;
setTolerance( tolerance );
}
//! Destructor
QwtWeedingCurveFitter::~QwtWeedingCurveFitter()
{
delete d_data;
}
/*!
Assign the tolerance
The tolerance is the maximum distance, that is acceptable
between the original curve and the smoothed curve.
Increasing the tolerance will reduce the number of the
resulting points.
\param tolerance Tolerance
\sa tolerance()
*/
void QwtWeedingCurveFitter::setTolerance( double tolerance )
{
d_data->tolerance = qMax( tolerance, 0.0 );
}
/*!
\return Tolerance
\sa setTolerance()
*/
double QwtWeedingCurveFitter::tolerance() const
{
return d_data->tolerance;
}
/*!
Limit the number of points passed to a run of the algorithm
The runtime of the Douglas Peucker algorithm increases non linear
with the number of points. For a chunk size > 0 the polygon
is split into pieces passed to the algorithm one by one.
\param numPoints Maximum for the number of points passed to the algorithm
\sa chunkSize()
*/
void QwtWeedingCurveFitter::setChunkSize( uint numPoints )
{
if ( numPoints > 0 )
numPoints = qMax( numPoints, 3U );
d_data->chunkSize = numPoints;
}
/*!
\return Maximum for the number of points passed to a run
of the algorithm - or 0, when unlimited
\sa setChunkSize()
*/
uint QwtWeedingCurveFitter::chunkSize() const
{
return d_data->chunkSize;
}
/*!
\param points Series of data points
\return Curve points
*/
QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const
{
QPolygonF fittedPoints;
if ( d_data->chunkSize == 0 )
{
fittedPoints = simplify( points );
}
else
{
for ( int i = 0; i < points.size(); i += d_data->chunkSize )
{
const QPolygonF p = points.mid( i, d_data->chunkSize );
fittedPoints += simplify( p );
}
}
return fittedPoints;
}
QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF &points ) const
{
const double toleranceSqr = d_data->tolerance * d_data->tolerance;
QStack<Line> stack;
stack.reserve( 500 );
const QPointF *p = points.data();
const int nPoints = points.size();
QVector<bool> usePoint( nPoints, false );
stack.push( Line( 0, nPoints - 1 ) );
while ( !stack.isEmpty() )
{
const Line r = stack.pop();
// initialize line segment
const double vecX = p[r.to].x() - p[r.from].x();
const double vecY = p[r.to].y() - p[r.from].y();
const double vecLength = qSqrt( vecX * vecX + vecY * vecY );
const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0;
const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0;
double maxDistSqr = 0.0;
int nVertexIndexMaxDistance = r.from + 1;
for ( int i = r.from + 1; i < r.to; i++ )
{
//compare to anchor
const double fromVecX = p[i].x() - p[r.from].x();
const double fromVecY = p[i].y() - p[r.from].y();
double distToSegmentSqr;
if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
{
distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY;
}
else
{
const double toVecX = p[i].x() - p[r.to].x();
const double toVecY = p[i].y() - p[r.to].y();
const double toVecLength = toVecX * toVecX + toVecY * toVecY;
const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
if ( s < 0.0 )
{
distToSegmentSqr = toVecLength;
}
else
{
distToSegmentSqr = qFabs( toVecLength - s * s );
}
}
if ( maxDistSqr < distToSegmentSqr )
{
maxDistSqr = distToSegmentSqr;
nVertexIndexMaxDistance = i;
}
}
if ( maxDistSqr <= toleranceSqr )
{
usePoint[r.from] = true;
usePoint[r.to] = true;
}
else
{
stack.push( Line( r.from, nVertexIndexMaxDistance ) );
stack.push( Line( nVertexIndexMaxDistance, r.to ) );
}
}
QPolygonF stripped;
for ( int i = 0; i < nPoints; i++ )
{
if ( usePoint[i] )
stripped += p[i];
}
return stripped;
}

View File

@@ -0,0 +1,139 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_CURVE_FITTER_H
#define QWT_CURVE_FITTER_H
#include "qwt_global.h"
#include <qpolygon.h>
#include <qrect.h>
class QwtSpline;
/*!
\brief Abstract base class for a curve fitter
*/
class QWT_EXPORT QwtCurveFitter
{
public:
virtual ~QwtCurveFitter();
/*!
Find a curve which has the best fit to a series of data points
\param polygon Series of data points
\return Curve points
*/
virtual QPolygonF fitCurve( const QPolygonF &polygon ) const = 0;
protected:
QwtCurveFitter();
private:
QwtCurveFitter( const QwtCurveFitter & );
QwtCurveFitter &operator=( const QwtCurveFitter & );
};
/*!
\brief A curve fitter using cubic splines
*/
class QWT_EXPORT QwtSplineCurveFitter: public QwtCurveFitter
{
public:
/*!
Spline type
The default setting is Auto
\sa setFitMode(), FitMode()
*/
enum FitMode
{
/*!
Use the default spline algorithm for polygons with
increasing x values ( p[i-1] < p[i] ), otherwise use
a parametric spline algorithm.
*/
Auto,
//! Use a default spline algorithm
Spline,
//! Use a parametric spline algorithm
ParametricSpline
};
QwtSplineCurveFitter();
virtual ~QwtSplineCurveFitter();
void setFitMode( FitMode );
FitMode fitMode() const;
void setSpline( const QwtSpline& );
const QwtSpline &spline() const;
QwtSpline &spline();
void setSplineSize( int size );
int splineSize() const;
virtual QPolygonF fitCurve( const QPolygonF & ) const;
private:
QPolygonF fitSpline( const QPolygonF & ) const;
QPolygonF fitParametric( const QPolygonF & ) const;
class PrivateData;
PrivateData *d_data;
};
/*!
\brief A curve fitter implementing Douglas and Peucker algorithm
The purpose of the Douglas and Peucker algorithm is that given a 'curve'
composed of line segments to find a curve not too dissimilar but that
has fewer points. The algorithm defines 'too dissimilar' based on the
maximum distance (tolerance) between the original curve and the
smoothed curve.
The runtime of the algorithm increases non linear ( worst case O( n*n ) )
and might be very slow for huge polygons. To avoid performance issues
it might be useful to split the polygon ( setChunkSize() ) and to run the algorithm
for these smaller parts. The disadvantage of having no interpolation
at the borders is for most use cases irrelevant.
The smoothed curve consists of a subset of the points that defined the
original curve.
In opposite to QwtSplineCurveFitter the Douglas and Peucker algorithm reduces
the number of points. By adjusting the tolerance parameter according to the
axis scales QwtSplineCurveFitter can be used to implement different
level of details to speed up painting of curves of many points.
*/
class QWT_EXPORT QwtWeedingCurveFitter: public QwtCurveFitter
{
public:
QwtWeedingCurveFitter( double tolerance = 1.0 );
virtual ~QwtWeedingCurveFitter();
void setTolerance( double );
double tolerance() const;
void setChunkSize( uint );
uint chunkSize() const;
virtual QPolygonF fitCurve( const QPolygonF & ) const;
private:
virtual QPolygonF simplify( const QPolygonF & ) const;
class Line;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,760 @@
/* -*- 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_date.h"
#include <qdebug.h>
#include <qlocale.h>
#include <math.h>
#include <limits>
#include <limits.h>
#if QT_VERSION >= 0x050000
typedef qint64 QwtJulianDay;
static const QwtJulianDay minJulianDayD = Q_INT64_C( -784350574879 );
static const QwtJulianDay maxJulianDayD = Q_INT64_C( 784354017364 );
#else
// QDate stores the Julian day as unsigned int, but
// but it is QDate::fromJulianDay( int ). That's why
// we have the range [ 1, INT_MAX ]
typedef int QwtJulianDay;
static const QwtJulianDay minJulianDayD = 1;
static const QwtJulianDay maxJulianDayD = std::numeric_limits<int>::max();
#endif
static QString qwtExpandedFormat( const QString & format,
const QDateTime &dateTime, QwtDate::Week0Type week0Type )
{
const int week = QwtDate::weekNumber( dateTime.date(), week0Type );
QString weekNo;
weekNo.setNum( week );
QString weekNoWW;
if ( weekNo.length() == 1 )
weekNoWW += "0";
weekNoWW += weekNo;
QString fmt = format;
fmt.replace( "ww", weekNoWW );
fmt.replace( "w", weekNo );
if ( week == 1 && dateTime.date().month() != 1 )
{
// in case of week 1, we might need to increment the year
static QString s_yyyy = "yyyy";
static QString s_yy = "yy";
// week 1 might start in the previous year
bool doReplaceYear = fmt.contains( s_yy );
if ( doReplaceYear )
{
if ( fmt.contains( 'M' ) )
{
// in case of also having 'M' we have a conflict about
// which year to show
doReplaceYear = false;
}
else
{
// in case of also having 'd' or 'dd' we have a conflict about
// which year to show
int numD = 0;
for ( int i = 0; i < fmt.size(); i++ )
{
if ( fmt[i] == 'd' )
{
numD++;
}
else
{
if ( numD > 0 && numD <= 2 )
break;
numD = 0;
}
}
if ( numD > 0 && numD <= 2 )
doReplaceYear = false;
}
}
if ( doReplaceYear )
{
const QDate dt( dateTime.date().year() + 1, 1, 1 );
if ( fmt.contains( s_yyyy ) )
{
fmt.replace( s_yyyy, dt.toString( s_yyyy ) );
}
else
{
fmt.replace( s_yy, dt.toString( s_yyyy ) );
}
}
}
return fmt;
}
static inline Qt::DayOfWeek qwtFirstDayOfWeek()
{
#if QT_VERSION >= 0x040800
return QLocale().firstDayOfWeek();
#else
switch( QLocale().country() )
{
case QLocale::Maldives:
return Qt::Friday;
case QLocale::Afghanistan:
case QLocale::Algeria:
case QLocale::Bahrain:
case QLocale::Djibouti:
case QLocale::Egypt:
case QLocale::Eritrea:
case QLocale::Ethiopia:
case QLocale::Iran:
case QLocale::Iraq:
case QLocale::Jordan:
case QLocale::Kenya:
case QLocale::Kuwait:
case QLocale::LibyanArabJamahiriya:
case QLocale::Morocco:
case QLocale::Oman:
case QLocale::Qatar:
case QLocale::SaudiArabia:
case QLocale::Somalia:
case QLocale::Sudan:
case QLocale::Tunisia:
case QLocale::Yemen:
return Qt::Saturday;
case QLocale::AmericanSamoa:
case QLocale::Argentina:
case QLocale::Azerbaijan:
case QLocale::Botswana:
case QLocale::Canada:
case QLocale::China:
case QLocale::FaroeIslands:
case QLocale::Georgia:
case QLocale::Greenland:
case QLocale::Guam:
case QLocale::HongKong:
case QLocale::Iceland:
case QLocale::India:
case QLocale::Ireland:
case QLocale::Israel:
case QLocale::Jamaica:
case QLocale::Japan:
case QLocale::Kyrgyzstan:
case QLocale::Lao:
case QLocale::Malta:
case QLocale::MarshallIslands:
case QLocale::Macau:
case QLocale::Mongolia:
case QLocale::NewZealand:
case QLocale::NorthernMarianaIslands:
case QLocale::Pakistan:
case QLocale::Philippines:
case QLocale::RepublicOfKorea:
case QLocale::Singapore:
case QLocale::SyrianArabRepublic:
case QLocale::Taiwan:
case QLocale::Thailand:
case QLocale::TrinidadAndTobago:
case QLocale::UnitedStates:
case QLocale::UnitedStatesMinorOutlyingIslands:
case QLocale::USVirginIslands:
case QLocale::Uzbekistan:
case QLocale::Zimbabwe:
return Qt::Sunday;
default:
return Qt::Monday;
}
#endif
}
static inline void qwtFloorTime(
QwtDate::IntervalType intervalType, QDateTime &dt )
{
// when dt is inside the special hour where DST is ending
// an hour is no unique. Therefore we have to
// use UTC time.
const Qt::TimeSpec timeSpec = dt.timeSpec();
if ( timeSpec == Qt::LocalTime )
dt = dt.toTimeSpec( Qt::UTC );
const QTime t = dt.time();
switch( intervalType )
{
case QwtDate::Second:
{
dt.setTime( QTime( t.hour(), t.minute(), t.second() ) );
break;
}
case QwtDate::Minute:
{
dt.setTime( QTime( t.hour(), t.minute(), 0 ) );
break;
}
case QwtDate::Hour:
{
dt.setTime( QTime( t.hour(), 0, 0 ) );
break;
}
default:
break;
}
if ( timeSpec == Qt::LocalTime )
dt = dt.toTimeSpec( Qt::LocalTime );
}
static inline QDateTime qwtToTimeSpec(
const QDateTime &dt, Qt::TimeSpec spec )
{
if ( dt.timeSpec() == spec )
return dt;
const qint64 jd = dt.date().toJulianDay();
if ( jd < 0 || jd >= INT_MAX )
{
// the conversion between local time and UTC
// is internally limited. To avoid
// overflows we simply ignore the difference
// for those dates
QDateTime dt2 = dt;
dt2.setTimeSpec( spec );
return dt2;
}
return dt.toTimeSpec( spec );
}
static inline double qwtToJulianDay( int year, int month, int day )
{
// code from QDate but using doubles to avoid overflows
// for large values
const int m1 = ( month - 14 ) / 12;
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
return ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
}
static inline qint64 qwtFloorDiv64( qint64 a, int b )
{
if ( a < 0 )
a -= b - 1;
return a / b;
}
static inline qint64 qwtFloorDiv( int a, int b )
{
if ( a < 0 )
a -= b - 1;
return a / b;
}
static inline QDate qwtToDate( int year, int month = 1, int day = 1 )
{
#if QT_VERSION >= 0x050000
return QDate( year, month, day );
#else
if ( year > 100000 )
{
// code from QDate but using doubles to avoid overflows
// for large values
const int m1 = ( month - 14 ) / 12;
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
const double jd = ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
if ( jd > maxJulianDayD )
{
qWarning() << "qwtToDate: overflow";
return QDate();
}
return QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
}
else
{
return QDate( year, month, day );
}
#endif
}
/*!
Translate from double to QDateTime
\param value Number of milliseconds since the epoch,
1970-01-01T00:00:00 UTC
\param timeSpec Time specification
\return Datetime value
\sa toDouble(), QDateTime::setMSecsSinceEpoch()
\note The return datetime for Qt::OffsetFromUTC will be Qt::UTC
*/
QDateTime QwtDate::toDateTime( double value, Qt::TimeSpec timeSpec )
{
const int msecsPerDay = 86400000;
const double days = static_cast<qint64>( ::floor( value / msecsPerDay ) );
const double jd = QwtDate::JulianDayForEpoch + days;
if ( ( jd > maxJulianDayD ) || ( jd < minJulianDayD ) )
{
qWarning() << "QwtDate::toDateTime: overflow";
return QDateTime();
}
const QDate d = QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
const int msecs = static_cast<int>( value - days * msecsPerDay );
static const QTime timeNull( 0, 0, 0, 0 );
QDateTime dt( d, timeNull.addMSecs( msecs ), Qt::UTC );
if ( timeSpec == Qt::LocalTime )
dt = qwtToTimeSpec( dt, timeSpec );
return dt;
}
/*!
Translate from QDateTime to double
\param dateTime Datetime value
\return Number of milliseconds since 1970-01-01T00:00:00 UTC has passed.
\sa toDateTime(), QDateTime::toMSecsSinceEpoch()
\warning For values very far below or above 1970-01-01 UTC rounding errors
will happen due to the limited significance of a double.
*/
double QwtDate::toDouble( const QDateTime &dateTime )
{
const int msecsPerDay = 86400000;
const QDateTime dt = qwtToTimeSpec( dateTime, Qt::UTC );
const double days = dt.date().toJulianDay() - QwtDate::JulianDayForEpoch;
const QTime time = dt.time();
const double secs = 3600.0 * time.hour() +
60.0 * time.minute() + time.second();
return days * msecsPerDay + time.msec() + 1000.0 * secs;
}
/*!
Ceil a datetime according the interval type
\param dateTime Datetime value
\param intervalType Interval type, how to ceil.
F.e. when intervalType = QwtDate::Months, the result
will be ceiled to the next beginning of a month
\return Ceiled datetime
\sa floor()
*/
QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType )
{
if ( dateTime.date() >= QwtDate::maxDate() )
return dateTime;
QDateTime dt = dateTime;
switch ( intervalType )
{
case QwtDate::Millisecond:
{
break;
}
case QwtDate::Second:
{
qwtFloorTime( QwtDate::Second, dt );
if ( dt < dateTime )
dt = dt.addSecs( 1 );
break;
}
case QwtDate::Minute:
{
qwtFloorTime( QwtDate::Minute, dt );
if ( dt < dateTime )
dt = dt.addSecs( 60 );
break;
}
case QwtDate::Hour:
{
qwtFloorTime( QwtDate::Hour, dt );
if ( dt < dateTime )
dt = dt.addSecs( 3600 );
break;
}
case QwtDate::Day:
{
dt.setTime( QTime( 0, 0 ) );
if ( dt < dateTime )
dt = dt.addDays( 1 );
break;
}
case QwtDate::Week:
{
dt.setTime( QTime( 0, 0 ) );
if ( dt < dateTime )
dt = dt.addDays( 1 );
int days = qwtFirstDayOfWeek() - dt.date().dayOfWeek();
if ( days < 0 )
days += 7;
dt = dt.addDays( days );
break;
}
case QwtDate::Month:
{
dt.setTime( QTime( 0, 0 ) );
dt.setDate( qwtToDate( dateTime.date().year(),
dateTime.date().month() ) );
if ( dt < dateTime )
dt = dt.addMonths( 1 );
break;
}
case QwtDate::Year:
{
dt.setTime( QTime( 0, 0 ) );
const QDate d = dateTime.date();
int year = d.year();
if ( d.month() > 1 || d.day() > 1 || !dateTime.time().isNull() )
year++;
if ( year == 0 )
year++; // there is no year 0
dt.setDate( qwtToDate( year ) );
break;
}
}
return dt;
}
/*!
Floor a datetime according the interval type
\param dateTime Datetime value
\param intervalType Interval type, how to ceil.
F.e. when intervalType = QwtDate::Months,
the result will be ceiled to the next
beginning of a month
\return Floored datetime
\sa floor()
*/
QDateTime QwtDate::floor( const QDateTime &dateTime,
IntervalType intervalType )
{
if ( dateTime.date() <= QwtDate::minDate() )
return dateTime;
QDateTime dt = dateTime;
switch ( intervalType )
{
case QwtDate::Millisecond:
{
break;
}
case QwtDate::Second:
case QwtDate::Minute:
case QwtDate::Hour:
{
qwtFloorTime( intervalType, dt );
break;
}
case QwtDate::Day:
{
dt.setTime( QTime( 0, 0 ) );
break;
}
case QwtDate::Week:
{
dt.setTime( QTime( 0, 0 ) );
int days = dt.date().dayOfWeek() - qwtFirstDayOfWeek();
if ( days < 0 )
days += 7;
dt = dt.addDays( -days );
break;
}
case QwtDate::Month:
{
dt.setTime( QTime( 0, 0 ) );
const QDate date = qwtToDate( dt.date().year(),
dt.date().month() );
dt.setDate( date );
break;
}
case QwtDate::Year:
{
dt.setTime( QTime( 0, 0 ) );
const QDate date = qwtToDate( dt.date().year() );
dt.setDate( date );
break;
}
}
return dt;
}
/*!
Minimum for the supported date range
The range of valid dates depends on how QDate stores the
Julian day internally.
- For Qt4 it is "Tue Jan 2 -4713"
- For Qt5 it is "Thu Jan 1 -2147483648"
\return minimum of the date range
\sa maxDate()
*/
QDate QwtDate::minDate()
{
static QDate date;
if ( !date.isValid() )
date = QDate::fromJulianDay( minJulianDayD );
return date;
}
/*!
Maximum for the supported date range
The range of valid dates depends on how QDate stores the
Julian day internally.
- For Qt4 it is "Tue Jun 3 5874898"
- For Qt5 it is "Tue Dec 31 2147483647"
\return maximum of the date range
\sa minDate()
\note The maximum differs between Qt4 and Qt5
*/
QDate QwtDate::maxDate()
{
static QDate date;
if ( !date.isValid() )
date = QDate::fromJulianDay( maxJulianDayD );
return date;
}
/*!
\brief Date of the first day of the first week for a year
The first day of a week depends on the current locale
( QLocale::firstDayOfWeek() ).
\param year Year
\param type Option how to identify the first week
\return First day of week 0
\sa QLocale::firstDayOfWeek(), weekNumber()
*/
QDate QwtDate::dateOfWeek0( int year, Week0Type type )
{
const Qt::DayOfWeek firstDayOfWeek = qwtFirstDayOfWeek();
QDate dt0( year, 1, 1 );
// floor to the first day of the week
int days = dt0.dayOfWeek() - firstDayOfWeek;
if ( days < 0 )
days += 7;
dt0 = dt0.addDays( -days );
if ( type == QwtDate::FirstThursday )
{
// according to ISO 8601 the first week is defined
// by the first thursday.
int d = Qt::Thursday - firstDayOfWeek;
if ( d < 0 )
d += 7;
if ( dt0.addDays( d ).year() < year )
dt0 = dt0.addDays( 7 );
}
return dt0;
}
/*!
Find the week number of a date
- QwtDate::FirstThursday\n
Corresponding to ISO 8601 ( see QDate::weekNumber() ).
- QwtDate::FirstDay\n
Number of weeks that have begun since dateOfWeek0().
\param date Date
\param type Option how to identify the first week
\return Week number, starting with 1
*/
int QwtDate::weekNumber( const QDate &date, Week0Type type )
{
int weekNo;
if ( type == QwtDate::FirstDay )
{
QDate day0;
if ( date.month() == 12 && date.day() >= 24 )
{
// week 1 usually starts in the previous years.
// and we have to check if we are already there
day0 = dateOfWeek0( date.year() + 1, type );
if ( day0.daysTo( date ) < 0 )
day0 = dateOfWeek0( date.year(), type );
}
else
{
day0 = dateOfWeek0( date.year(), type );
}
weekNo = day0.daysTo( date ) / 7 + 1;
}
else
{
weekNo = date.weekNumber();
}
return weekNo;
}
/*!
Offset in seconds from Coordinated Universal Time
The offset depends on the time specification of dateTime:
- Qt::UTC
0, dateTime has no offset
- Qt::OffsetFromUTC
returns dateTime.utcOffset()
- Qt::LocalTime:
number of seconds from the UTC
For Qt::LocalTime the offset depends on the timezone and
daylight savings.
\param dateTime Datetime value
\return Offset in seconds
*/
int QwtDate::utcOffset( const QDateTime &dateTime )
{
int seconds = 0;
switch( dateTime.timeSpec() )
{
case Qt::UTC:
{
break;
}
case Qt::OffsetFromUTC:
{
seconds = dateTime.utcOffset();
break;
}
default:
{
const QDateTime dt1( dateTime.date(), dateTime.time(), Qt::UTC );
seconds = dateTime.secsTo( dt1 );
}
}
return seconds;
}
/*!
Translate a datetime into a string
Beside the format expressions documented in QDateTime::toString()
the following expressions are supported:
- w\n
week number: ( 1 - 53 )
- ww\n
week number with a leading zero ( 01 - 53 )
As week 1 usually starts in the previous year a special rule
is applied for formats, where the year is expected to match the
week number - even if the date belongs to the previous year.
\param dateTime Datetime value
\param format Format string
\param week0Type Specification of week 0
\return Datetime string
\sa QDateTime::toString(), weekNumber(), QwtDateScaleDraw
*/
QString QwtDate::toString( const QDateTime &dateTime,
const QString & format, Week0Type week0Type )
{
QString fmt = format;
if ( fmt.contains( 'w' ) )
{
fmt = qwtExpandedFormat( fmt, dateTime, week0Type );
}
return dateTime.toString( fmt );
}

View File

@@ -0,0 +1,128 @@
/* -*- 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
*****************************************************************************/
#ifndef _QWT_DATE_H_
#define _QWT_DATE_H_
#include "qwt_global.h"
#include <qdatetime.h>
/*!
\brief A collection of methods around date/time values
Qt offers convenient classes for dealing with date/time values,
but Qwt uses coordinate systems that are based on doubles.
QwtDate offers methods to translate from QDateTime to double and v.v.
A double is interpreted as the number of milliseconds since
1970-01-01T00:00:00 Universal Coordinated Time - also known
as "The Epoch".
While the range of the Julian day in Qt4 is limited to [0, MAX_INT],
Qt5 stores it as qint64 offering a huge range of valid dates.
As the significance of a double is below this ( assuming a
fraction of 52 bits ) the translation is not
bijective with rounding errors for dates very far from Epoch.
For a resolution of 1 ms those start to happen for dates above the
year 144683.
An axis for a date/time interval is expected to be aligned
and divided in time/date units like seconds, minutes, ...
QwtDate offers several algorithms that are needed to
calculate these axes.
\sa QwtDateScaleEngine, QwtDateScaleDraw, QDate, QTime
*/
class QWT_EXPORT QwtDate
{
public:
/*!
How to identify the first week of year differs between
countries.
*/
enum Week0Type
{
/*!
According to ISO 8601 the first week of a year is defined
as "the week with the year's first Thursday in it".
FirstThursday corresponds to the numbering that is
implemented in QDate::weekNumber().
*/
FirstThursday,
/*!
"The week with January 1.1 in it."
In the U.S. this definition is more common than
FirstThursday.
*/
FirstDay
};
/*!
Classification of an time interval
Time intervals needs to be classified to decide how to
align and divide it.
*/
enum IntervalType
{
//! The interval is related to milliseconds
Millisecond,
//! The interval is related to seconds
Second,
//! The interval is related to minutes
Minute,
//! The interval is related to hours
Hour,
//! The interval is related to days
Day,
//! The interval is related to weeks
Week,
//! The interval is related to months
Month,
//! The interval is related to years
Year
};
enum
{
//! The Julian day of "The Epoch"
JulianDayForEpoch = 2440588
};
static QDate minDate();
static QDate maxDate();
static QDateTime toDateTime( double value,
Qt::TimeSpec = Qt::UTC );
static double toDouble( const QDateTime & );
static QDateTime ceil( const QDateTime &, IntervalType );
static QDateTime floor( const QDateTime &, IntervalType );
static QDate dateOfWeek0( int year, Week0Type );
static int weekNumber( const QDate &, Week0Type );
static int utcOffset( const QDateTime & );
static QString toString( const QDateTime &,
const QString & format, Week0Type );
};
#endif

View File

@@ -0,0 +1,278 @@
/* -*- 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_date_scale_draw.h"
class QwtDateScaleDraw::PrivateData
{
public:
PrivateData( Qt::TimeSpec spec ):
timeSpec( spec ),
utcOffset( 0 ),
week0Type( QwtDate::FirstThursday )
{
dateFormats[ QwtDate::Millisecond ] = "hh:mm:ss:zzz\nddd dd MMM yyyy";
dateFormats[ QwtDate::Second ] = "hh:mm:ss\nddd dd MMM yyyy";
dateFormats[ QwtDate::Minute ] = "hh:mm\nddd dd MMM yyyy";
dateFormats[ QwtDate::Hour ] = "hh:mm\nddd dd MMM yyyy";
dateFormats[ QwtDate::Day ] = "ddd dd MMM yyyy";
dateFormats[ QwtDate::Week ] = "Www yyyy";
dateFormats[ QwtDate::Month ] = "MMM yyyy";
dateFormats[ QwtDate::Year ] = "yyyy";
}
Qt::TimeSpec timeSpec;
int utcOffset;
QwtDate::Week0Type week0Type;
QString dateFormats[ QwtDate::Year + 1 ];
};
/*!
\brief Constructor
The default setting is to display tick labels for the
given time specification. The first week of a year is defined like
for QwtDate::FirstThursday.
\param timeSpec Time specification
\sa setTimeSpec(), setWeek0Type()
*/
QwtDateScaleDraw::QwtDateScaleDraw( Qt::TimeSpec timeSpec )
{
d_data = new PrivateData( timeSpec );
}
//! Destructor
QwtDateScaleDraw::~QwtDateScaleDraw()
{
delete d_data;
}
/*!
Set the time specification used for the tick labels
\param timeSpec Time specification
\sa timeSpec(), setUtcOffset(), toDateTime()
*/
void QwtDateScaleDraw::setTimeSpec( Qt::TimeSpec timeSpec )
{
d_data->timeSpec = timeSpec;
}
/*!
\return Time specification used for the tick labels
\sa setTimeSpec(), utcOffset(), toDateTime()
*/
Qt::TimeSpec QwtDateScaleDraw::timeSpec() const
{
return d_data->timeSpec;
}
/*!
Set the offset in seconds from Coordinated Universal Time
\param seconds Offset in seconds
\note The offset has no effect beside for the time specification
Qt::OffsetFromUTC.
\sa QDate::utcOffset(), setTimeSpec(), toDateTime()
*/
void QwtDateScaleDraw::setUtcOffset( int seconds )
{
d_data->utcOffset = seconds;
}
/*!
\return Offset in seconds from Coordinated Universal Time
\note The offset has no effect beside for the time specification
Qt::OffsetFromUTC.
\sa QDate::setUtcOffset(), setTimeSpec(), toDateTime()
*/
int QwtDateScaleDraw::utcOffset() const
{
return d_data->utcOffset;
}
/*!
Sets how to identify the first week of a year.
\param week0Type Mode how to identify the first week of a year
\sa week0Type().
\note week0Type has no effect beside for intervals classified as
QwtDate::Week.
*/
void QwtDateScaleDraw::setWeek0Type( QwtDate::Week0Type week0Type )
{
d_data->week0Type = week0Type;
}
/*!
\return Setting how to identify the first week of a year.
\sa setWeek0Type()
*/
QwtDate::Week0Type QwtDateScaleDraw::week0Type() const
{
return d_data->week0Type;
}
/*!
Set the default format string for an datetime interval type
\param intervalType Interval type
\param format Default format string
\sa dateFormat(), dateFormatOfDate(), QwtDate::toString()
*/
void QwtDateScaleDraw::setDateFormat(
QwtDate::IntervalType intervalType, const QString &format )
{
if ( intervalType >= QwtDate::Millisecond &&
intervalType <= QwtDate::Year )
{
d_data->dateFormats[ intervalType ] = format;
}
}
/*!
\param intervalType Interval type
\return Default format string for an datetime interval type
\sa setDateFormat(), dateFormatOfDate()
*/
QString QwtDateScaleDraw::dateFormat(
QwtDate::IntervalType intervalType ) const
{
if ( intervalType >= QwtDate::Millisecond &&
intervalType <= QwtDate::Year )
{
return d_data->dateFormats[ intervalType ];
}
return QString::null;
}
/*!
Format string for the representation of a datetime
dateFormatOfDate() is intended to be overloaded for
situations, where formats are individual for specific
datetime values.
The default setting ignores dateTime and return
the default format for the interval type.
\param dateTime Datetime value
\param intervalType Interval type
\return Format string
\sa setDateFormat(), QwtDate::toString()
*/
QString QwtDateScaleDraw::dateFormatOfDate( const QDateTime &dateTime,
QwtDate::IntervalType intervalType ) const
{
Q_UNUSED( dateTime )
if ( intervalType >= QwtDate::Millisecond &&
intervalType <= QwtDate::Year )
{
return d_data->dateFormats[ intervalType ];
}
return d_data->dateFormats[ QwtDate::Second ];
}
/*!
\brief Convert a value into its representing label
The value is converted to a datetime value using toDateTime()
and converted to a plain text using QwtDate::toString().
\param value Value
\return Label string.
\sa dateFormatOfDate()
*/
QwtText QwtDateScaleDraw::label( double value ) const
{
const QDateTime dt = toDateTime( value );
const QString fmt = dateFormatOfDate(
dt, intervalType( scaleDiv() ) );
return QwtDate::toString( dt, fmt, d_data->week0Type );
}
/*!
Find the less detailed datetime unit, where no rounding
errors happen.
\param scaleDiv Scale division
\return Interval type
\sa dateFormatOfDate()
*/
QwtDate::IntervalType QwtDateScaleDraw::intervalType(
const QwtScaleDiv &scaleDiv ) const
{
int intvType = QwtDate::Year;
bool alignedToWeeks = true;
const QList<double> ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick );
for ( int i = 0; i < ticks.size(); i++ )
{
const QDateTime dt = toDateTime( ticks[i] );
for ( int j = QwtDate::Second; j <= intvType; j++ )
{
const QDateTime dt0 = QwtDate::floor( dt,
static_cast<QwtDate::IntervalType>( j ) );
if ( dt0 != dt )
{
if ( j == QwtDate::Week )
{
alignedToWeeks = false;
}
else
{
intvType = j - 1;
break;
}
}
}
if ( intvType == QwtDate::Millisecond )
break;
}
if ( intvType == QwtDate::Week && !alignedToWeeks )
intvType = QwtDate::Day;
return static_cast<QwtDate::IntervalType>( intvType );
}
/*!
Translate a double value into a QDateTime object.
\return QDateTime object initialized with timeSpec() and utcOffset().
\sa timeSpec(), utcOffset(), QwtDate::toDateTime()
*/
QDateTime QwtDateScaleDraw::toDateTime( double value ) const
{
QDateTime dt = QwtDate::toDateTime( value, d_data->timeSpec );
if ( d_data->timeSpec == Qt::OffsetFromUTC )
{
dt = dt.addSecs( d_data->utcOffset );
dt.setUtcOffset( d_data->utcOffset );
}
return dt;
}

View File

@@ -0,0 +1,86 @@
/* -*- 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
*****************************************************************************/
#ifndef _QWT_DATE_SCALE_DRAW_H_
#define _QWT_DATE_SCALE_DRAW_H_ 1
#include "qwt_global.h"
#include "qwt_scale_draw.h"
#include "qwt_date.h"
/*!
\brief A class for drawing datetime scales
QwtDateScaleDraw displays values as datetime labels.
The format of the labels depends on the alignment of
the major tick labels.
The default format strings are:
- Millisecond\n
"hh:mm:ss:zzz\nddd dd MMM yyyy"
- Second\n
"hh:mm:ss\nddd dd MMM yyyy"
- Minute\n
"hh:mm\nddd dd MMM yyyy"
- Hour\n
"hh:mm\nddd dd MMM yyyy"
- Day\n
"ddd dd MMM yyyy"
- Week\n
"Www yyyy"
- Month\n
"MMM yyyy"
- Year\n
"yyyy"
The format strings can be modified using setDateFormat()
or individually for each tick label by overloading dateFormatOfDate(),
Usually QwtDateScaleDraw is used in combination with
QwtDateScaleEngine, that calculates scales for datetime
intervals.
\sa QwtDateScaleEngine, QwtPlot::setAxisScaleDraw()
*/
class QWT_EXPORT QwtDateScaleDraw: public QwtScaleDraw
{
public:
QwtDateScaleDraw( Qt::TimeSpec = Qt::LocalTime );
virtual ~QwtDateScaleDraw();
void setDateFormat( QwtDate::IntervalType, const QString & );
QString dateFormat( QwtDate::IntervalType ) const;
void setTimeSpec( Qt::TimeSpec );
Qt::TimeSpec timeSpec() const;
void setUtcOffset( int seconds );
int utcOffset() const;
void setWeek0Type( QwtDate::Week0Type );
QwtDate::Week0Type week0Type() const;
virtual QwtText label( double ) const;
QDateTime toDateTime( double ) const;
protected:
virtual QwtDate::IntervalType
intervalType( const QwtScaleDiv & ) const;
virtual QString dateFormatOfDate( const QDateTime &,
QwtDate::IntervalType ) const;
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,86 @@
/* -*- 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
*****************************************************************************/
#ifndef _QWT_DATE_SCALE_ENGINE_H_
#define _QWT_DATE_SCALE_ENGINE_H_ 1
#include "qwt_date.h"
#include "qwt_scale_engine.h"
/*!
\brief A scale engine for date/time values
QwtDateScaleEngine builds scales from a time intervals.
Together with QwtDateScaleDraw it can be used for
axes according to date/time values.
Years, months, weeks, days, hours and minutes are organized
in steps with non constant intervals. QwtDateScaleEngine
classifies intervals and aligns the boundaries and tick positions
according to this classification.
QwtDateScaleEngine supports representations depending
on Qt::TimeSpec specifications. The valid range for scales
is limited by the range of QDateTime, that differs
between Qt4 and Qt5.
Datetime values are expected as the number of milliseconds since
1970-01-01T00:00:00 Universal Coordinated Time - also known
as "The Epoch", that can be converted to QDateTime using
QwtDate::toDateTime().
\sa QwtDate, QwtPlot::setAxisScaleEngine(),
QwtAbstractScale::setScaleEngine()
*/
class QWT_EXPORT QwtDateScaleEngine: public QwtLinearScaleEngine
{
public:
QwtDateScaleEngine( Qt::TimeSpec = Qt::LocalTime );
virtual ~QwtDateScaleEngine();
void setTimeSpec( Qt::TimeSpec );
Qt::TimeSpec timeSpec() const;
void setUtcOffset( int seconds );
int utcOffset() const;
void setWeek0Type( QwtDate::Week0Type );
QwtDate::Week0Type week0Type() const;
void setMaxWeeks( int );
int maxWeeks() const;
virtual void autoScale( int maxNumSteps,
double &x1, double &x2, double &stepSize ) const;
virtual QwtScaleDiv divideScale(
double x1, double x2,
int maxMajorSteps, int maxMinorSteps,
double stepSize = 0.0 ) const;
virtual QwtDate::IntervalType intervalType(
const QDateTime &, const QDateTime &, int maxSteps ) const;
QDateTime toDateTime( double ) const;
protected:
virtual QDateTime alignDate( const QDateTime &, double stepSize,
QwtDate::IntervalType, bool up ) const;
private:
QwtScaleDiv buildScaleDiv( const QDateTime &, const QDateTime &,
int maxMajorSteps, int maxMinorSteps,
QwtDate::IntervalType ) const;
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,871 @@
/* -*- 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_dial.h"
#include "qwt_dial_needle.h"
#include "qwt_math.h"
#include "qwt_scale_engine.h"
#include "qwt_scale_map.h"
#include "qwt_round_scale_draw.h"
#include "qwt_painter.h"
#include <qpainter.h>
#include <qpalette.h>
#include <qpixmap.h>
#include <qevent.h>
#include <qalgorithms.h>
#include <qmath.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qapplication.h>
static inline double qwtAngleDist( double a1, double a2 )
{
double dist = qAbs( a2 - a1 );
if ( dist > 360.0 )
dist -= 360.0;
return dist;
}
static inline bool qwtIsOnArc( double angle, double min, double max )
{
if ( min < max )
{
return ( angle >= min ) && ( angle <= max );
}
else
{
return ( angle >= min ) || ( angle <= max );
}
}
static inline double qwtBoundedAngle( double min, double angle, double max )
{
double from = qwtNormalizeDegrees( min );
double to = qwtNormalizeDegrees( max );
double a;
if ( qwtIsOnArc( angle, from, to ) )
{
a = angle;
if ( a < min )
a += 360.0;
}
else
{
if ( qwtAngleDist( angle, from ) <
qwtAngleDist( angle, to ) )
{
a = min;
}
else
{
a = max;
}
}
return a;
}
class QwtDial::PrivateData
{
public:
PrivateData():
frameShadow( Sunken ),
lineWidth( 0 ),
mode( RotateNeedle ),
origin( 90.0 ),
minScaleArc( 0.0 ),
maxScaleArc( 0.0 ),
needle( NULL ),
arcOffset( 0.0 ),
mouseOffset( 0.0 )
{
}
~PrivateData()
{
delete needle;
}
Shadow frameShadow;
int lineWidth;
QwtDial::Mode mode;
double origin;
double minScaleArc;
double maxScaleArc;
QwtDialNeedle *needle;
double arcOffset;
double mouseOffset;
QPixmap pixmapCache;
};
/*!
\brief Constructor
\param parent Parent widget
Create a dial widget with no needle. The scale is initialized
to [ 0.0, 360.0 ] and 360 steps ( QwtAbstractSlider::setTotalSteps() ).
The origin of the scale is at 90°,
The value is set to 0.0.
The default mode is QwtDial::RotateNeedle.
*/
QwtDial::QwtDial( QWidget* parent ):
QwtAbstractSlider( parent )
{
d_data = new PrivateData;
setFocusPolicy( Qt::TabFocus );
QPalette p = palette();
for ( int i = 0; i < QPalette::NColorGroups; i++ )
{
const QPalette::ColorGroup colorGroup =
static_cast<QPalette::ColorGroup>( i );
// Base: background color of the circle inside the frame.
// WindowText: background color of the circle inside the scale
p.setColor( colorGroup, QPalette::WindowText,
p.color( colorGroup, QPalette::Base ) );
}
setPalette( p );
QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
scaleDraw->setRadius( 0 );
setScaleDraw( scaleDraw );
setScaleArc( 0.0, 360.0 ); // scale as a full circle
setScaleMaxMajor( 10 );
setScaleMaxMinor( 5 );
setValue( 0.0 );
}
//! Destructor
QwtDial::~QwtDial()
{
delete d_data;
}
/*!
Sets the frame shadow value from the frame style.
\param shadow Frame shadow
\sa setLineWidth(), QFrame::setFrameShadow()
*/
void QwtDial::setFrameShadow( Shadow shadow )
{
if ( shadow != d_data->frameShadow )
{
invalidateCache();
d_data->frameShadow = shadow;
if ( lineWidth() > 0 )
update();
}
}
/*!
\return Frame shadow
/sa setFrameShadow(), lineWidth(), QFrame::frameShadow()
*/
QwtDial::Shadow QwtDial::frameShadow() const
{
return d_data->frameShadow;
}
/*!
Sets the line width of the frame
\param lineWidth Line width
\sa setFrameShadow()
*/
void QwtDial::setLineWidth( int lineWidth )
{
if ( lineWidth < 0 )
lineWidth = 0;
if ( d_data->lineWidth != lineWidth )
{
invalidateCache();
d_data->lineWidth = lineWidth;
update();
}
}
/*!
\return Line width of the frame
\sa setLineWidth(), frameShadow(), lineWidth()
*/
int QwtDial::lineWidth() const
{
return d_data->lineWidth;
}
/*!
\return bounding rectangle of the circle inside the frame
\sa setLineWidth(), scaleInnerRect(), boundingRect()
*/
QRect QwtDial::innerRect() const
{
const int lw = lineWidth();
return boundingRect().adjusted( lw, lw, -lw, -lw );
}
/*!
\return bounding rectangle of the dial including the frame
\sa setLineWidth(), scaleInnerRect(), innerRect()
*/
QRect QwtDial::boundingRect() const
{
const QRect cr = contentsRect();
const double dim = qMin( cr.width(), cr.height() );
QRect inner( 0, 0, dim, dim );
inner.moveCenter( cr.center() );
return inner;
}
/*!
\return rectangle inside the scale
\sa setLineWidth(), boundingRect(), innerRect()
*/
QRect QwtDial::scaleInnerRect() const
{
QRect rect = innerRect();
const QwtAbstractScaleDraw *sd = scaleDraw();
if ( sd )
{
int scaleDist = qCeil( sd->extent( font() ) );
scaleDist++; // margin
rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
}
return rect;
}
/*!
\brief Change the mode of the dial.
\param mode New mode
In case of QwtDial::RotateNeedle the needle is rotating, in case of
QwtDial::RotateScale, the needle points to origin()
and the scale is rotating.
The default mode is QwtDial::RotateNeedle.
\sa mode(), setValue(), setOrigin()
*/
void QwtDial::setMode( Mode mode )
{
if ( mode != d_data->mode )
{
invalidateCache();
d_data->mode = mode;
sliderChange();
}
}
/*!
\return Mode of the dial.
\sa setMode(), origin(), setScaleArc(), value()
*/
QwtDial::Mode QwtDial::mode() const
{
return d_data->mode;
}
/*!
Invalidate the internal caches used to speed up repainting
*/
void QwtDial::invalidateCache()
{
d_data->pixmapCache = QPixmap();
}
/*!
Paint the dial
\param event Paint event
*/
void QwtDial::paintEvent( QPaintEvent *event )
{
QPainter painter( this );
painter.setClipRegion( event->region() );
QStyleOption opt;
opt.init(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
if ( d_data->mode == QwtDial::RotateScale )
{
painter.save();
painter.setRenderHint( QPainter::Antialiasing, true );
drawContents( &painter );
painter.restore();
}
const QRect r = contentsRect();
if ( r.size() != d_data->pixmapCache.size() )
{
d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
d_data->pixmapCache.fill( Qt::transparent );
QPainter p( &d_data->pixmapCache );
p.setRenderHint( QPainter::Antialiasing, true );
p.translate( -r.topLeft() );
if ( d_data->mode != QwtDial::RotateScale )
drawContents( &p );
if ( lineWidth() > 0 )
drawFrame( &p );
if ( d_data->mode != QwtDial::RotateNeedle )
drawNeedle( &p );
}
painter.drawPixmap( r.topLeft(), d_data->pixmapCache );
if ( d_data->mode == QwtDial::RotateNeedle )
drawNeedle( &painter );
if ( hasFocus() )
drawFocusIndicator( &painter );
}
/*!
Draw the focus indicator
\param painter Painter
*/
void QwtDial::drawFocusIndicator( QPainter *painter ) const
{
QwtPainter::drawFocusRect( painter, this, boundingRect() );
}
/*!
Draw the frame around the dial
\param painter Painter
\sa lineWidth(), frameShadow()
*/
void QwtDial::drawFrame( QPainter *painter )
{
QwtPainter::drawRoundFrame( painter, boundingRect(),
palette(), lineWidth(), d_data->frameShadow );
}
/*!
\brief Draw the contents inside the frame
QPalette::Window is the background color outside of the frame.
QPalette::Base is the background color inside the frame.
QPalette::WindowText is the background color inside the scale.
\param painter Painter
\sa boundingRect(), innerRect(),
scaleInnerRect(), QWidget::setPalette()
*/
void QwtDial::drawContents( QPainter *painter ) const
{
if ( testAttribute( Qt::WA_NoSystemBackground ) ||
palette().brush( QPalette::Base ) !=
palette().brush( QPalette::Window ) )
{
const QRectF br = boundingRect();
painter->save();
painter->setPen( Qt::NoPen );
painter->setBrush( palette().brush( QPalette::Base ) );
painter->drawEllipse( br );
painter->restore();
}
const QRectF insideScaleRect = scaleInnerRect();
if ( palette().brush( QPalette::WindowText ) !=
palette().brush( QPalette::Base ) )
{
painter->save();
painter->setPen( Qt::NoPen );
painter->setBrush( palette().brush( QPalette::WindowText ) );
painter->drawEllipse( insideScaleRect );
painter->restore();
}
const QPointF center = insideScaleRect.center();
const double radius = 0.5 * insideScaleRect.width();
painter->save();
drawScale( painter, center, radius );
painter->restore();
painter->save();
drawScaleContents( painter, center, radius );
painter->restore();
}
/*!
Draw the needle
\param painter Painter
\param center Center of the dial
\param radius Length for the needle
\param direction Direction of the needle in degrees, counter clockwise
\param colorGroup ColorGroup
*/
void QwtDial::drawNeedle( QPainter *painter, const QPointF &center,
double radius, double direction, QPalette::ColorGroup colorGroup ) const
{
if ( d_data->needle )
{
direction = 360.0 - direction; // counter clockwise
d_data->needle->draw( painter, center, radius, direction, colorGroup );
}
}
void QwtDial::drawNeedle( QPainter *painter ) const
{
if ( !isValid() )
return;
QPalette::ColorGroup colorGroup;
if ( isEnabled() )
colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
else
colorGroup = QPalette::Disabled;
const QRectF sr = scaleInnerRect();
painter->save();
painter->setRenderHint( QPainter::Antialiasing, true );
drawNeedle( painter, sr.center(), 0.5 * sr.width(),
scaleMap().transform( value() ) + 270.0, colorGroup );
painter->restore();
}
/*!
Draw the scale
\param painter Painter
\param center Center of the dial
\param radius Radius of the scale
*/
void QwtDial::drawScale( QPainter *painter,
const QPointF &center, double radius ) const
{
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
if ( sd == NULL )
return;
sd->setRadius( radius );
sd->moveCenter( center );
QPalette pal = palette();
const QColor textColor = pal.color( QPalette::Text );
pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
painter->setFont( font() );
painter->setPen( QPen( textColor, sd->penWidth() ) );
painter->setBrush( Qt::red );
sd->draw( painter, pal );
}
/*!
Draw the contents inside the scale
Paints nothing.
\param painter Painter
\param center Center of the contents circle
\param radius Radius of the contents circle
*/
void QwtDial::drawScaleContents( QPainter *painter,
const QPointF &center, double radius ) const
{
Q_UNUSED(painter);
Q_UNUSED(center);
Q_UNUSED(radius);
}
/*!
Set a needle for the dial
\param needle Needle
\warning The needle will be deleted, when a different needle is
set or in ~QwtDial()
*/
void QwtDial::setNeedle( QwtDialNeedle *needle )
{
if ( needle != d_data->needle )
{
if ( d_data->needle )
delete d_data->needle;
d_data->needle = needle;
update();
}
}
/*!
\return needle
\sa setNeedle()
*/
const QwtDialNeedle *QwtDial::needle() const
{
return d_data->needle;
}
/*!
\return needle
\sa setNeedle()
*/
QwtDialNeedle *QwtDial::needle()
{
return d_data->needle;
}
//! \return the scale draw
QwtRoundScaleDraw *QwtDial::scaleDraw()
{
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
}
//! \return the scale draw
const QwtRoundScaleDraw *QwtDial::scaleDraw() const
{
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
}
/*!
Set an individual scale draw
The motivation for setting a scale draw is often
to overload QwtRoundScaleDraw::label() to return
individual tick labels.
\param scaleDraw Scale draw
\warning The previous scale draw is deleted
*/
void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
{
setAbstractScaleDraw( scaleDraw );
sliderChange();
}
/*!
Change the arc of the scale
\param minArc Lower limit
\param maxArc Upper limit
\sa minScaleArc(), maxScaleArc()
*/
void QwtDial::setScaleArc( double minArc, double maxArc )
{
if ( minArc != 360.0 && minArc != -360.0 )
minArc = ::fmod( minArc, 360.0 );
if ( maxArc != 360.0 && maxArc != -360.0 )
maxArc = ::fmod( maxArc, 360.0 );
double minScaleArc = qMin( minArc, maxArc );
double maxScaleArc = qMax( minArc, maxArc );
if ( maxScaleArc - minScaleArc > 360.0 )
maxScaleArc = minScaleArc + 360.0;
if ( ( minScaleArc != d_data->minScaleArc ) ||
( maxScaleArc != d_data->maxScaleArc ) )
{
d_data->minScaleArc = minScaleArc;
d_data->maxScaleArc = maxScaleArc;
invalidateCache();
sliderChange();
}
}
/*!
Set the lower limit for the scale arc
\param min Lower limit of the scale arc
\sa setScaleArc(), setMaxScaleArc()
*/
void QwtDial::setMinScaleArc( double min )
{
setScaleArc( min, d_data->maxScaleArc );
}
/*!
\return Lower limit of the scale arc
\sa setScaleArc()
*/
double QwtDial::minScaleArc() const
{
return d_data->minScaleArc;
}
/*!
Set the upper limit for the scale arc
\param max Upper limit of the scale arc
\sa setScaleArc(), setMinScaleArc()
*/
void QwtDial::setMaxScaleArc( double max )
{
setScaleArc( d_data->minScaleArc, max );
}
/*!
\return Upper limit of the scale arc
\sa setScaleArc()
*/
double QwtDial::maxScaleArc() const
{
return d_data->maxScaleArc;
}
/*!
\brief Change the origin
The origin is the angle where scale and needle is relative to.
\param origin New origin
\sa origin()
*/
void QwtDial::setOrigin( double origin )
{
invalidateCache();
d_data->origin = origin;
sliderChange();
}
/*!
The origin is the angle where scale and needle is relative to.
\return Origin of the dial
\sa setOrigin()
*/
double QwtDial::origin() const
{
return d_data->origin;
}
/*!
\return Size hint
\sa minimumSizeHint()
*/
QSize QwtDial::sizeHint() const
{
int sh = 0;
if ( scaleDraw() )
sh = qCeil( scaleDraw()->extent( font() ) );
const int d = 6 * sh + 2 * lineWidth();
QSize hint( d, d );
if ( !isReadOnly() )
hint = hint.expandedTo( QApplication::globalStrut() );
return hint;
}
/*!
\return Minimum size hint
\sa sizeHint()
*/
QSize QwtDial::minimumSizeHint() const
{
int sh = 0;
if ( scaleDraw() )
sh = qCeil( scaleDraw()->extent( font() ) );
const int d = 3 * sh + 2 * lineWidth();
return QSize( d, d );
}
/*!
\brief Determine what to do when the user presses a mouse button.
\param pos Mouse position
\retval True, when the inner circle contains pos
\sa scrolledTo()
*/
bool QwtDial::isScrollPosition( const QPoint &pos ) const
{
const QRegion region( innerRect(), QRegion::Ellipse );
if ( region.contains( pos ) && ( pos != innerRect().center() ) )
{
double angle = QLineF( rect().center(), pos ).angle();
if ( d_data->mode == QwtDial::RotateScale )
angle = 360.0 - angle;
double valueAngle =
qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
d_data->arcOffset = scaleMap().p1();
return true;
}
return false;
}
/*!
\brief Determine the value for a new position of the
slider handle.
\param pos Mouse position
\return Value for the mouse position
\sa isScrollPosition()
*/
double QwtDial::scrolledTo( const QPoint &pos ) const
{
double angle = QLineF( rect().center(), pos ).angle();
if ( d_data->mode == QwtDial::RotateScale )
{
angle += scaleMap().p1() - d_data->arcOffset;
angle = 360.0 - angle;
}
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
angle = qwtNormalizeDegrees( 90.0 - angle );
if ( scaleMap().pDist() >= 360.0 )
{
if ( angle < scaleMap().p1() )
angle += 360.0;
if ( !wrapping() )
{
double boundedAngle = angle;
const double arc = angle - scaleMap().transform( value() );
if ( qAbs( arc ) > 180.0 )
{
boundedAngle = ( arc > 0 )
? scaleMap().p1() : scaleMap().p2();
}
d_data->mouseOffset += ( boundedAngle - angle );
angle = boundedAngle;
}
}
else
{
const double boundedAngle =
qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
if ( !wrapping() )
d_data->mouseOffset += ( boundedAngle - angle );
angle = boundedAngle;
}
return scaleMap().invTransform( angle );
}
/*!
Change Event handler
\param event Change event
Invalidates internal paint caches if necessary
*/
void QwtDial::changeEvent( QEvent *event )
{
switch( event->type() )
{
case QEvent::EnabledChange:
case QEvent::FontChange:
case QEvent::StyleChange:
case QEvent::PaletteChange:
case QEvent::LanguageChange:
case QEvent::LocaleChange:
{
invalidateCache();
break;
}
default:
break;
}
QwtAbstractSlider::changeEvent( event );
}
/*!
Wheel Event handler
\param event Wheel event
*/
void QwtDial::wheelEvent( QWheelEvent *event )
{
const QRegion region( innerRect(), QRegion::Ellipse );
if ( region.contains( event->pos() ) )
QwtAbstractSlider::wheelEvent( event );
}
void QwtDial::setAngleRange( double angle, double span )
{
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
if ( sd )
{
angle = qwtNormalizeDegrees( angle - 270.0 );
sd->setAngleRange( angle, angle + span );
}
}
/*!
Invalidate the internal caches and call
QwtAbstractSlider::scaleChange()
*/
void QwtDial::scaleChange()
{
invalidateCache();
QwtAbstractSlider::scaleChange();
}
void QwtDial::sliderChange()
{
setAngleRange( d_data->origin + d_data->minScaleArc,
d_data->maxScaleArc - d_data->minScaleArc );
if ( mode() == RotateScale )
{
const double arc = scaleMap().transform( value() ) - scaleMap().p1();
setAngleRange( d_data->origin - arc,
d_data->maxScaleArc - d_data->minScaleArc );
}
QwtAbstractSlider::sliderChange();
}

View File

@@ -0,0 +1,168 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_DIAL_H
#define QWT_DIAL_H 1
#include "qwt_global.h"
#include "qwt_abstract_slider.h"
#include "qwt_abstract_scale_draw.h"
#include <qframe.h>
#include <qpalette.h>
class QwtDialNeedle;
class QwtRoundScaleDraw;
/*!
\brief QwtDial class provides a rounded range control.
QwtDial is intended as base class for dial widgets like
speedometers, compass widgets, clocks ...
\image html dials2.png
A dial contains a scale and a needle indicating the current value
of the dial. Depending on Mode one of them is fixed and the
other is rotating. If not isReadOnly() the
dial can be rotated by dragging the mouse or using keyboard inputs
(see QwtAbstractSlider::keyPressEvent()). A dial might be wrapping, what means
a rotation below/above one limit continues on the other limit (f.e compass).
The scale might cover any arc of the dial, its values are related to
the origin() of the dial.
Often dials have to be updated very often according to values from external
devices. For these high refresh rates QwtDial caches as much as possible.
For derived classes it might be necessary to clear these caches manually
according to attribute changes using invalidateCache().
\sa QwtCompass, QwtAnalogClock, QwtDialNeedle
\note The controls and dials examples shows different types of dials.
\note QDial is more similar to QwtKnob than to QwtDial
*/
class QWT_EXPORT QwtDial: public QwtAbstractSlider
{
Q_OBJECT
Q_ENUMS( Shadow Mode Direction )
Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth )
Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
Q_PROPERTY( Mode mode READ mode WRITE setMode )
Q_PROPERTY( double origin READ origin WRITE setOrigin )
Q_PROPERTY( double minScaleArc READ minScaleArc WRITE setMinScaleArc )
Q_PROPERTY( double maxScaleArc READ maxScaleArc WRITE setMaxScaleArc )
public:
/*!
\brief Frame shadow
Unfortunately it is not possible to use QFrame::Shadow
as a property of a widget that is not derived from QFrame.
The following enum is made for the designer only. It is safe
to use QFrame::Shadow instead.
*/
enum Shadow
{
//! QFrame::Plain
Plain = QFrame::Plain,
//! QFrame::Raised
Raised = QFrame::Raised,
//! QFrame::Sunken
Sunken = QFrame::Sunken
};
//! Mode controlling whether the needle or the scale is rotating
enum Mode
{
//! The needle is rotating
RotateNeedle,
//! The needle is fixed, the scales are rotating
RotateScale
};
explicit QwtDial( QWidget *parent = NULL );
virtual ~QwtDial();
void setFrameShadow( Shadow );
Shadow frameShadow() const;
void setLineWidth( int );
int lineWidth() const;
void setMode( Mode );
Mode mode() const;
void setScaleArc( double min, double max );
void setMinScaleArc( double min );
double minScaleArc() const;
void setMaxScaleArc( double min );
double maxScaleArc() const;
virtual void setOrigin( double );
double origin() const;
void setNeedle( QwtDialNeedle * );
const QwtDialNeedle *needle() const;
QwtDialNeedle *needle();
QRect boundingRect() const;
QRect innerRect() const;
virtual QRect scaleInnerRect() const;
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
void setScaleDraw( QwtRoundScaleDraw * );
QwtRoundScaleDraw *scaleDraw();
const QwtRoundScaleDraw *scaleDraw() const;
protected:
virtual void wheelEvent( QWheelEvent * );
virtual void paintEvent( QPaintEvent * );
virtual void changeEvent( QEvent * );
virtual void drawFrame( QPainter *p );
virtual void drawContents( QPainter * ) const;
virtual void drawFocusIndicator( QPainter * ) const;
void invalidateCache();
virtual void drawScale( QPainter *,
const QPointF &center, double radius ) const;
virtual void drawScaleContents( QPainter *painter,
const QPointF &center, double radius ) const;
virtual void drawNeedle( QPainter *, const QPointF &,
double radius, double direction, QPalette::ColorGroup ) const;
virtual double scrolledTo( const QPoint & ) const;
virtual bool isScrollPosition( const QPoint & ) const;
virtual void sliderChange();
virtual void scaleChange();
private:
void setAngleRange( double angle, double span );
void drawNeedle( QPainter * ) const;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,440 @@
/* -*- 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_dial_needle.h"
#include "qwt_global.h"
#include "qwt_math.h"
#include "qwt_painter.h"
#include <qapplication.h>
#include <qpainter.h>
#if QT_VERSION < 0x040601
#define qFastSin(x) qSin(x)
#define qFastCos(x) qCos(x)
#endif
static void qwtDrawStyle1Needle( QPainter *painter,
const QPalette &palette, QPalette::ColorGroup colorGroup,
double length )
{
const double r[] = { 0.4, 0.3, 1, 0.8, 1, 0.3, 0.4 };
const double a[] = { -45, -20, -15, 0, 15, 20, 45 };
QPainterPath path;
for ( int i = 0; i < 7; i++ )
{
const double angle = a[i] / 180.0 * M_PI;
const double radius = r[i] * length;
const double x = radius * qFastCos( angle );
const double y = radius * qFastSin( angle );
path.lineTo( x, -y );
}
painter->setPen( Qt::NoPen );
painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
painter->drawPath( path );
}
static void qwtDrawStyle2Needle( QPainter *painter,
const QPalette &palette, QPalette::ColorGroup colorGroup, double length )
{
const double ratioX = 0.7;
const double ratioY = 0.3;
QPainterPath path1;
path1.lineTo( ratioX * length, 0.0 );
path1.lineTo( length, ratioY * length );
QPainterPath path2;
path2.lineTo( ratioX * length, 0.0 );
path2.lineTo( length, -ratioY * length );
painter->setPen( Qt::NoPen );
painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
painter->drawPath( path1 );
painter->setBrush( palette.brush( colorGroup, QPalette::Dark ) );
painter->drawPath( path2 );
}
static void qwtDrawShadedPointer( QPainter *painter,
const QColor &lightColor, const QColor &darkColor,
double length, double width )
{
const double peak = qMax( length / 10.0, 5.0 );
const double knobWidth = width + 8;
QRectF knobRect( 0, 0, knobWidth, knobWidth );
knobRect.moveCenter( QPointF(0, 0) );
QPainterPath path1;
path1.lineTo( 0.0, 0.5 * width );
path1.lineTo( length - peak, 0.5 * width );
path1.lineTo( length, 0.0 );
path1.lineTo( 0.0, 0.0 );
QPainterPath arcPath1;
arcPath1.arcTo( knobRect, 0.0, -90.0 );
path1 = path1.united( arcPath1 );
QPainterPath path2;
path2.lineTo( 0.0, -0.5 * width );
path2.lineTo( length - peak, -0.5 * width );
path2.lineTo( length, 0.0 );
path2.lineTo( 0.0, 0.0 );
QPainterPath arcPath2;
arcPath2.arcTo( knobRect, 0.0, 90.0 );
path2 = path2.united( arcPath2 );
painter->setPen( Qt::NoPen );
painter->setBrush( lightColor );
painter->drawPath( path1 );
painter->setBrush( darkColor );
painter->drawPath( path2 );
}
static void qwtDrawArrowNeedle( QPainter *painter,
const QPalette &palette, QPalette::ColorGroup colorGroup,
double length, double width )
{
if ( width <= 0 )
width = qMax( length * 0.06, 9.0 );
const double peak = qMax( 2.0, 0.4 * width );
QPainterPath path;
path.moveTo( 0.0, 0.5 * width );
path.lineTo( length - peak, 0.3 * width );
path.lineTo( length, 0.0 );
path.lineTo( length - peak, -0.3 * width );
path.lineTo( 0.0, -0.5 * width );
QRectF br = path.boundingRect();
QPalette pal( palette.color( QPalette::Mid ) );
QColor c1 = pal.color( QPalette::Light );
QColor c2 = pal.color( QPalette::Dark );
QLinearGradient gradient( br.topLeft(), br.bottomLeft() );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 0.5, c1 );
gradient.setColorAt( 0.5001, c2 );
gradient.setColorAt( 1.0, c2 );
QPen pen( gradient, 1 );
pen.setJoinStyle( Qt::MiterJoin );
painter->setPen( pen );
painter->setBrush( palette.brush( colorGroup, QPalette::Mid ) );
painter->drawPath( path );
}
static void qwtDrawTriangleNeedle( QPainter *painter,
const QPalette &palette, QPalette::ColorGroup colorGroup,
double length )
{
const double width = qRound( length / 3.0 );
QPainterPath path[4];
path[0].lineTo( length, 0.0 );
path[0].lineTo( 0.0, width / 2 );
path[1].lineTo( length, 0.0 );
path[1].lineTo( 0.0, -width / 2 );
path[2].lineTo( -length, 0.0 );
path[2].lineTo( 0.0, width / 2 );
path[3].lineTo( -length, 0.0 );
path[3].lineTo( 0.0, -width / 2 );
const int colorOffset = 10;
const QColor darkColor = palette.color( colorGroup, QPalette::Dark );
const QColor lightColor = palette.color( colorGroup, QPalette::Light );
QColor color[4];
color[0] = darkColor.light( 100 + colorOffset );
color[1] = darkColor.dark( 100 + colorOffset );
color[2] = lightColor.light( 100 + colorOffset );
color[3] = lightColor.dark( 100 + colorOffset );
painter->setPen( Qt::NoPen );
for ( int i = 0; i < 4; i++ )
{
painter->setBrush( color[i] );
painter->drawPath( path[i] );
}
}
//! Constructor
QwtDialNeedle::QwtDialNeedle():
d_palette( QApplication::palette() )
{
}
//! Destructor
QwtDialNeedle::~QwtDialNeedle()
{
}
/*!
Sets the palette for the needle.
\param palette New Palette
*/
void QwtDialNeedle::setPalette( const QPalette &palette )
{
d_palette = palette;
}
/*!
\return the palette of the needle.
*/
const QPalette &QwtDialNeedle::palette() const
{
return d_palette;
}
/*!
Draw the needle
\param painter Painter
\param center Center of the dial, start position for the needle
\param length Length of the needle
\param direction Direction of the needle, in degrees counter clockwise
\param colorGroup Color group, used for painting
*/
void QwtDialNeedle::draw( QPainter *painter,
const QPointF &center, double length, double direction,
QPalette::ColorGroup colorGroup ) const
{
painter->save();
painter->translate( center );
painter->rotate( -direction );
drawNeedle( painter, length, colorGroup );
painter->restore();
}
//! Draw the knob
void QwtDialNeedle::drawKnob( QPainter *painter,
double width, const QBrush &brush, bool sunken ) const
{
QPalette palette( brush.color() );
QColor c1 = palette.color( QPalette::Light );
QColor c2 = palette.color( QPalette::Dark );
if ( sunken )
qSwap( c1, c2 );
QRectF rect( 0.0, 0.0, width, width );
rect.moveCenter( painter->combinedTransform().map( QPointF() ) );
QLinearGradient gradient( rect.topLeft(), rect.bottomRight() );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 0.3, c1 );
gradient.setColorAt( 0.7, c2 );
gradient.setColorAt( 1.0, c2 );
painter->save();
painter->resetTransform();
painter->setPen( QPen( gradient, 1 ) );
painter->setBrush( brush );
painter->drawEllipse( rect );
painter->restore();
}
/*!
Constructor
\param style Style
\param hasKnob With/Without knob
\param mid Middle color
\param base Base color
*/
QwtDialSimpleNeedle::QwtDialSimpleNeedle( Style style, bool hasKnob,
const QColor &mid, const QColor &base ):
d_style( style ),
d_hasKnob( hasKnob ),
d_width( -1 )
{
QPalette palette;
palette.setColor( QPalette::Mid, mid );
palette.setColor( QPalette::Base, base );
setPalette( palette );
}
/*!
Set the width of the needle
\param width Width
\sa width()
*/
void QwtDialSimpleNeedle::setWidth( double width )
{
d_width = width;
}
/*!
\return the width of the needle
\sa setWidth()
*/
double QwtDialSimpleNeedle::width() const
{
return d_width;
}
/*!
Draw the needle
\param painter Painter
\param length Length of the needle
\param colorGroup Color group, used for painting
*/
void QwtDialSimpleNeedle::drawNeedle( QPainter *painter,
double length, QPalette::ColorGroup colorGroup ) const
{
double knobWidth = 0.0;
double width = d_width;
if ( d_style == Arrow )
{
if ( width <= 0.0 )
width = qMax(length * 0.06, 6.0);
qwtDrawArrowNeedle( painter,
palette(), colorGroup, length, width );
knobWidth = qMin( width * 2.0, 0.2 * length );
}
else
{
if ( width <= 0.0 )
width = 5.0;
QPen pen ( palette().brush( colorGroup, QPalette::Mid ), width );
pen.setCapStyle( Qt::FlatCap );
painter->setPen( pen );
painter->drawLine( QPointF( 0.0, 0.0 ), QPointF( length, 0.0 ) );
knobWidth = qMax( width * 3.0, 5.0 );
}
if ( d_hasKnob && knobWidth > 0.0 )
{
drawKnob( painter, knobWidth,
palette().brush( colorGroup, QPalette::Base ), false );
}
}
//! Constructor
QwtCompassMagnetNeedle::QwtCompassMagnetNeedle( Style style,
const QColor &light, const QColor &dark ):
d_style( style )
{
QPalette palette;
palette.setColor( QPalette::Light, light );
palette.setColor( QPalette::Dark, dark );
palette.setColor( QPalette::Base, Qt::gray );
setPalette( palette );
}
/*!
Draw the needle
\param painter Painter
\param length Length of the needle
\param colorGroup Color group, used for painting
*/
void QwtCompassMagnetNeedle::drawNeedle( QPainter *painter,
double length, QPalette::ColorGroup colorGroup ) const
{
if ( d_style == ThinStyle )
{
const double width = qMax( length / 6.0, 3.0 );
const int colorOffset = 10;
const QColor light = palette().color( colorGroup, QPalette::Light );
const QColor dark = palette().color( colorGroup, QPalette::Dark );
qwtDrawShadedPointer( painter,
dark.light( 100 + colorOffset ),
dark.dark( 100 + colorOffset ),
length, width );
painter->rotate( 180.0 );
qwtDrawShadedPointer( painter,
light.light( 100 + colorOffset ),
light.dark( 100 + colorOffset ),
length, width );
const QBrush baseBrush = palette().brush( colorGroup, QPalette::Base );
drawKnob( painter, width, baseBrush, true );
}
else
{
qwtDrawTriangleNeedle( painter, palette(), colorGroup, length );
}
}
/*!
Constructor
\param style Arrow style
\param light Light color
\param dark Dark color
*/
QwtCompassWindArrow::QwtCompassWindArrow( Style style,
const QColor &light, const QColor &dark ):
d_style( style )
{
QPalette palette;
palette.setColor( QPalette::Light, light );
palette.setColor( QPalette::Dark, dark );
setPalette( palette );
}
/*!
Draw the needle
\param painter Painter
\param length Length of the needle
\param colorGroup Color group, used for painting
*/
void QwtCompassWindArrow::drawNeedle( QPainter *painter,
double length, QPalette::ColorGroup colorGroup ) const
{
if ( d_style == Style1 )
qwtDrawStyle1Needle( painter, palette(), colorGroup, length );
else
qwtDrawStyle2Needle( painter, palette(), colorGroup, length );
}

View File

@@ -0,0 +1,187 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_DIAL_NEEDLE_H
#define QWT_DIAL_NEEDLE_H 1
#include "qwt_global.h"
#include <qpalette.h>
class QPainter;
class QPoint;
/*!
\brief Base class for needles that can be used in a QwtDial.
QwtDialNeedle is a pointer that indicates a value by pointing
to a specific direction.
\sa QwtDial, QwtCompass
*/
class QWT_EXPORT QwtDialNeedle
{
public:
QwtDialNeedle();
virtual ~QwtDialNeedle();
virtual void setPalette( const QPalette & );
const QPalette &palette() const;
virtual void draw( QPainter *painter, const QPointF &center,
double length, double direction,
QPalette::ColorGroup = QPalette::Active ) const;
protected:
/*!
\brief Draw the needle
The origin of the needle is at position (0.0, 0.0 )
pointing in direction 0.0 ( = east ).
The painter is already initialized with translation and
rotation.
\param painter Painter
\param length Length of the needle
\param colorGroup Color group, used for painting
\sa setPalette(), palette()
*/
virtual void drawNeedle( QPainter *painter,
double length, QPalette::ColorGroup colorGroup ) const = 0;
virtual void drawKnob( QPainter *, double width,
const QBrush &, bool sunken ) const;
private:
QPalette d_palette;
};
/*!
\brief A needle for dial widgets
The following colors are used:
- QPalette::Mid\n
Pointer
- QPalette::Base\n
Knob
\sa QwtDial, QwtCompass
*/
class QWT_EXPORT QwtDialSimpleNeedle: public QwtDialNeedle
{
public:
//! Style of the needle
enum Style
{
//! Arrow
Arrow,
//! A straight line from the center
Ray
};
QwtDialSimpleNeedle( Style, bool hasKnob = true,
const QColor &mid = Qt::gray, const QColor &base = Qt::darkGray );
void setWidth( double width );
double width() const;
protected:
virtual void drawNeedle( QPainter *, double length,
QPalette::ColorGroup ) const;
private:
Style d_style;
bool d_hasKnob;
double d_width;
};
/*!
\brief A magnet needle for compass widgets
A magnet needle points to two opposite directions indicating
north and south.
The following colors are used:
- QPalette::Light\n
Used for pointing south
- QPalette::Dark\n
Used for pointing north
- QPalette::Base\n
Knob (ThinStyle only)
\sa QwtDial, QwtCompass
*/
class QWT_EXPORT QwtCompassMagnetNeedle: public QwtDialNeedle
{
public:
//! Style of the needle
enum Style
{
//! A needle with a triangular shape
TriangleStyle,
//! A thin needle
ThinStyle
};
QwtCompassMagnetNeedle( Style = TriangleStyle,
const QColor &light = Qt::white, const QColor &dark = Qt::red );
protected:
virtual void drawNeedle( QPainter *,
double length, QPalette::ColorGroup ) const;
private:
Style d_style;
};
/*!
\brief An indicator for the wind direction
QwtCompassWindArrow shows the direction where the wind comes from.
- QPalette::Light\n
Used for Style1, or the light half of Style2
- QPalette::Dark\n
Used for the dark half of Style2
\sa QwtDial, QwtCompass
*/
class QWT_EXPORT QwtCompassWindArrow: public QwtDialNeedle
{
public:
//! Style of the arrow
enum Style
{
//! A needle pointing to the center
Style1,
//! A needle pointing to the center
Style2
};
QwtCompassWindArrow( Style, const QColor &light = Qt::white,
const QColor &dark = Qt::gray );
protected:
virtual void drawNeedle( QPainter *,
double length, QPalette::ColorGroup ) const;
private:
Style d_style;
};
#endif

View File

@@ -0,0 +1,591 @@
/* -*- 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_dyngrid_layout.h"
#include "qwt_math.h"
#include <qvector.h>
#include <qlist.h>
class QwtDynGridLayout::PrivateData
{
public:
PrivateData():
isDirty( true )
{
}
void updateLayoutCache();
mutable QList<QLayoutItem*> itemList;
uint maxColumns;
uint numRows;
uint numColumns;
Qt::Orientations expanding;
bool isDirty;
QVector<QSize> itemSizeHints;
};
void QwtDynGridLayout::PrivateData::updateLayoutCache()
{
itemSizeHints.resize( itemList.count() );
int index = 0;
for ( QList<QLayoutItem*>::iterator it = itemList.begin();
it != itemList.end(); ++it, index++ )
{
itemSizeHints[ index ] = ( *it )->sizeHint();
}
isDirty = false;
}
/*!
\param parent Parent widget
\param margin Margin
\param spacing Spacing
*/
QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
int margin, int spacing ):
QLayout( parent )
{
init();
setSpacing( spacing );
setMargin( margin );
}
/*!
\param spacing Spacing
*/
QwtDynGridLayout::QwtDynGridLayout( int spacing )
{
init();
setSpacing( spacing );
}
/*!
Initialize the layout with default values.
*/
void QwtDynGridLayout::init()
{
d_data = new QwtDynGridLayout::PrivateData;
d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
d_data->expanding = 0;
}
//! Destructor
QwtDynGridLayout::~QwtDynGridLayout()
{
for ( int i = 0; i < d_data->itemList.size(); i++ )
delete d_data->itemList[i];
delete d_data;
}
//! Invalidate all internal caches
void QwtDynGridLayout::invalidate()
{
d_data->isDirty = true;
QLayout::invalidate();
}
/*!
Limit the number of columns.
\param maxColumns upper limit, 0 means unlimited
\sa maxColumns()
*/
void QwtDynGridLayout::setMaxColumns( uint maxColumns )
{
d_data->maxColumns = maxColumns;
}
/*!
\brief Return the upper limit for the number of columns.
0 means unlimited, what is the default.
\return Upper limit for the number of columns
\sa setMaxColumns()
*/
uint QwtDynGridLayout::maxColumns() const
{
return d_data->maxColumns;
}
/*!
\brief Add an item to the next free position.
\param item Layout item
*/
void QwtDynGridLayout::addItem( QLayoutItem *item )
{
d_data->itemList.append( item );
invalidate();
}
/*!
\return true if this layout is empty.
*/
bool QwtDynGridLayout::isEmpty() const
{
return d_data->itemList.isEmpty();
}
/*!
\return number of layout items
*/
uint QwtDynGridLayout::itemCount() const
{
return d_data->itemList.count();
}
/*!
Find the item at a specific index
\param index Index
\return Item at a specific index
\sa takeAt()
*/
QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
{
if ( index < 0 || index >= d_data->itemList.count() )
return NULL;
return d_data->itemList.at( index );
}
/*!
Find the item at a specific index and remove it from the layout
\param index Index
\return Layout item, removed from the layout
\sa itemAt()
*/
QLayoutItem *QwtDynGridLayout::takeAt( int index )
{
if ( index < 0 || index >= d_data->itemList.count() )
return NULL;
d_data->isDirty = true;
return d_data->itemList.takeAt( index );
}
//! \return Number of items in the layout
int QwtDynGridLayout::count() const
{
return d_data->itemList.count();
}
/*!
Set whether this layout can make use of more space than sizeHint().
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
to grow in both dimensions. The default value is 0.
\param expanding Or'd orientations
\sa expandingDirections()
*/
void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
{
d_data->expanding = expanding;
}
/*!
\brief Returns whether this layout can make use of more space than sizeHint().
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
to grow in both dimensions.
\return Orientations, where the layout expands
\sa setExpandingDirections()
*/
Qt::Orientations QwtDynGridLayout::expandingDirections() const
{
return d_data->expanding;
}
/*!
Reorganizes columns and rows and resizes managed items within
a rectangle.
\param rect Layout geometry
*/
void QwtDynGridLayout::setGeometry( const QRect &rect )
{
QLayout::setGeometry( rect );
if ( isEmpty() )
return;
d_data->numColumns = columnsForWidth( rect.width() );
d_data->numRows = itemCount() / d_data->numColumns;
if ( itemCount() % d_data->numColumns )
d_data->numRows++;
QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
int index = 0;
for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
it != d_data->itemList.end(); ++it )
{
( *it )->setGeometry( itemGeometries[index] );
index++;
}
}
/*!
\brief Calculate the number of columns for a given width.
The calculation tries to use as many columns as possible
( limited by maxColumns() )
\param width Available width for all columns
\return Number of columns for a given width
\sa maxColumns(), setMaxColumns()
*/
uint QwtDynGridLayout::columnsForWidth( int width ) const
{
if ( isEmpty() )
return 0;
uint maxColumns = itemCount();
if ( d_data->maxColumns > 0 )
maxColumns = qMin( d_data->maxColumns, maxColumns );
if ( maxRowWidth( maxColumns ) <= width )
return maxColumns;
for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
{
const int rowWidth = maxRowWidth( numColumns );
if ( rowWidth > width )
return numColumns - 1;
}
return 1; // At least 1 column
}
/*!
Calculate the width of a layout for a given number of
columns.
\param numColumns Given number of columns
\param itemWidth Array of the width hints for all items
*/
int QwtDynGridLayout::maxRowWidth( int numColumns ) const
{
int col;
QVector<int> colWidth( numColumns );
for ( col = 0; col < numColumns; col++ )
colWidth[col] = 0;
if ( d_data->isDirty )
d_data->updateLayoutCache();
for ( int index = 0;
index < d_data->itemSizeHints.count(); index++ )
{
col = index % numColumns;
colWidth[col] = qMax( colWidth[col],
d_data->itemSizeHints[int( index )].width() );
}
int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
for ( col = 0; col < numColumns; col++ )
rowWidth += colWidth[col];
return rowWidth;
}
/*!
\return the maximum width of all layout items
*/
int QwtDynGridLayout::maxItemWidth() const
{
if ( isEmpty() )
return 0;
if ( d_data->isDirty )
d_data->updateLayoutCache();
int w = 0;
for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
{
const int itemW = d_data->itemSizeHints[i].width();
if ( itemW > w )
w = itemW;
}
return w;
}
/*!
Calculate the geometries of the layout items for a layout
with numColumns columns and a given rectangle.
\param rect Rect where to place the items
\param numColumns Number of columns
\return item geometries
*/
QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
uint numColumns ) const
{
QList<QRect> itemGeometries;
if ( numColumns == 0 || isEmpty() )
return itemGeometries;
uint numRows = itemCount() / numColumns;
if ( numColumns % itemCount() )
numRows++;
if ( numRows == 0 )
return itemGeometries;
QVector<int> rowHeight( numRows );
QVector<int> colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
bool expandH, expandV;
expandH = expandingDirections() & Qt::Horizontal;
expandV = expandingDirections() & Qt::Vertical;
if ( expandH || expandV )
stretchGrid( rect, numColumns, rowHeight, colWidth );
const int maxColumns = d_data->maxColumns;
d_data->maxColumns = numColumns;
const QRect alignedRect = alignmentRect( rect );
d_data->maxColumns = maxColumns;
const int xOffset = expandH ? 0 : alignedRect.x();
const int yOffset = expandV ? 0 : alignedRect.y();
QVector<int> colX( numColumns );
QVector<int> rowY( numRows );
const int xySpace = spacing();
rowY[0] = yOffset + margin();
for ( uint r = 1; r < numRows; r++ )
rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
colX[0] = xOffset + margin();
for ( uint c = 1; c < numColumns; c++ )
colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
const int itemCount = d_data->itemList.size();
for ( int i = 0; i < itemCount; i++ )
{
const int row = i / numColumns;
const int col = i % numColumns;
QRect itemGeometry( colX[col], rowY[row],
colWidth[col], rowHeight[row] );
itemGeometries.append( itemGeometry );
}
return itemGeometries;
}
/*!
Calculate the dimensions for the columns and rows for a grid
of numColumns columns.
\param numColumns Number of columns.
\param rowHeight Array where to fill in the calculated row heights.
\param colWidth Array where to fill in the calculated column widths.
*/
void QwtDynGridLayout::layoutGrid( uint numColumns,
QVector<int>& rowHeight, QVector<int>& colWidth ) const
{
if ( numColumns <= 0 )
return;
if ( d_data->isDirty )
d_data->updateLayoutCache();
for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
{
const int row = index / numColumns;
const int col = index % numColumns;
const QSize &size = d_data->itemSizeHints[int( index )];
rowHeight[row] = ( col == 0 )
? size.height() : qMax( rowHeight[row], size.height() );
colWidth[col] = ( row == 0 )
? size.width() : qMax( colWidth[col], size.width() );
}
}
/*!
\return true: QwtDynGridLayout implements heightForWidth().
\sa heightForWidth()
*/
bool QwtDynGridLayout::hasHeightForWidth() const
{
return true;
}
/*!
\return The preferred height for this layout, given a width.
\sa hasHeightForWidth()
*/
int QwtDynGridLayout::heightForWidth( int width ) const
{
if ( isEmpty() )
return 0;
const uint numColumns = columnsForWidth( width );
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
QVector<int> rowHeight( numRows );
QVector<int> colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
int h = 2 * margin() + ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
h += rowHeight[row];
return h;
}
/*!
Stretch columns in case of expanding() & QSizePolicy::Horizontal and
rows in case of expanding() & QSizePolicy::Vertical to fill the entire
rect. Rows and columns are stretched with the same factor.
\param rect Bounding rectangle
\param numColumns Number of columns
\param rowHeight Array to be filled with the calculated row heights
\param colWidth Array to be filled with the calculated column widths
\sa setExpanding(), expanding()
*/
void QwtDynGridLayout::stretchGrid( const QRect &rect,
uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
{
if ( numColumns == 0 || isEmpty() )
return;
bool expandH, expandV;
expandH = expandingDirections() & Qt::Horizontal;
expandV = expandingDirections() & Qt::Vertical;
if ( expandH )
{
int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
for ( uint col = 0; col < numColumns; col++ )
xDelta -= colWidth[col];
if ( xDelta > 0 )
{
for ( uint col = 0; col < numColumns; col++ )
{
const int space = xDelta / ( numColumns - col );
colWidth[col] += space;
xDelta -= space;
}
}
}
if ( expandV )
{
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
yDelta -= rowHeight[row];
if ( yDelta > 0 )
{
for ( uint row = 0; row < numRows; row++ )
{
const int space = yDelta / ( numRows - row );
rowHeight[row] += space;
yDelta -= space;
}
}
}
}
/*!
Return the size hint. If maxColumns() > 0 it is the size for
a grid with maxColumns() columns, otherwise it is the size for
a grid with only one row.
\return Size hint
\sa maxColumns(), setMaxColumns()
*/
QSize QwtDynGridLayout::sizeHint() const
{
if ( isEmpty() )
return QSize();
uint numColumns = itemCount();
if ( d_data->maxColumns > 0 )
numColumns = qMin( d_data->maxColumns, numColumns );
uint numRows = itemCount() / numColumns;
if ( itemCount() % numColumns )
numRows++;
QVector<int> rowHeight( numRows );
QVector<int> colWidth( numColumns );
layoutGrid( numColumns, rowHeight, colWidth );
int h = 2 * margin() + ( numRows - 1 ) * spacing();
for ( uint row = 0; row < numRows; row++ )
h += rowHeight[row];
int w = 2 * margin() + ( numColumns - 1 ) * spacing();
for ( uint col = 0; col < numColumns; col++ )
w += colWidth[col];
return QSize( w, h );
}
/*!
\return Number of rows of the current layout.
\sa numColumns()
\warning The number of rows might change whenever the geometry changes
*/
uint QwtDynGridLayout::numRows() const
{
return d_data->numRows;
}
/*!
\return Number of columns of the current layout.
\sa numRows()
\warning The number of columns might change whenever the geometry changes
*/
uint QwtDynGridLayout::numColumns() const
{
return d_data->numColumns;
}

View File

@@ -0,0 +1,83 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_DYNGRID_LAYOUT_H
#define QWT_DYNGRID_LAYOUT_H
#include "qwt_global.h"
#include <qlayout.h>
#include <qsize.h>
#include <qlist.h>
/*!
\brief The QwtDynGridLayout class lays out widgets in a grid,
adjusting the number of columns and rows to the current size.
QwtDynGridLayout takes the space it gets, divides it up into rows and
columns, and puts each of the widgets it manages into the correct cell(s).
It lays out as many number of columns as possible (limited by maxColumns()).
*/
class QWT_EXPORT QwtDynGridLayout : public QLayout
{
Q_OBJECT
public:
explicit QwtDynGridLayout( QWidget *, int margin = 0, int space = -1 );
explicit QwtDynGridLayout( int space = -1 );
virtual ~QwtDynGridLayout();
virtual void invalidate();
void setMaxColumns( uint maxCols );
uint maxColumns() const;
uint numRows () const;
uint numColumns () const;
virtual void addItem( QLayoutItem * );
virtual QLayoutItem *itemAt( int index ) const;
virtual QLayoutItem *takeAt( int index );
virtual int count() const;
void setExpandingDirections( Qt::Orientations );
virtual Qt::Orientations expandingDirections() const;
QList<QRect> layoutItems( const QRect &, uint numCols ) const;
virtual int maxItemWidth() const;
virtual void setGeometry( const QRect &rect );
virtual bool hasHeightForWidth() const;
virtual int heightForWidth( int ) const;
virtual QSize sizeHint() const;
virtual bool isEmpty() const;
uint itemCount() const;
virtual uint columnsForWidth( int width ) const;
protected:
void layoutGrid( uint numCols,
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
void stretchGrid( const QRect &rect, uint numCols,
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
private:
void init();
int maxRowWidth( int numCols ) const;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,265 @@
/* -*- 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_event_pattern.h"
#include <qevent.h>
/*!
Constructor
\sa MousePatternCode, KeyPatternCode
*/
QwtEventPattern::QwtEventPattern():
d_mousePattern( MousePatternCount ),
d_keyPattern( KeyPatternCount )
{
initKeyPattern();
initMousePattern( 3 );
}
//! Destructor
QwtEventPattern::~QwtEventPattern()
{
}
/*!
Set default mouse patterns, depending on the number of mouse buttons
\param numButtons Number of mouse buttons ( <= 3 )
\sa MousePatternCode
*/
void QwtEventPattern::initMousePattern( int numButtons )
{
d_mousePattern.resize( MousePatternCount );
switch ( numButtons )
{
case 1:
{
setMousePattern( MouseSelect1, Qt::LeftButton );
setMousePattern( MouseSelect2, Qt::LeftButton, Qt::ControlModifier );
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
break;
}
case 2:
{
setMousePattern( MouseSelect1, Qt::LeftButton );
setMousePattern( MouseSelect2, Qt::RightButton );
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
break;
}
default:
{
setMousePattern( MouseSelect1, Qt::LeftButton );
setMousePattern( MouseSelect2, Qt::RightButton );
setMousePattern( MouseSelect3, Qt::MidButton );
}
}
setMousePattern( MouseSelect4, d_mousePattern[MouseSelect1].button,
d_mousePattern[MouseSelect1].modifiers | Qt::ShiftModifier );
setMousePattern( MouseSelect5, d_mousePattern[MouseSelect2].button,
d_mousePattern[MouseSelect2].modifiers | Qt::ShiftModifier );
setMousePattern( MouseSelect6, d_mousePattern[MouseSelect3].button,
d_mousePattern[MouseSelect3].modifiers | Qt::ShiftModifier );
}
/*!
Set default mouse patterns.
\sa KeyPatternCode
*/
void QwtEventPattern::initKeyPattern()
{
d_keyPattern.resize( KeyPatternCount );
setKeyPattern( KeySelect1, Qt::Key_Return );
setKeyPattern( KeySelect2, Qt::Key_Space );
setKeyPattern( KeyAbort, Qt::Key_Escape );
setKeyPattern( KeyLeft, Qt::Key_Left );
setKeyPattern( KeyRight, Qt::Key_Right );
setKeyPattern( KeyUp, Qt::Key_Up );
setKeyPattern( KeyDown, Qt::Key_Down );
setKeyPattern( KeyRedo, Qt::Key_Plus );
setKeyPattern( KeyUndo, Qt::Key_Minus );
setKeyPattern( KeyHome, Qt::Key_Escape );
}
/*!
Change one mouse pattern
\param pattern Index of the pattern
\param button Button
\param modifiers Keyboard modifiers
\sa QMouseEvent
*/
void QwtEventPattern::setMousePattern( MousePatternCode pattern,
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
{
if ( pattern >= 0 && pattern < MousePatternCount )
{
d_mousePattern[ pattern ].button = button;
d_mousePattern[ pattern ].modifiers = modifiers;
}
}
/*!
Change one key pattern
\param pattern Index of the pattern
\param key Key
\param modifiers Keyboard modifiers
\sa QKeyEvent
*/
void QwtEventPattern::setKeyPattern( KeyPatternCode pattern,
int key, Qt::KeyboardModifiers modifiers )
{
if ( pattern >= 0 && pattern < KeyPatternCount )
{
d_keyPattern[ pattern ].key = key;
d_keyPattern[ pattern ].modifiers = modifiers;
}
}
//! Change the mouse event patterns
void QwtEventPattern::setMousePattern( const QVector<MousePattern> &pattern )
{
d_mousePattern = pattern;
}
//! Change the key event patterns
void QwtEventPattern::setKeyPattern( const QVector<KeyPattern> &pattern )
{
d_keyPattern = pattern;
}
//! \return Mouse pattern
const QVector<QwtEventPattern::MousePattern> &
QwtEventPattern::mousePattern() const
{
return d_mousePattern;
}
//! \return Key pattern
const QVector<QwtEventPattern::KeyPattern> &
QwtEventPattern::keyPattern() const
{
return d_keyPattern;
}
//! \return Mouse pattern
QVector<QwtEventPattern::MousePattern> &QwtEventPattern::mousePattern()
{
return d_mousePattern;
}
//! \return Key pattern
QVector<QwtEventPattern::KeyPattern> &QwtEventPattern::keyPattern()
{
return d_keyPattern;
}
/*!
\brief Compare a mouse event with an event pattern.
A mouse event matches the pattern when both have the same button
value and in the state value the same key flags(Qt::KeyButtonMask)
are set.
\param code Index of the event pattern
\param event Mouse event
\return true if matches
\sa keyMatch()
*/
bool QwtEventPattern::mouseMatch( MousePatternCode code,
const QMouseEvent *event ) const
{
if ( code >= 0 && code < MousePatternCount )
return mouseMatch( d_mousePattern[ code ], event );
return false;
}
/*!
\brief Compare a mouse event with an event pattern.
A mouse event matches the pattern when both have the same button
value and in the state value the same key flags(Qt::KeyButtonMask)
are set.
\param pattern Mouse event pattern
\param event Mouse event
\return true if matches
\sa keyMatch()
*/
bool QwtEventPattern::mouseMatch( const MousePattern &pattern,
const QMouseEvent *event ) const
{
if ( event == NULL )
return false;
const MousePattern mousePattern( event->button(), event->modifiers() );
return mousePattern == pattern;
}
/*!
\brief Compare a key event with an event pattern.
A key event matches the pattern when both have the same key
value and in the state value the same key flags (Qt::KeyButtonMask)
are set.
\param code Index of the event pattern
\param event Key event
\return true if matches
\sa mouseMatch()
*/
bool QwtEventPattern::keyMatch( KeyPatternCode code,
const QKeyEvent *event ) const
{
if ( code >= 0 && code < KeyPatternCount )
return keyMatch( d_keyPattern[ code ], event );
return false;
}
/*!
\brief Compare a key event with an event pattern.
A key event matches the pattern when both have the same key
value and in the state value the same key flags (Qt::KeyButtonMask)
are set.
\param pattern Key event pattern
\param event Key event
\return true if matches
\sa mouseMatch()
*/
bool QwtEventPattern::keyMatch(
const KeyPattern &pattern, const QKeyEvent *event ) const
{
if ( event == NULL )
return false;
const KeyPattern keyPattern( event->key(), event->modifiers() );
return keyPattern == pattern;
}

View File

@@ -0,0 +1,240 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_EVENT_PATTERN
#define QWT_EVENT_PATTERN 1
#include "qwt_global.h"
#include <qnamespace.h>
#include <qvector.h>
class QMouseEvent;
class QKeyEvent;
/*!
\brief A collection of event patterns
QwtEventPattern introduces an level of indirection for mouse and
keyboard inputs. Those are represented by symbolic names, so
the application code can be configured by individual mappings.
\sa QwtPicker, QwtPickerMachine, QwtPlotZoomer
*/
class QWT_EXPORT QwtEventPattern
{
public:
/*!
\brief Symbolic mouse input codes
QwtEventPattern implements 3 different settings for
mice with 1, 2, or 3 buttons that can be activated
using initMousePattern(). The default setting is for
3 button mice.
Individual settings can be configured using setMousePattern().
\sa initMousePattern(), setMousePattern(), setKeyPattern()
*/
enum MousePatternCode
{
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton
- Qt::LeftButton
- Qt::LeftButton
*/
MouseSelect1,
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton + Qt::ControlModifier
- Qt::RightButton
- Qt::RightButton
*/
MouseSelect2,
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton + Qt::AltModifier
- Qt::LeftButton + Qt::AltModifier
- Qt::MidButton
*/
MouseSelect3,
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton + Qt::ShiftModifier
- Qt::LeftButton + Qt::ShiftModifier
- Qt::LeftButton + Qt::ShiftModifier
*/
MouseSelect4,
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton + Qt::ControlButton | Qt::ShiftModifier
- Qt::RightButton + Qt::ShiftModifier
- Qt::RightButton + Qt::ShiftModifier
*/
MouseSelect5,
/*!
The default setting for 1, 2 and 3 button mice is:
- Qt::LeftButton + Qt::AltModifier + Qt::ShiftModifier
- Qt::LeftButton + Qt::AltModifier | Qt::ShiftModifier
- Qt::MidButton + Qt::ShiftModifier
*/
MouseSelect6,
//! Number of mouse patterns
MousePatternCount
};
/*!
\brief Symbolic keyboard input codes
Individual settings can be configured using setKeyPattern()
\sa setKeyPattern(), setMousePattern()
*/
enum KeyPatternCode
{
//! Qt::Key_Return
KeySelect1,
//! Qt::Key_Space
KeySelect2,
//! Qt::Key_Escape
KeyAbort,
//! Qt::Key_Left
KeyLeft,
//! Qt::Key_Right
KeyRight,
//! Qt::Key_Up
KeyUp,
//! Qt::Key_Down
KeyDown,
//! Qt::Key_Plus
KeyRedo,
//! Qt::Key_Minus
KeyUndo,
//! Qt::Key_Escape
KeyHome,
//! Number of key patterns
KeyPatternCount
};
//! A pattern for mouse events
class MousePattern
{
public:
//! Constructor
MousePattern( Qt::MouseButton btn = Qt::NoButton,
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
button( btn ),
modifiers( modifierCodes )
{
}
//! Button
Qt::MouseButton button;
//! Keyboard modifier
Qt::KeyboardModifiers modifiers;
};
//! A pattern for key events
class KeyPattern
{
public:
//! Constructor
KeyPattern( int keyCode = Qt::Key_unknown,
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
key( keyCode ),
modifiers( modifierCodes )
{
}
//! Key code
int key;
//! Modifiers
Qt::KeyboardModifiers modifiers;
};
QwtEventPattern();
virtual ~QwtEventPattern();
void initMousePattern( int numButtons );
void initKeyPattern();
void setMousePattern( MousePatternCode, Qt::MouseButton button,
Qt::KeyboardModifiers = Qt::NoModifier );
void setKeyPattern( KeyPatternCode, int keyCode,
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier );
void setMousePattern( const QVector<MousePattern> & );
void setKeyPattern( const QVector<KeyPattern> & );
const QVector<MousePattern> &mousePattern() const;
const QVector<KeyPattern> &keyPattern() const;
QVector<MousePattern> &mousePattern();
QVector<KeyPattern> &keyPattern();
bool mouseMatch( MousePatternCode, const QMouseEvent * ) const;
bool keyMatch( KeyPatternCode, const QKeyEvent * ) const;
protected:
virtual bool mouseMatch( const MousePattern &, const QMouseEvent * ) const;
virtual bool keyMatch( const KeyPattern &, const QKeyEvent * ) const;
private:
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable: 4251)
#endif
QVector<MousePattern> d_mousePattern;
QVector<KeyPattern> d_keyPattern;
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
};
//! Compare operator
inline bool operator==( QwtEventPattern::MousePattern b1,
QwtEventPattern::MousePattern b2 )
{
return b1.button == b2.button && b1.modifiers == b2.modifiers;
}
//! Compare operator
inline bool operator==( QwtEventPattern::KeyPattern b1,
QwtEventPattern::KeyPattern b2 )
{
return b1.key == b2.key && b1.modifiers == b2.modifiers;
}
#endif

View File

@@ -0,0 +1,41 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_GLOBAL_H
#define QWT_GLOBAL_H
#include <qglobal.h>
// QWT_VERSION is (major << 16) + (minor << 8) + patch.
#define QWT_VERSION 0x060103
#define QWT_VERSION_STR "6.1.3"
#if defined(_MSC_VER) /* MSVC Compiler */
/* template-class specialization 'identifier' is already instantiated */
#pragma warning(disable: 4660)
/* inherits via dominance */
#pragma warning(disable: 4250)
#endif // _MSC_VER
#ifdef QWT_DLL
#if defined(QWT_MAKEDLL) // create a Qwt DLL library
#define QWT_EXPORT Q_DECL_EXPORT
#else // use a Qwt DLL library
#define QWT_EXPORT Q_DECL_IMPORT
#endif
#endif // QWT_DLL
#ifndef QWT_EXPORT
#define QWT_EXPORT
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_GRAPHIC_H
#define QWT_GRAPHIC_H
#include "qwt_global.h"
#include "qwt_null_paintdevice.h"
#include <qmetatype.h>
#include <qimage.h>
#include <qpixmap.h>
class QwtPainterCommand;
/*!
\brief A paint device for scalable graphics
QwtGraphic is the representation of a graphic that is tailored for
scalability. Like QPicture it will be initialized by QPainter
operations and can be replayed later to any target paint device.
While the usual image representations QImage and QPixmap are not
scalable Qt offers two paint devices, that might be candidates
for representing a vector graphic:
- QPicture\n
Unfortunately QPicture had been forgotten, when Qt4
introduced floating point based render engines. Its API
is still on integers, what make it unusable for proper scaling.
- QSvgRenderer/QSvgGenerator\n
Unfortunately QSvgRenderer hides to much information about
its nodes in internal APIs, that are necessary for proper
layout calculations. Also it is derived from QObject and
can't be copied like QImage/QPixmap.
QwtGraphic maps all scalable drawing primitives to a QPainterPath
and stores them together with the painter state changes
( pen, brush, transformation ... ) in a list of QwtPaintCommands.
For being a complete QPaintDevice it also stores pixmaps or images,
what is somehow against the idea of the class, because these objects
can't be scaled without a loss in quality.
The main issue about scaling a QwtGraphic object are the pens used for
drawing the outlines of the painter paths. While non cosmetic pens
( QPen::isCosmetic() ) are scaled with the same ratio as the path,
cosmetic pens have a fixed width. A graphic might have paths with
different pens - cosmetic and non-cosmetic.
QwtGraphic caches 2 different rectangles:
- control point rectangle\n
The control point rectangle is the bounding rectangle of all
control point rectangles of the painter paths, or the target
rectangle of the pixmaps/images.
- bounding rectangle\n
The bounding rectangle extends the control point rectangle by
what is needed for rendering the outline with an unscaled pen.
Because the offset for drawing the outline depends on the shape
of the painter path ( the peak of a triangle is different than the flat side )
scaling with a fixed aspect ratio always needs to be calculated from the
control point rectangle.
\sa QwtPainterCommand
*/
class QWT_EXPORT QwtGraphic: public QwtNullPaintDevice
{
public:
/*!
Hint how to render a graphic
\sa setRenderHint(), testRenderHint()
*/
enum RenderHint
{
/*!
When rendering a QwtGraphic a specific scaling between
the controlPointRect() and the coordinates of the target rectangle
is set up internally in render().
When RenderPensUnscaled is set this specific scaling is applied
for the control points only, but not for the pens.
All other painter transformations ( set up by application code )
are supposed to work like usual.
\sa render();
*/
RenderPensUnscaled = 0x1
};
/*!
\brief Render hints
The default setting is to disable all hints
*/
typedef QFlags<RenderHint> RenderHints;
QwtGraphic();
QwtGraphic( const QwtGraphic & );
virtual ~QwtGraphic();
QwtGraphic& operator=( const QwtGraphic & );
void reset();
bool isNull() const;
bool isEmpty() const;
void render( QPainter * ) const;
void render( QPainter *, const QSizeF &,
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
void render( QPainter *, const QRectF &,
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
void render( QPainter *, const QPointF &,
Qt::Alignment = Qt::AlignTop | Qt::AlignLeft ) const;
QPixmap toPixmap() const;
QPixmap toPixmap( const QSize &,
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
QImage toImage() const;
QImage toImage( const QSize &,
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
QRectF scaledBoundingRect( double sx, double sy ) const;
QRectF boundingRect() const;
QRectF controlPointRect() const;
const QVector< QwtPainterCommand > &commands() const;
void setCommands( QVector< QwtPainterCommand > & );
void setDefaultSize( const QSizeF & );
QSizeF defaultSize() const;
void setRenderHint( RenderHint, bool on = true );
bool testRenderHint( RenderHint ) const;
protected:
virtual QSize sizeMetrics() const;
virtual void drawPath( const QPainterPath & );
virtual void drawPixmap( const QRectF &,
const QPixmap &, const QRectF & );
virtual void drawImage( const QRectF &,
const QImage &, const QRectF &, Qt::ImageConversionFlags );
virtual void updateState( const QPaintEngineState &state );
private:
void updateBoundingRect( const QRectF & );
void updateControlPointRect( const QRectF & );
class PathInfo;
class PrivateData;
PrivateData *d_data;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtGraphic::RenderHints )
Q_DECLARE_METATYPE( QwtGraphic )
#endif

View File

@@ -0,0 +1,354 @@
/* -*- 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_interval.h"
#include "qwt_math.h"
#include <qalgorithms.h>
/*!
\brief Normalize the limits of the interval
If maxValue() < minValue() the limits will be inverted.
\return Normalized interval
\sa isValid(), inverted()
*/
QwtInterval QwtInterval::normalized() const
{
if ( d_minValue > d_maxValue )
{
return inverted();
}
if ( d_minValue == d_maxValue && d_borderFlags == ExcludeMinimum )
{
return inverted();
}
return *this;
}
/*!
Invert the limits of the interval
\return Inverted interval
\sa normalized()
*/
QwtInterval QwtInterval::inverted() const
{
BorderFlags borderFlags = IncludeBorders;
if ( d_borderFlags & ExcludeMinimum )
borderFlags |= ExcludeMaximum;
if ( d_borderFlags & ExcludeMaximum )
borderFlags |= ExcludeMinimum;
return QwtInterval( d_maxValue, d_minValue, borderFlags );
}
/*!
Test if a value is inside an interval
\param value Value
\return true, if value >= minValue() && value <= maxValue()
*/
bool QwtInterval::contains( double value ) const
{
if ( !isValid() )
return false;
if ( value < d_minValue || value > d_maxValue )
return false;
if ( value == d_minValue && d_borderFlags & ExcludeMinimum )
return false;
if ( value == d_maxValue && d_borderFlags & ExcludeMaximum )
return false;
return true;
}
//! Unite 2 intervals
QwtInterval QwtInterval::unite( const QwtInterval &other ) const
{
/*
If one of the intervals is invalid return the other one.
If both are invalid return an invalid default interval
*/
if ( !isValid() )
{
if ( !other.isValid() )
return QwtInterval();
else
return other;
}
if ( !other.isValid() )
return *this;
QwtInterval united;
BorderFlags flags = IncludeBorders;
// minimum
if ( d_minValue < other.minValue() )
{
united.setMinValue( d_minValue );
flags &= d_borderFlags & ExcludeMinimum;
}
else if ( other.minValue() < d_minValue )
{
united.setMinValue( other.minValue() );
flags &= other.borderFlags() & ExcludeMinimum;
}
else // d_minValue == other.minValue()
{
united.setMinValue( d_minValue );
flags &= ( d_borderFlags & other.borderFlags() ) & ExcludeMinimum;
}
// maximum
if ( d_maxValue > other.maxValue() )
{
united.setMaxValue( d_maxValue );
flags &= d_borderFlags & ExcludeMaximum;
}
else if ( other.maxValue() > d_maxValue )
{
united.setMaxValue( other.maxValue() );
flags &= other.borderFlags() & ExcludeMaximum;
}
else // d_maxValue == other.maxValue() )
{
united.setMaxValue( d_maxValue );
flags &= d_borderFlags & other.borderFlags() & ExcludeMaximum;
}
united.setBorderFlags( flags );
return united;
}
/*!
\brief Intersect 2 intervals
\param other Interval to be intersect with
\return Intersection
*/
QwtInterval QwtInterval::intersect( const QwtInterval &other ) const
{
if ( !other.isValid() || !isValid() )
return QwtInterval();
QwtInterval i1 = *this;
QwtInterval i2 = other;
// swap i1/i2, so that the minimum of i1
// is smaller then the minimum of i2
if ( i1.minValue() > i2.minValue() )
{
qSwap( i1, i2 );
}
else if ( i1.minValue() == i2.minValue() )
{
if ( i1.borderFlags() & ExcludeMinimum )
qSwap( i1, i2 );
}
if ( i1.maxValue() < i2.minValue() )
{
return QwtInterval();
}
if ( i1.maxValue() == i2.minValue() )
{
if ( i1.borderFlags() & ExcludeMaximum ||
i2.borderFlags() & ExcludeMinimum )
{
return QwtInterval();
}
}
QwtInterval intersected;
BorderFlags flags = IncludeBorders;
intersected.setMinValue( i2.minValue() );
flags |= i2.borderFlags() & ExcludeMinimum;
if ( i1.maxValue() < i2.maxValue() )
{
intersected.setMaxValue( i1.maxValue() );
flags |= i1.borderFlags() & ExcludeMaximum;
}
else if ( i2.maxValue() < i1.maxValue() )
{
intersected.setMaxValue( i2.maxValue() );
flags |= i2.borderFlags() & ExcludeMaximum;
}
else // i1.maxValue() == i2.maxValue()
{
intersected.setMaxValue( i1.maxValue() );
flags |= i1.borderFlags() & i2.borderFlags() & ExcludeMaximum;
}
intersected.setBorderFlags( flags );
return intersected;
}
/*!
\brief Unite this interval with the given interval.
\param other Interval to be united with
\return This interval
*/
QwtInterval& QwtInterval::operator|=( const QwtInterval &other )
{
*this = *this | other;
return *this;
}
/*!
\brief Intersect this interval with the given interval.
\param other Interval to be intersected with
\return This interval
*/
QwtInterval& QwtInterval::operator&=( const QwtInterval &other )
{
*this = *this & other;
return *this;
}
/*!
\brief Test if two intervals overlap
\param other Interval
\return True, when the intervals are intersecting
*/
bool QwtInterval::intersects( const QwtInterval &other ) const
{
if ( !isValid() || !other.isValid() )
return false;
QwtInterval i1 = *this;
QwtInterval i2 = other;
// swap i1/i2, so that the minimum of i1
// is smaller then the minimum of i2
if ( i1.minValue() > i2.minValue() )
{
qSwap( i1, i2 );
}
else if ( i1.minValue() == i2.minValue() &&
i1.borderFlags() & ExcludeMinimum )
{
qSwap( i1, i2 );
}
if ( i1.maxValue() > i2.minValue() )
{
return true;
}
if ( i1.maxValue() == i2.minValue() )
{
return !( ( i1.borderFlags() & ExcludeMaximum ) ||
( i2.borderFlags() & ExcludeMinimum ) );
}
return false;
}
/*!
Adjust the limit that is closer to value, so that value becomes
the center of the interval.
\param value Center
\return Interval with value as center
*/
QwtInterval QwtInterval::symmetrize( double value ) const
{
if ( !isValid() )
return *this;
const double delta =
qMax( qAbs( value - d_maxValue ), qAbs( value - d_minValue ) );
return QwtInterval( value - delta, value + delta );
}
/*!
Limit the interval, keeping the border modes
\param lowerBound Lower limit
\param upperBound Upper limit
\return Limited interval
*/
QwtInterval QwtInterval::limited( double lowerBound, double upperBound ) const
{
if ( !isValid() || lowerBound > upperBound )
return QwtInterval();
double minValue = qMax( d_minValue, lowerBound );
minValue = qMin( minValue, upperBound );
double maxValue = qMax( d_maxValue, lowerBound );
maxValue = qMin( maxValue, upperBound );
return QwtInterval( minValue, maxValue, d_borderFlags );
}
/*!
\brief Extend the interval
If value is below minValue(), value becomes the lower limit.
If value is above maxValue(), value becomes the upper limit.
extend() has no effect for invalid intervals
\param value Value
\return extended interval
\sa isValid()
*/
QwtInterval QwtInterval::extend( double value ) const
{
if ( !isValid() )
return *this;
return QwtInterval( qMin( value, d_minValue ),
qMax( value, d_maxValue ), d_borderFlags );
}
/*!
Extend an interval
\param value Value
\return Reference of the extended interval
\sa extend()
*/
QwtInterval& QwtInterval::operator|=( double value )
{
*this = *this | value;
return *this;
}
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<( QDebug debug, const QwtInterval &interval )
{
const int flags = interval.borderFlags();
debug.nospace() << "QwtInterval("
<< ( ( flags & QwtInterval::ExcludeMinimum ) ? "]" : "[" )
<< interval.minValue() << "," << interval.maxValue()
<< ( ( flags & QwtInterval::ExcludeMaximum ) ? "[" : "]" )
<< ")";
return debug.space();
}
#endif

View File

@@ -0,0 +1,320 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_INTERVAL_H
#define QWT_INTERVAL_H
#include "qwt_global.h"
#include <qmetatype.h>
#ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h>
#endif
/*!
\brief A class representing an interval
The interval is represented by 2 doubles, the lower and the upper limit.
*/
class QWT_EXPORT QwtInterval
{
public:
/*!
Flag indicating if a border is included or excluded
\sa setBorderFlags(), borderFlags()
*/
enum BorderFlag
{
//! Min/Max values are inside the interval
IncludeBorders = 0x00,
//! Min value is not included in the interval
ExcludeMinimum = 0x01,
//! Max value is not included in the interval
ExcludeMaximum = 0x02,
//! Min/Max values are not included in the interval
ExcludeBorders = ExcludeMinimum | ExcludeMaximum
};
//! Border flags
typedef QFlags<BorderFlag> BorderFlags;
QwtInterval();
QwtInterval( double minValue, double maxValue,
BorderFlags = IncludeBorders );
void setInterval( double minValue, double maxValue,
BorderFlags = IncludeBorders );
QwtInterval normalized() const;
QwtInterval inverted() const;
QwtInterval limited( double minValue, double maxValue ) const;
bool operator==( const QwtInterval & ) const;
bool operator!=( const QwtInterval & ) const;
void setBorderFlags( BorderFlags );
BorderFlags borderFlags() const;
double minValue() const;
double maxValue() const;
double width() const;
void setMinValue( double );
void setMaxValue( double );
bool contains( double value ) const;
bool intersects( const QwtInterval & ) const;
QwtInterval intersect( const QwtInterval & ) const;
QwtInterval unite( const QwtInterval & ) const;
QwtInterval operator|( const QwtInterval & ) const;
QwtInterval operator&( const QwtInterval & ) const;
QwtInterval &operator|=( const QwtInterval & );
QwtInterval &operator&=( const QwtInterval & );
QwtInterval extend( double value ) const;
QwtInterval operator|( double ) const;
QwtInterval &operator|=( double );
bool isValid() const;
bool isNull() const;
void invalidate();
QwtInterval symmetrize( double value ) const;
private:
double d_minValue;
double d_maxValue;
BorderFlags d_borderFlags;
};
Q_DECLARE_TYPEINFO(QwtInterval, Q_MOVABLE_TYPE);
/*!
\brief Default Constructor
Creates an invalid interval [0.0, -1.0]
\sa setInterval(), isValid()
*/
inline QwtInterval::QwtInterval():
d_minValue( 0.0 ),
d_maxValue( -1.0 ),
d_borderFlags( IncludeBorders )
{
}
/*!
Constructor
Build an interval with from min/max values
\param minValue Minimum value
\param maxValue Maximum value
\param borderFlags Include/Exclude borders
*/
inline QwtInterval::QwtInterval(
double minValue, double maxValue, BorderFlags borderFlags ):
d_minValue( minValue ),
d_maxValue( maxValue ),
d_borderFlags( borderFlags )
{
}
/*!
Assign the limits of the interval
\param minValue Minimum value
\param maxValue Maximum value
\param borderFlags Include/Exclude borders
*/
inline void QwtInterval::setInterval(
double minValue, double maxValue, BorderFlags borderFlags )
{
d_minValue = minValue;
d_maxValue = maxValue;
d_borderFlags = borderFlags;
}
/*!
Change the border flags
\param borderFlags Or'd BorderMode flags
\sa borderFlags()
*/
inline void QwtInterval::setBorderFlags( BorderFlags borderFlags )
{
d_borderFlags = borderFlags;
}
/*!
\return Border flags
\sa setBorderFlags()
*/
inline QwtInterval::BorderFlags QwtInterval::borderFlags() const
{
return d_borderFlags;
}
/*!
Assign the lower limit of the interval
\param minValue Minimum value
*/
inline void QwtInterval::setMinValue( double minValue )
{
d_minValue = minValue;
}
/*!
Assign the upper limit of the interval
\param maxValue Maximum value
*/
inline void QwtInterval::setMaxValue( double maxValue )
{
d_maxValue = maxValue;
}
//! \return Lower limit of the interval
inline double QwtInterval::minValue() const
{
return d_minValue;
}
//! \return Upper limit of the interval
inline double QwtInterval::maxValue() const
{
return d_maxValue;
}
/*!
A interval is valid when minValue() <= maxValue().
In case of QwtInterval::ExcludeBorders it is true
when minValue() < maxValue()
\return True, when the interval is valid
*/
inline bool QwtInterval::isValid() const
{
if ( ( d_borderFlags & ExcludeBorders ) == 0 )
return d_minValue <= d_maxValue;
else
return d_minValue < d_maxValue;
}
/*!
\brief Return the width of an interval
The width of invalid intervals is 0.0, otherwise the result is
maxValue() - minValue().
\return Interval width
\sa isValid()
*/
inline double QwtInterval::width() const
{
return isValid() ? ( d_maxValue - d_minValue ) : 0.0;
}
/*!
\brief Intersection of two intervals
\param other Interval to intersect with
\return Intersection of this and other
\sa intersect()
*/
inline QwtInterval QwtInterval::operator&(
const QwtInterval &other ) const
{
return intersect( other );
}
/*!
Union of two intervals
\param other Interval to unite with
\return Union of this and other
\sa unite()
*/
inline QwtInterval QwtInterval::operator|(
const QwtInterval &other ) const
{
return unite( other );
}
/*!
\brief Compare two intervals
\param other Interval to compare with
\return True, when this and other are equal
*/
inline bool QwtInterval::operator==( const QwtInterval &other ) const
{
return ( d_minValue == other.d_minValue ) &&
( d_maxValue == other.d_maxValue ) &&
( d_borderFlags == other.d_borderFlags );
}
/*!
\brief Compare two intervals
\param other Interval to compare with
\return True, when this and other are not equal
*/
inline bool QwtInterval::operator!=( const QwtInterval &other ) const
{
return ( !( *this == other ) );
}
/*!
Extend an interval
\param value Value
\return Extended interval
\sa extend()
*/
inline QwtInterval QwtInterval::operator|( double value ) const
{
return extend( value );
}
//! \return true, if isValid() && (minValue() >= maxValue())
inline bool QwtInterval::isNull() const
{
return isValid() && d_minValue >= d_maxValue;
}
/*!
Invalidate the interval
The limits are set to interval [0.0, -1.0]
\sa isValid()
*/
inline void QwtInterval::invalidate()
{
d_minValue = 0.0;
d_maxValue = -1.0;
}
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtInterval::BorderFlags )
Q_DECLARE_METATYPE( QwtInterval )
#ifndef QT_NO_DEBUG_STREAM
QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & );
#endif
#endif

View File

@@ -0,0 +1,319 @@
/* -*- 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_interval_symbol.h"
#include "qwt_painter.h"
#include "qwt_math.h"
#include <qpainter.h>
#if QT_VERSION < 0x040601
#define qAtan2(y, x) ::atan2(y, x)
#define qFastSin(x) qSin(x)
#define qFastCos(x) qCos(x)
#endif
class QwtIntervalSymbol::PrivateData
{
public:
PrivateData():
style( QwtIntervalSymbol::NoSymbol ),
width( 6 )
{
}
bool operator==( const PrivateData &other ) const
{
return ( style == other.style )
&& ( width == other.width )
&& ( brush == other.brush )
&& ( pen == other.pen );
}
QwtIntervalSymbol::Style style;
int width;
QPen pen;
QBrush brush;
};
/*!
Constructor
\param style Style of the symbol
\sa setStyle(), style(), Style
*/
QwtIntervalSymbol::QwtIntervalSymbol( Style style )
{
d_data = new PrivateData();
d_data->style = style;
}
//! Copy constructor
QwtIntervalSymbol::QwtIntervalSymbol( const QwtIntervalSymbol &other )
{
d_data = new PrivateData();
*d_data = *other.d_data;
}
//! Destructor
QwtIntervalSymbol::~QwtIntervalSymbol()
{
delete d_data;
}
//! \brief Assignment operator
QwtIntervalSymbol &QwtIntervalSymbol::operator=(
const QwtIntervalSymbol &other )
{
*d_data = *other.d_data;
return *this;
}
//! \brief Compare two symbols
bool QwtIntervalSymbol::operator==(
const QwtIntervalSymbol &other ) const
{
return *d_data == *other.d_data;
}
//! \brief Compare two symbols
bool QwtIntervalSymbol::operator!=(
const QwtIntervalSymbol &other ) const
{
return !( *d_data == *other.d_data );
}
/*!
Specify the symbol style
\param style Style
\sa style(), Style
*/
void QwtIntervalSymbol::setStyle( Style style )
{
d_data->style = style;
}
/*!
\return Current symbol style
\sa setStyle()
*/
QwtIntervalSymbol::Style QwtIntervalSymbol::style() const
{
return d_data->style;
}
/*!
Specify the width of the symbol
It is used depending on the style.
\param width Width
\sa width(), setStyle()
*/
void QwtIntervalSymbol::setWidth( int width )
{
d_data->width = width;
}
/*!
\return Width of the symbol.
\sa setWidth(), setStyle()
*/
int QwtIntervalSymbol::width() const
{
return d_data->width;
}
/*!
\brief Assign a brush
The brush is used for the Box style.
\param brush Brush
\sa brush()
*/
void QwtIntervalSymbol::setBrush( const QBrush &brush )
{
d_data->brush = brush;
}
/*!
\return Brush
\sa setBrush()
*/
const QBrush& QwtIntervalSymbol::brush() const
{
return d_data->brush;
}
/*!
Build and assign a pen
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtIntervalSymbol::setPen( const QColor &color,
qreal width, Qt::PenStyle style )
{
setPen( QPen( color, width, style ) );
}
/*!
Assign a pen
\param pen Pen
\sa pen(), setBrush()
*/
void QwtIntervalSymbol::setPen( const QPen &pen )
{
d_data->pen = pen;
}
/*!
\return Pen
\sa setPen(), brush()
*/
const QPen& QwtIntervalSymbol::pen() const
{
return d_data->pen;
}
/*!
Draw a symbol depending on its style
\param painter Painter
\param orientation Orientation
\param from Start point of the interval in target device coordinates
\param to End point of the interval in target device coordinates
\sa setStyle()
*/
void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation,
const QPointF &from, const QPointF &to ) const
{
const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) );
QPointF p1 = from;
QPointF p2 = to;
if ( QwtPainter::roundingAlignment( painter ) )
{
p1 = p1.toPoint();
p2 = p2.toPoint();
}
switch ( d_data->style )
{
case QwtIntervalSymbol::Bar:
{
QwtPainter::drawLine( painter, p1, p2 );
if ( d_data->width > pw )
{
if ( ( orientation == Qt::Horizontal )
&& ( p1.y() == p2.y() ) )
{
const double sw = d_data->width;
const double y = p1.y() - sw / 2;
QwtPainter::drawLine( painter,
p1.x(), y, p1.x(), y + sw );
QwtPainter::drawLine( painter,
p2.x(), y, p2.x(), y + sw );
}
else if ( ( orientation == Qt::Vertical )
&& ( p1.x() == p2.x() ) )
{
const double sw = d_data->width;
const double x = p1.x() - sw / 2;
QwtPainter::drawLine( painter,
x, p1.y(), x + sw, p1.y() );
QwtPainter::drawLine( painter,
x, p2.y(), x + sw, p2.y() );
}
else
{
const double sw = d_data->width;
const double dx = p2.x() - p1.x();
const double dy = p2.y() - p1.y();
const double angle = qAtan2( dy, dx ) + M_PI_2;
double dw2 = sw / 2.0;
const double cx = qFastCos( angle ) * dw2;
const double sy = qFastSin( angle ) * dw2;
QwtPainter::drawLine( painter,
p1.x() - cx, p1.y() - sy,
p1.x() + cx, p1.y() + sy );
QwtPainter::drawLine( painter,
p2.x() - cx, p2.y() - sy,
p2.x() + cx, p2.y() + sy );
}
}
break;
}
case QwtIntervalSymbol::Box:
{
if ( d_data->width <= pw )
{
QwtPainter::drawLine( painter, p1, p2 );
}
else
{
if ( ( orientation == Qt::Horizontal )
&& ( p1.y() == p2.y() ) )
{
const double sw = d_data->width;
const double y = p1.y() - d_data->width / 2;
QwtPainter::drawRect( painter,
p1.x(), y, p2.x() - p1.x(), sw );
}
else if ( ( orientation == Qt::Vertical )
&& ( p1.x() == p2.x() ) )
{
const double sw = d_data->width;
const double x = p1.x() - d_data->width / 2;
QwtPainter::drawRect( painter,
x, p1.y(), sw, p2.y() - p1.y() );
}
else
{
const double sw = d_data->width;
const double dx = p2.x() - p1.x();
const double dy = p2.y() - p1.y();
const double angle = qAtan2( dy, dx ) + M_PI_2;
double dw2 = sw / 2.0;
const double cx = qFastCos( angle ) * dw2;
const double sy = qFastSin( angle ) * dw2;
QPolygonF polygon;
polygon += QPointF( p1.x() - cx, p1.y() - sy );
polygon += QPointF( p1.x() + cx, p1.y() + sy );
polygon += QPointF( p2.x() + cx, p2.y() + sy );
polygon += QPointF( p2.x() - cx, p2.y() - sy );
QwtPainter::drawPolygon( painter, polygon );
}
}
break;
}
default:;
}
}

View File

@@ -0,0 +1,87 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_INTERVAL_SYMBOL_H
#define QWT_INTERVAL_SYMBOL_H
#include "qwt_global.h"
#include <qpen.h>
#include <qsize.h>
class QPainter;
class QRect;
class QPointF;
/*!
\brief A drawing primitive for displaying an interval like an error bar
\sa QwtPlotIntervalCurve
*/
class QWT_EXPORT QwtIntervalSymbol
{
public:
//! Symbol style
enum Style
{
//! No Style. The symbol cannot be drawn.
NoSymbol = -1,
/*!
The symbol displays a line with caps at the beginning/end.
The size of the caps depends on the symbol width().
*/
Bar,
/*!
The symbol displays a plain rectangle using pen() and brush().
The size of the rectangle depends on the translated interval and
the width(),
*/
Box,
/*!
Styles >= UserSymbol are reserved for derived
classes of QwtIntervalSymbol that overload draw() with
additional application specific symbol types.
*/
UserSymbol = 1000
};
public:
QwtIntervalSymbol( Style = NoSymbol );
QwtIntervalSymbol( const QwtIntervalSymbol & );
virtual ~QwtIntervalSymbol();
QwtIntervalSymbol &operator=( const QwtIntervalSymbol & );
bool operator==( const QwtIntervalSymbol & ) const;
bool operator!=( const QwtIntervalSymbol & ) const;
void setWidth( int );
int width() const;
void setBrush( const QBrush& b );
const QBrush& brush() const;
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setPen( const QPen & );
const QPen& pen() const;
void setStyle( Style );
Style style() const;
virtual void draw( QPainter *, Qt::Orientation,
const QPointF& from, const QPointF& to ) const;
private:
class PrivateData;
PrivateData* d_data;
};
#endif

View File

@@ -0,0 +1,855 @@
/* -*- 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_knob.h"
#include "qwt_round_scale_draw.h"
#include "qwt_math.h"
#include "qwt_painter.h"
#include "qwt_scale_map.h"
#include <qpainter.h>
#include <qpalette.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qevent.h>
#include <qmath.h>
#include <qapplication.h>
#if QT_VERSION < 0x040601
#define qAtan2(y, x) ::atan2(y, x)
#define qFabs(x) ::fabs(x)
#define qFastCos(x) qCos(x)
#define qFastSin(x) qSin(x)
#endif
static QSize qwtKnobSizeHint( const QwtKnob *knob, int min )
{
int knobWidth = knob->knobWidth();
if ( knobWidth <= 0 )
knobWidth = qMax( 3 * knob->markerSize(), min );
// Add the scale radial thickness to the knobWidth
const int extent = qCeil( knob->scaleDraw()->extent( knob->font() ) );
const int d = 2 * ( extent + 4 ) + knobWidth;
int left, right, top, bottom;
knob->getContentsMargins( &left, &top, &right, &bottom );
return QSize( d + left + right, d + top + bottom );
}
static inline double qwtToScaleAngle( double angle )
{
// the map is counter clockwise with the origin
// at 90° using angles from -180° -> 180°
double a = 90.0 - angle;
if ( a <= -180.0 )
a += 360.0;
else if ( a >= 180.0 )
a -= 360.0;
return a;
}
static double qwtToDegrees( double value )
{
return qwtNormalizeDegrees( 90.0 - value );
}
class QwtKnob::PrivateData
{
public:
PrivateData():
knobStyle( QwtKnob::Raised ),
markerStyle( QwtKnob::Notch ),
borderWidth( 2 ),
borderDist( 4 ),
scaleDist( 4 ),
maxScaleTicks( 11 ),
knobWidth( 0 ),
alignment( Qt::AlignCenter ),
markerSize( 8 ),
totalAngle( 270.0 ),
mouseOffset( 0.0 )
{
}
QwtKnob::KnobStyle knobStyle;
QwtKnob::MarkerStyle markerStyle;
int borderWidth;
int borderDist;
int scaleDist;
int maxScaleTicks;
int knobWidth;
Qt::Alignment alignment;
int markerSize;
double totalAngle;
double mouseOffset;
};
/*!
\brief Constructor
Construct a knob with an angle of 270°. The style is
QwtKnob::Raised and the marker style is QwtKnob::Notch.
The width of the knob is set to 50 pixels.
\param parent Parent widget
\sa setTotalAngle()
*/
QwtKnob::QwtKnob( QWidget* parent ):
QwtAbstractSlider( parent )
{
d_data = new PrivateData;
setScaleDraw( new QwtRoundScaleDraw() );
setTotalAngle( 270.0 );
setScale( 0.0, 10.0 );
setValue( 0.0 );
setSizePolicy( QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding );
}
//! Destructor
QwtKnob::~QwtKnob()
{
delete d_data;
}
/*!
\brief Set the knob type
\param knobStyle Knob type
\sa knobStyle(), setBorderWidth()
*/
void QwtKnob::setKnobStyle( KnobStyle knobStyle )
{
if ( d_data->knobStyle != knobStyle )
{
d_data->knobStyle = knobStyle;
update();
}
}
/*!
\return Marker type of the knob
\sa setKnobStyle(), setBorderWidth()
*/
QwtKnob::KnobStyle QwtKnob::knobStyle() const
{
return d_data->knobStyle;
}
/*!
\brief Set the marker type of the knob
\param markerStyle Marker type
\sa markerStyle(), setMarkerSize()
*/
void QwtKnob::setMarkerStyle( MarkerStyle markerStyle )
{
if ( d_data->markerStyle != markerStyle )
{
d_data->markerStyle = markerStyle;
update();
}
}
/*!
\return Marker type of the knob
\sa setMarkerStyle(), setMarkerSize()
*/
QwtKnob::MarkerStyle QwtKnob::markerStyle() const
{
return d_data->markerStyle;
}
/*!
\brief Set the total angle by which the knob can be turned
\param angle Angle in degrees.
The angle has to be between [10, 360] degrees. Angles above
360 ( so that the knob can be turned several times around its axis )
have to be set using setNumTurns().
The default angle is 270 degrees.
\sa totalAngle(), setNumTurns()
*/
void QwtKnob::setTotalAngle ( double angle )
{
angle = qBound( 10.0, angle, 360.0 );
if ( angle != d_data->totalAngle )
{
d_data->totalAngle = angle;
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
0.5 * d_data->totalAngle );
updateGeometry();
update();
}
}
/*!
\return the total angle
\sa setTotalAngle(), setNumTurns(), numTurns()
*/
double QwtKnob::totalAngle() const
{
return d_data->totalAngle;
}
/*!
\brief Set the number of turns
When numTurns > 1 the knob can be turned several times around its axis
- otherwise the total angle is floored to 360°.
\sa numTurns(), totalAngle(), setTotalAngle()
*/
void QwtKnob::setNumTurns( int numTurns )
{
numTurns = qMax( numTurns, 1 );
if ( numTurns == 1 && d_data->totalAngle <= 360.0 )
return;
const double angle = numTurns * 360.0;
if ( angle != d_data->totalAngle )
{
d_data->totalAngle = angle;
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
0.5 * d_data->totalAngle );
updateGeometry();
update();
}
}
/*!
\return Number of turns.
When the total angle is below 360° numTurns() is ceiled to 1.
\sa setNumTurns(), setTotalAngle(), totalAngle()
*/
int QwtKnob::numTurns() const
{
return qCeil( d_data->totalAngle / 360.0 );
}
/*!
Change the scale draw of the knob
For changing the labels of the scales, it
is necessary to derive from QwtRoundScaleDraw and
overload QwtRoundScaleDraw::label().
\sa scaleDraw()
*/
void QwtKnob::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
{
setAbstractScaleDraw( scaleDraw );
setTotalAngle( d_data->totalAngle );
updateGeometry();
update();
}
/*!
\return the scale draw of the knob
\sa setScaleDraw()
*/
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
{
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
}
/*!
\return the scale draw of the knob
\sa setScaleDraw()
*/
QwtRoundScaleDraw *QwtKnob::scaleDraw()
{
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
}
/*!
Calculate the bounding rectangle of the knob without the scale
\return Bounding rectangle of the knob
\sa knobWidth(), alignment(), QWidget::contentsRect()
*/
QRect QwtKnob::knobRect() const
{
const QRect cr = contentsRect();
const int extent = qCeil( scaleDraw()->extent( font() ) );
const int d = extent + d_data->scaleDist;
int w = d_data->knobWidth;
if ( w <= 0 )
{
const int dim = qMin( cr.width(), cr.height() );
w = dim - 2 * ( d );
w = qMax( 0, w );
}
QRect r( 0, 0, w, w );
if ( d_data->alignment & Qt::AlignLeft )
{
r.moveLeft( cr.left() + d );
}
else if ( d_data->alignment & Qt::AlignRight )
{
r.moveRight( cr.right() - d );
}
else
{
r.moveCenter( QPoint( cr.center().x(), r.center().y() ) );
}
if ( d_data->alignment & Qt::AlignTop )
{
r.moveTop( cr.top() + d );
}
else if ( d_data->alignment & Qt::AlignBottom )
{
r.moveBottom( cr.bottom() - d );
}
else
{
r.moveCenter( QPoint( r.center().x(), cr.center().y() ) );
}
return r;
}
/*!
\brief Determine what to do when the user presses a mouse button.
\param pos Mouse position
\retval True, when pos is inside the circle of the knob.
\sa scrolledTo()
*/
bool QwtKnob::isScrollPosition( const QPoint &pos ) const
{
const QRect kr = knobRect();
const QRegion region( kr, QRegion::Ellipse );
if ( region.contains( pos ) && ( pos != kr.center() ) )
{
const double angle = QLineF( kr.center(), pos ).angle();
const double valueAngle = qwtToDegrees( scaleMap().transform( value() ) );
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
return true;
}
return false;
}
/*!
\brief Determine the value for a new position of the mouse
\param pos Mouse position
\return Value for the mouse position
\sa isScrollPosition()
*/
double QwtKnob::scrolledTo( const QPoint &pos ) const
{
double angle = QLineF( rect().center(), pos ).angle();
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
if ( scaleMap().pDist() > 360.0 )
{
angle = qwtToDegrees( angle );
const double v = scaleMap().transform( value() );
int numTurns = qFloor( ( v - scaleMap().p1() ) / 360.0 );
double valueAngle = qwtNormalizeDegrees( v );
if ( qAbs( valueAngle - angle ) > 180.0 )
{
numTurns += ( angle > valueAngle ) ? -1 : 1;
}
angle += scaleMap().p1() + numTurns * 360.0;
if ( !wrapping() )
{
const double boundedAngle =
qBound( scaleMap().p1(), angle, scaleMap().p2() );
d_data->mouseOffset += ( boundedAngle - angle );
angle = boundedAngle;
}
}
else
{
angle = qwtToScaleAngle( angle );
double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() );
if ( !wrapping() )
{
const double currentAngle = scaleMap().transform( value() );
if ( ( currentAngle > 90.0 ) && ( boundedAngle < -90.0 ) )
boundedAngle = scaleMap().p2();
else if ( ( currentAngle < -90.0 ) && ( boundedAngle > 90.0 ) )
boundedAngle = scaleMap().p1();
d_data->mouseOffset += ( boundedAngle - angle );
}
angle = boundedAngle;
}
return scaleMap().invTransform( angle );
}
/*!
Handle QEvent::StyleChange and QEvent::FontChange;
\param event Change event
*/
void QwtKnob::changeEvent( QEvent *event )
{
switch( event->type() )
{
case QEvent::StyleChange:
case QEvent::FontChange:
{
updateGeometry();
update();
break;
}
default:
break;
}
}
/*!
Repaint the knob
\param event Paint event
*/
void QwtKnob::paintEvent( QPaintEvent *event )
{
const QRectF knobRect = this->knobRect();
QPainter painter( this );
painter.setClipRegion( event->region() );
QStyleOption opt;
opt.init(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
painter.setRenderHint( QPainter::Antialiasing, true );
if ( !knobRect.contains( event->region().boundingRect() ) )
{
scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist );
scaleDraw()->moveCenter( knobRect.center() );
scaleDraw()->draw( &painter, palette() );
}
drawKnob( &painter, knobRect );
drawMarker( &painter, knobRect,
qwtNormalizeDegrees( scaleMap().transform( value() ) ) );
painter.setRenderHint( QPainter::Antialiasing, false );
if ( hasFocus() )
drawFocusIndicator( &painter );
}
/*!
\brief Draw the knob
\param painter painter
\param knobRect Bounding rectangle of the knob (without scale)
*/
void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const
{
double dim = qMin( knobRect.width(), knobRect.height() );
dim -= d_data->borderWidth * 0.5;
QRectF aRect( 0, 0, dim, dim );
aRect.moveCenter( knobRect.center() );
QPen pen( Qt::NoPen );
if ( d_data->borderWidth > 0 )
{
QColor c1 = palette().color( QPalette::Light );
QColor c2 = palette().color( QPalette::Dark );
QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 0.3, c1 );
gradient.setColorAt( 0.7, c2 );
gradient.setColorAt( 1.0, c2 );
pen = QPen( gradient, d_data->borderWidth );
}
QBrush brush;
switch( d_data->knobStyle )
{
case QwtKnob::Raised:
{
double off = 0.3 * knobRect.width();
QRadialGradient gradient( knobRect.center(),
knobRect.width(), knobRect.topLeft() + QPointF( off, off ) );
gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) );
gradient.setColorAt( 1.0, palette().color( QPalette::Button ) );
brush = QBrush( gradient );
break;
}
case QwtKnob::Styled:
{
QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3,
knobRect.center().y() - knobRect.height() / 2,
knobRect.width() * 1.3,
knobRect.center().x(),
knobRect.center().y() - knobRect.height() / 2);
const QColor c = palette().color( QPalette::Button );
gradient.setColorAt(0, c.lighter(110));
gradient.setColorAt(qreal(0.5), c);
gradient.setColorAt(qreal(0.501), c.darker(102));
gradient.setColorAt(1, c.darker(115));
brush = QBrush( gradient );
break;
}
case QwtKnob::Sunken:
{
QLinearGradient gradient(
knobRect.topLeft(), knobRect.bottomRight() );
gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) );
gradient.setColorAt( 0.5, palette().color( QPalette::Button ) );
gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) );
brush = QBrush( gradient );
break;
}
case QwtKnob::Flat:
default:
brush = palette().brush( QPalette::Button );
}
painter->setPen( pen );
painter->setBrush( brush );
painter->drawEllipse( aRect );
}
/*!
\brief Draw the marker at the knob's front
\param painter Painter
\param rect Bounding rectangle of the knob without scale
\param angle Angle of the marker in degrees
( clockwise, 0 at the 12 o'clock position )
*/
void QwtKnob::drawMarker( QPainter *painter,
const QRectF &rect, double angle ) const
{
if ( d_data->markerStyle == NoMarker || !isValid() )
return;
const double radians = qwtRadians( angle );
const double sinA = -qFastSin( radians );
const double cosA = qFastCos( radians );
const double xm = rect.center().x();
const double ym = rect.center().y();
const double margin = 4.0;
double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
if ( radius < 1.0 )
radius = 1.0;
int markerSize = d_data->markerSize;
if ( markerSize <= 0 )
markerSize = qRound( 0.4 * radius );
switch ( d_data->markerStyle )
{
case Notch:
case Nub:
{
const double dotWidth =
qMin( double( markerSize ), radius);
const double dotCenterDist = radius - 0.5 * dotWidth;
if ( dotCenterDist > 0.0 )
{
const QPointF center( xm - sinA * dotCenterDist,
ym - cosA * dotCenterDist );
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
ellipse.moveCenter( center );
QColor c1 = palette().color( QPalette::Light );
QColor c2 = palette().color( QPalette::Mid );
if ( d_data->markerStyle == Notch )
qSwap( c1, c2 );
QLinearGradient gradient(
ellipse.topLeft(), ellipse.bottomRight() );
gradient.setColorAt( 0.0, c1 );
gradient.setColorAt( 1.0, c2 );
painter->setPen( Qt::NoPen );
painter->setBrush( gradient );
painter->drawEllipse( ellipse );
}
break;
}
case Dot:
{
const double dotWidth =
qMin( double( markerSize ), radius);
const double dotCenterDist = radius - 0.5 * dotWidth;
if ( dotCenterDist > 0.0 )
{
const QPointF center( xm - sinA * dotCenterDist,
ym - cosA * dotCenterDist );
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
ellipse.moveCenter( center );
painter->setPen( Qt::NoPen );
painter->setBrush( palette().color( QPalette::ButtonText ) );
painter->drawEllipse( ellipse );
}
break;
}
case Tick:
{
const double rb = qMax( radius - markerSize, 1.0 );
const double re = radius;
const QLineF line( xm - sinA * rb, ym - cosA * rb,
xm - sinA * re, ym - cosA * re );
QPen pen( palette().color( QPalette::ButtonText ), 0 );
pen.setCapStyle( Qt::FlatCap );
painter->setPen( pen );
painter->drawLine ( line );
break;
}
case Triangle:
{
const double rb = qMax( radius - markerSize, 1.0 );
const double re = radius;
painter->translate( rect.center() );
painter->rotate( angle - 90.0 );
QPolygonF polygon;
polygon += QPointF( re, 0.0 );
polygon += QPointF( rb, 0.5 * ( re - rb ) );
polygon += QPointF( rb, -0.5 * ( re - rb ) );
painter->setPen( Qt::NoPen );
painter->setBrush( palette().color( QPalette::ButtonText ) );
painter->drawPolygon( polygon );
painter->resetTransform();
break;
}
default:
break;
}
}
/*!
Draw the focus indicator
\param painter Painter
*/
void QwtKnob::drawFocusIndicator( QPainter *painter ) const
{
const QRect cr = contentsRect();
int w = d_data->knobWidth;
if ( w <= 0 )
{
w = qMin( cr.width(), cr.height() );
}
else
{
const int extent = qCeil( scaleDraw()->extent( font() ) );
w += 2 * ( extent + d_data->scaleDist );
}
QRect focusRect( 0, 0, w, w );
focusRect.moveCenter( cr.center() );
QwtPainter::drawFocusRect( painter, this, focusRect );
}
/*!
\brief Set the alignment of the knob
Similar to a QLabel::alignment() the flags decide how
to align the knob inside of contentsRect().
The default setting is Qt::AlignCenter
\param alignment Or'd alignment flags
\sa alignment(), setKnobWidth(), knobRect()
*/
void QwtKnob::setAlignment( Qt::Alignment alignment )
{
if ( d_data->alignment != alignment )
{
d_data->alignment = alignment;
update();
}
}
/*!
\return Alignment of the knob inside of contentsRect()
\sa setAlignment(), knobWidth(), knobRect()
*/
Qt::Alignment QwtKnob::alignment() const
{
return d_data->alignment;
}
/*!
\brief Change the knob's width.
Setting a fixed value for the diameter of the knob
is helpful for aligning several knobs in a row.
\param width New width
\sa knobWidth(), setAlignment()
\note Modifies the sizePolicy()
*/
void QwtKnob::setKnobWidth( int width )
{
width = qMax( width, 0 );
if ( width != d_data->knobWidth )
{
QSizePolicy::Policy policy;
if ( width > 0 )
policy = QSizePolicy::Minimum;
else
policy = QSizePolicy::MinimumExpanding;
setSizePolicy( policy, policy );
d_data->knobWidth = width;
updateGeometry();
update();
}
}
//! Return the width of the knob
int QwtKnob::knobWidth() const
{
return d_data->knobWidth;
}
/*!
\brief Set the knob's border width
\param borderWidth new border width
*/
void QwtKnob::setBorderWidth( int borderWidth )
{
d_data->borderWidth = qMax( borderWidth, 0 );
updateGeometry();
update();
}
//! Return the border width
int QwtKnob::borderWidth() const
{
return d_data->borderWidth;
}
/*!
\brief Set the size of the marker
When setting a size <= 0 the marker will
automatically scaled to 40% of the radius of the knob.
\sa markerSize(), markerStyle()
*/
void QwtKnob::setMarkerSize( int size )
{
if ( d_data->markerSize != size )
{
d_data->markerSize = size;
update();
}
}
/*!
\return Marker size
\sa setMarkerSize()
*/
int QwtKnob::markerSize() const
{
return d_data->markerSize;
}
/*!
\return sizeHint()
*/
QSize QwtKnob::sizeHint() const
{
const QSize hint = qwtKnobSizeHint( this, 50 );
return hint.expandedTo( QApplication::globalStrut() );
}
/*!
\return Minimum size hint
\sa sizeHint()
*/
QSize QwtKnob::minimumSizeHint() const
{
return qwtKnobSizeHint( this, 20 );
}

View File

@@ -0,0 +1,178 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_KNOB_H
#define QWT_KNOB_H
#include "qwt_global.h"
#include "qwt_abstract_slider.h"
class QwtRoundScaleDraw;
/*!
\brief The Knob Widget
The QwtKnob widget imitates look and behavior of a volume knob on a radio.
It looks similar to QDial - not to QwtDial.
The value range of a knob might be divided into several turns.
The layout of the knob depends on the knobWidth().
- width > 0
The diameter of the knob is fixed and the knob is aligned
according to the alignment() flags inside of the contentsRect().
- width <= 0
The knob is extended to the minimum of width/height of the contentsRect()
and aligned in the other direction according to alignment().
Setting a fixed knobWidth() is helpful to align several knobs with different
scale labels.
\image html knob.png
*/
class QWT_EXPORT QwtKnob: public QwtAbstractSlider
{
Q_OBJECT
Q_ENUMS ( KnobStyle MarkerStyle )
Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle )
Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth )
Q_PROPERTY( Qt::Alignment alignment READ alignment WRITE setAlignment )
Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle )
Q_PROPERTY( int numTurns READ numTurns WRITE setNumTurns )
Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle )
Q_PROPERTY( int markerSize READ markerSize WRITE setMarkerSize )
Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
public:
/*!
\brief Style of the knob surface
Depending on the KnobStyle the surface of the knob is
filled from the brushes of the widget palette().
\sa setKnobStyle(), knobStyle()
*/
enum KnobStyle
{
//! Fill the knob with a brush from QPalette::Button.
Flat,
//! Build a gradient from QPalette::Midlight and QPalette::Button
Raised,
/*!
Build a gradient from QPalette::Midlight, QPalette::Button
and QPalette::Midlight
*/
Sunken,
/*!
Build a radial gradient from QPalette::Button
like it is used for QDial in various Qt styles.
*/
Styled
};
/*!
\brief Marker type
The marker indicates the current value on the knob
The default setting is a Notch marker.
\sa setMarkerStyle(), setMarkerSize()
*/
enum MarkerStyle
{
//! Don't paint any marker
NoMarker = -1,
//! Paint a single tick in QPalette::ButtonText color
Tick,
//! Paint a triangle in QPalette::ButtonText color
Triangle,
//! Paint a circle in QPalette::ButtonText color
Dot,
/*!
Draw a raised ellipse with a gradient build from
QPalette::Light and QPalette::Mid
*/
Nub,
/*!
Draw a sunken ellipse with a gradient build from
QPalette::Light and QPalette::Mid
*/
Notch
};
explicit QwtKnob( QWidget* parent = NULL );
virtual ~QwtKnob();
void setAlignment( Qt::Alignment );
Qt::Alignment alignment() const;
void setKnobWidth( int );
int knobWidth() const;
void setNumTurns( int );
int numTurns() const;
void setTotalAngle ( double angle );
double totalAngle() const;
void setKnobStyle( KnobStyle );
KnobStyle knobStyle() const;
void setBorderWidth( int bw );
int borderWidth() const;
void setMarkerStyle( MarkerStyle );
MarkerStyle markerStyle() const;
void setMarkerSize( int );
int markerSize() const;
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
void setScaleDraw( QwtRoundScaleDraw * );
const QwtRoundScaleDraw *scaleDraw() const;
QwtRoundScaleDraw *scaleDraw();
QRect knobRect() const;
protected:
virtual void paintEvent( QPaintEvent * );
virtual void changeEvent( QEvent * );
virtual void drawKnob( QPainter *, const QRectF & ) const;
virtual void drawFocusIndicator( QPainter * ) const;
virtual void drawMarker( QPainter *,
const QRectF &, double arc ) const;
virtual double scrolledTo( const QPoint & ) const;
virtual bool isScrollPosition( const QPoint & ) const;
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,811 @@
/* -*- 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_legend.h"
#include "qwt_legend_label.h"
#include "qwt_dyngrid_layout.h"
#include "qwt_math.h"
#include "qwt_plot_item.h"
#include "qwt_painter.h"
#include <qapplication.h>
#include <qscrollbar.h>
#include <qscrollarea.h>
#include <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
class QwtLegendMap
{
public:
inline bool isEmpty() const { return d_entries.isEmpty(); }
void insert( const QVariant &, const QList<QWidget *> & );
void remove( const QVariant & );
void removeWidget( const QWidget * );
QList<QWidget *> legendWidgets( const QVariant & ) const;
QVariant itemInfo( const QWidget * ) const;
private:
// we don't know anything about itemInfo and therefore don't have
// any key that can be used for a map or hashtab.
// But a simple linear list is o.k. here, as we will never have
// more than a few entries.
class Entry
{
public:
QVariant itemInfo;
QList<QWidget *> widgets;
};
QList< Entry > d_entries;
};
void QwtLegendMap::insert( const QVariant &itemInfo,
const QList<QWidget *> &widgets )
{
for ( int i = 0; i < d_entries.size(); i++ )
{
Entry &entry = d_entries[i];
if ( entry.itemInfo == itemInfo )
{
entry.widgets = widgets;
return;
}
}
Entry newEntry;
newEntry.itemInfo = itemInfo;
newEntry.widgets = widgets;
d_entries += newEntry;
}
void QwtLegendMap::remove( const QVariant &itemInfo )
{
for ( int i = 0; i < d_entries.size(); i++ )
{
Entry &entry = d_entries[i];
if ( entry.itemInfo == itemInfo )
{
d_entries.removeAt( i );
return;
}
}
}
void QwtLegendMap::removeWidget( const QWidget *widget )
{
QWidget *w = const_cast<QWidget *>( widget );
for ( int i = 0; i < d_entries.size(); i++ )
d_entries[ i ].widgets.removeAll( w );
}
QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const
{
if ( widget != NULL )
{
QWidget *w = const_cast<QWidget *>( widget );
for ( int i = 0; i < d_entries.size(); i++ )
{
const Entry &entry = d_entries[i];
if ( entry.widgets.indexOf( w ) >= 0 )
return entry.itemInfo;
}
}
return QVariant();
}
QList<QWidget *> QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const
{
if ( itemInfo.isValid() )
{
for ( int i = 0; i < d_entries.size(); i++ )
{
const Entry &entry = d_entries[i];
if ( entry.itemInfo == itemInfo )
return entry.widgets;
}
}
return QList<QWidget *>();
}
class QwtLegend::PrivateData
{
public:
PrivateData():
itemMode( QwtLegendData::ReadOnly ),
view( NULL )
{
}
QwtLegendData::Mode itemMode;
QwtLegendMap itemMap;
class LegendView;
LegendView *view;
};
class QwtLegend::PrivateData::LegendView: public QScrollArea
{
public:
LegendView( QWidget *parent ):
QScrollArea( parent )
{
contentsWidget = new QWidget( this );
contentsWidget->setObjectName( "QwtLegendViewContents" );
setWidget( contentsWidget );
setWidgetResizable( false );
viewport()->setObjectName( "QwtLegendViewport" );
// QScrollArea::setWidget internally sets autoFillBackground to true
// But we don't want a background.
contentsWidget->setAutoFillBackground( false );
viewport()->setAutoFillBackground( false );
}
virtual bool event( QEvent *event )
{
if ( event->type() == QEvent::PolishRequest )
{
setFocusPolicy( Qt::NoFocus );
}
if ( event->type() == QEvent::Resize )
{
// adjust the size to en/disable the scrollbars
// before QScrollArea adjusts the viewport size
const QRect cr = contentsRect();
int w = cr.width();
int h = contentsWidget->heightForWidth( cr.width() );
if ( h > w )
{
w -= verticalScrollBar()->sizeHint().width();
h = contentsWidget->heightForWidth( w );
}
contentsWidget->resize( w, h );
}
return QScrollArea::event( event );
}
virtual bool viewportEvent( QEvent *event )
{
bool ok = QScrollArea::viewportEvent( event );
if ( event->type() == QEvent::Resize )
{
layoutContents();
}
return ok;
}
QSize viewportSize( int w, int h ) const
{
const int sbHeight = horizontalScrollBar()->sizeHint().height();
const int sbWidth = verticalScrollBar()->sizeHint().width();
const int cw = contentsRect().width();
const int ch = contentsRect().height();
int vw = cw;
int vh = ch;
if ( w > vw )
vh -= sbHeight;
if ( h > vh )
{
vw -= sbWidth;
if ( w > vw && vh == ch )
vh -= sbHeight;
}
return QSize( vw, vh );
}
void layoutContents()
{
const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
contentsWidget->layout() );
if ( tl == NULL )
return;
const QSize visibleSize = viewport()->contentsRect().size();
const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
int w = qMax( visibleSize.width(), minW );
int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
const int vpWidth = viewportSize( w, h ).width();
if ( w > vpWidth )
{
w = qMax( vpWidth, minW );
h = qMax( tl->heightForWidth( w ), visibleSize.height() );
}
contentsWidget->resize( w, h );
}
QWidget *contentsWidget;
};
/*!
Constructor
\param parent Parent widget
*/
QwtLegend::QwtLegend( QWidget *parent ):
QwtAbstractLegend( parent )
{
setFrameStyle( NoFrame );
d_data = new QwtLegend::PrivateData;
d_data->view = new QwtLegend::PrivateData::LegendView( this );
d_data->view->setObjectName( "QwtLegendView" );
d_data->view->setFrameStyle( NoFrame );
QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
d_data->view->contentsWidget );
gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
d_data->view->contentsWidget->installEventFilter( this );
QVBoxLayout *layout = new QVBoxLayout( this );
layout->setContentsMargins( 0, 0, 0, 0 );
layout->addWidget( d_data->view );
}
//! Destructor
QwtLegend::~QwtLegend()
{
delete d_data;
}
/*!
\brief Set the maximum number of entries in a row
F.e when the maximum is set to 1 all items are aligned
vertically. 0 means unlimited
\param numColums Maximum number of entries in a row
\sa maxColumns(), QwtDynGridLayout::setMaxColumns()
*/
void QwtLegend::setMaxColumns( uint numColums )
{
QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
d_data->view->contentsWidget->layout() );
if ( tl )
tl->setMaxColumns( numColums );
}
/*!
\return Maximum number of entries in a row
\sa setMaxColumns(), QwtDynGridLayout::maxColumns()
*/
uint QwtLegend::maxColumns() const
{
uint maxCols = 0;
const QwtDynGridLayout *tl = qobject_cast<const QwtDynGridLayout *>(
d_data->view->contentsWidget->layout() );
if ( tl )
maxCols = tl->maxColumns();
return maxCols;
}
/*!
\brief Set the default mode for legend labels
Legend labels will be constructed according to the
attributes in a QwtLegendData object. When it doesn't
contain a value for the QwtLegendData::ModeRole the
label will be initialized with the default mode of the legend.
\param mode Default item mode
\sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData()
\note Changing the mode doesn't have any effect on existing labels.
*/
void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode )
{
d_data->itemMode = mode;
}
/*!
\return Default item mode
\sa setDefaultItemMode()
*/
QwtLegendData::Mode QwtLegend::defaultItemMode() const
{
return d_data->itemMode;
}
/*!
The contents widget is the only child of the viewport of
the internal QScrollArea and the parent widget of all legend items.
\return Container widget of the legend items
*/
QWidget *QwtLegend::contentsWidget()
{
return d_data->view->contentsWidget;
}
/*!
\return Horizontal scrollbar
\sa verticalScrollBar()
*/
QScrollBar *QwtLegend::horizontalScrollBar() const
{
return d_data->view->horizontalScrollBar();
}
/*!
\return Vertical scrollbar
\sa horizontalScrollBar()
*/
QScrollBar *QwtLegend::verticalScrollBar() const
{
return d_data->view->verticalScrollBar();
}
/*!
The contents widget is the only child of the viewport of
the internal QScrollArea and the parent widget of all legend items.
\return Container widget of the legend items
*/
const QWidget *QwtLegend::contentsWidget() const
{
return d_data->view->contentsWidget;
}
/*!
\brief Update the entries for an item
\param itemInfo Info for an item
\param data List of legend entry attributes for the item
*/
void QwtLegend::updateLegend( const QVariant &itemInfo,
const QList<QwtLegendData> &data )
{
QList<QWidget *> widgetList = legendWidgets( itemInfo );
if ( widgetList.size() != data.size() )
{
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
while ( widgetList.size() > data.size() )
{
QWidget *w = widgetList.takeLast();
contentsLayout->removeWidget( w );
// updates might be triggered by signals from the legend widget
// itself. So we better don't delete it here.
w->hide();
w->deleteLater();
}
for ( int i = widgetList.size(); i < data.size(); i++ )
{
QWidget *widget = createWidget( data[i] );
if ( contentsLayout )
contentsLayout->addWidget( widget );
if ( isVisible() )
{
// QLayout does a delayed show, with the effect, that
// the size hint will be wrong, when applications
// call replot() right after changing the list
// of plot items. So we better do the show now.
widget->setVisible( true );
}
widgetList += widget;
}
if ( widgetList.isEmpty() )
{
d_data->itemMap.remove( itemInfo );
}
else
{
d_data->itemMap.insert( itemInfo, widgetList );
}
updateTabOrder();
}
for ( int i = 0; i < data.size(); i++ )
updateWidget( widgetList[i], data[i] );
}
/*!
\brief Create a widget to be inserted into the legend
The default implementation returns a QwtLegendLabel.
\param data Attributes of the legend entry
\return Widget representing data on the legend
\note updateWidget() will called soon after createWidget()
with the same attributes.
*/
QWidget *QwtLegend::createWidget( const QwtLegendData &data ) const
{
Q_UNUSED( data );
QwtLegendLabel *label = new QwtLegendLabel();
label->setItemMode( defaultItemMode() );
connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) );
connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) );
return label;
}
/*!
\brief Update the widget
\param widget Usually a QwtLegendLabel
\param data Attributes to be displayed
\sa createWidget()
\note When widget is no QwtLegendLabel updateWidget() does nothing.
*/
void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &data )
{
QwtLegendLabel *label = qobject_cast<QwtLegendLabel *>( widget );
if ( label )
{
label->setData( data );
if ( !data.value( QwtLegendData::ModeRole ).isValid() )
{
// use the default mode, when there is no specific
// hint from the legend data
label->setItemMode( defaultItemMode() );
}
}
}
void QwtLegend::updateTabOrder()
{
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
if ( contentsLayout )
{
// set tab focus chain
QWidget *w = NULL;
for ( int i = 0; i < contentsLayout->count(); i++ )
{
QLayoutItem *item = contentsLayout->itemAt( i );
if ( w && item->widget() )
QWidget::setTabOrder( w, item->widget() );
w = item->widget();
}
}
}
//! Return a size hint.
QSize QwtLegend::sizeHint() const
{
QSize hint = d_data->view->contentsWidget->sizeHint();
hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
return hint;
}
/*!
\return The preferred height, for a width.
\param width Width
*/
int QwtLegend::heightForWidth( int width ) const
{
width -= 2 * frameWidth();
int h = d_data->view->contentsWidget->heightForWidth( width );
if ( h >= 0 )
h += 2 * frameWidth();
return h;
}
/*!
Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
for the contentsWidget().
\param object Object to be filtered
\param event Event
\return Forwarded to QwtAbstractLegend::eventFilter()
*/
bool QwtLegend::eventFilter( QObject *object, QEvent *event )
{
if ( object == d_data->view->contentsWidget )
{
switch ( event->type() )
{
case QEvent::ChildRemoved:
{
const QChildEvent *ce =
static_cast<const QChildEvent *>(event);
if ( ce->child()->isWidgetType() )
{
QWidget *w = static_cast< QWidget * >( ce->child() );
d_data->itemMap.removeWidget( w );
}
break;
}
case QEvent::LayoutRequest:
{
d_data->view->layoutContents();
if ( parentWidget() && parentWidget()->layout() == NULL )
{
/*
We want the parent widget ( usually QwtPlot ) to recalculate
its layout, when the contentsWidget has changed. But
because of the scroll view we have to forward the LayoutRequest
event manually.
We don't use updateGeometry() because it doesn't post LayoutRequest
events when the legend is hidden. But we want the
parent widget notified, so it can show/hide the legend
depending on its items.
*/
QApplication::postEvent( parentWidget(),
new QEvent( QEvent::LayoutRequest ) );
}
break;
}
default:
break;
}
}
return QwtAbstractLegend::eventFilter( object, event );
}
/*!
Called internally when the legend has been clicked on.
Emits a clicked() signal.
*/
void QwtLegend::itemClicked()
{
QWidget *w = qobject_cast<QWidget *>( sender() );
if ( w )
{
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
if ( itemInfo.isValid() )
{
const QList<QWidget *> widgetList =
d_data->itemMap.legendWidgets( itemInfo );
const int index = widgetList.indexOf( w );
if ( index >= 0 )
Q_EMIT clicked( itemInfo, index );
}
}
}
/*!
Called internally when the legend has been checked
Emits a checked() signal.
*/
void QwtLegend::itemChecked( bool on )
{
QWidget *w = qobject_cast<QWidget *>( sender() );
if ( w )
{
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
if ( itemInfo.isValid() )
{
const QList<QWidget *> widgetList =
d_data->itemMap.legendWidgets( itemInfo );
const int index = widgetList.indexOf( w );
if ( index >= 0 )
Q_EMIT checked( itemInfo, on, index );
}
}
}
/*!
Render the legend into a given rectangle.
\param painter Painter
\param rect Bounding rectangle
\param fillBackground When true, fill rect with the widget background
\sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself
*/
void QwtLegend::renderLegend( QPainter *painter,
const QRectF &rect, bool fillBackground ) const
{
if ( d_data->itemMap.isEmpty() )
return;
if ( fillBackground )
{
if ( autoFillBackground() ||
testAttribute( Qt::WA_StyledBackground ) )
{
QwtPainter::drawBackgound( painter, rect, this );
}
}
const QwtDynGridLayout *legendLayout =
qobject_cast<QwtDynGridLayout *>( contentsWidget()->layout() );
if ( legendLayout == NULL )
return;
int left, right, top, bottom;
getContentsMargins( &left, &top, &right, &bottom );
QRect layoutRect;
layoutRect.setLeft( qCeil( rect.left() ) + left );
layoutRect.setTop( qCeil( rect.top() ) + top );
layoutRect.setRight( qFloor( rect.right() ) - right );
layoutRect.setBottom( qFloor( rect.bottom() ) - bottom );
uint numCols = legendLayout->columnsForWidth( layoutRect.width() );
QList<QRect> itemRects =
legendLayout->layoutItems( layoutRect, numCols );
int index = 0;
for ( int i = 0; i < legendLayout->count(); i++ )
{
QLayoutItem *item = legendLayout->itemAt( i );
QWidget *w = item->widget();
if ( w )
{
painter->save();
painter->setClipRect( itemRects[index], Qt::IntersectClip );
renderItem( painter, w, itemRects[index], fillBackground );
index++;
painter->restore();
}
}
}
/*!
Render a legend entry into a given rectangle.
\param painter Painter
\param widget Widget representing a legend entry
\param rect Bounding rectangle
\param fillBackground When true, fill rect with the widget background
\note When widget is not derived from QwtLegendLabel renderItem
does nothing beside the background
*/
void QwtLegend::renderItem( QPainter *painter,
const QWidget *widget, const QRectF &rect, bool fillBackground ) const
{
if ( fillBackground )
{
if ( widget->autoFillBackground() ||
widget->testAttribute( Qt::WA_StyledBackground ) )
{
QwtPainter::drawBackgound( painter, rect, widget );
}
}
const QwtLegendLabel *label = qobject_cast<const QwtLegendLabel *>( widget );
if ( label )
{
// icon
const QwtGraphic &icon = label->data().icon();
const QSizeF sz = icon.defaultSize();
const QRectF iconRect( rect.x() + label->margin(),
rect.center().y() - 0.5 * sz.height(),
sz.width(), sz.height() );
icon.render( painter, iconRect, Qt::KeepAspectRatio );
// title
QRectF titleRect = rect;
titleRect.setX( iconRect.right() + 2 * label->spacing() );
painter->setFont( label->font() );
painter->setPen( label->palette().color( QPalette::Text ) );
const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect );
}
}
/*!
\return List of widgets associated to a item
\param itemInfo Info about an item
\sa legendWidget(), itemInfo(), QwtPlot::itemToInfo()
*/
QList<QWidget *> QwtLegend::legendWidgets( const QVariant &itemInfo ) const
{
return d_data->itemMap.legendWidgets( itemInfo );
}
/*!
\return First widget in the list of widgets associated to an item
\param itemInfo Info about an item
\sa itemInfo(), QwtPlot::itemToInfo()
\note Almost all types of items have only one widget
*/
QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const
{
const QList<QWidget *> list = d_data->itemMap.legendWidgets( itemInfo );
if ( list.isEmpty() )
return NULL;
return list[0];
}
/*!
Find the item that is associated to a widget
\param widget Widget on the legend
\return Associated item info
\sa legendWidget()
*/
QVariant QwtLegend::itemInfo( const QWidget *widget ) const
{
return d_data->itemMap.itemInfo( widget );
}
//! \return True, when no item is inserted
bool QwtLegend::isEmpty() const
{
return d_data->itemMap.isEmpty();
}
/*!
Return the extent, that is needed for the scrollbars
\param orientation Orientation (
\return The width of the vertical scrollbar for Qt::Horizontal and v.v.
*/
int QwtLegend::scrollExtent( Qt::Orientation orientation ) const
{
int extent = 0;
if ( orientation == Qt::Horizontal )
extent = verticalScrollBar()->sizeHint().width();
else
extent = horizontalScrollBar()->sizeHint().height();
return extent;
}

View File

@@ -0,0 +1,117 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_LEGEND_H
#define QWT_LEGEND_H
#include "qwt_global.h"
#include "qwt_abstract_legend.h"
#include <qvariant.h>
class QScrollBar;
/*!
\brief The legend widget
The QwtLegend widget is a tabular arrangement of legend items. Legend
items might be any type of widget, but in general they will be
a QwtLegendLabel.
\sa QwtLegendLabel, QwtPlotItem, QwtPlot
*/
class QWT_EXPORT QwtLegend : public QwtAbstractLegend
{
Q_OBJECT
public:
explicit QwtLegend( QWidget *parent = NULL );
virtual ~QwtLegend();
void setMaxColumns( uint numColums );
uint maxColumns() const;
void setDefaultItemMode( QwtLegendData::Mode );
QwtLegendData::Mode defaultItemMode() const;
QWidget *contentsWidget();
const QWidget *contentsWidget() const;
QWidget *legendWidget( const QVariant & ) const;
QList<QWidget *> legendWidgets( const QVariant & ) const;
QVariant itemInfo( const QWidget * ) const;
virtual bool eventFilter( QObject *, QEvent * );
virtual QSize sizeHint() const;
virtual int heightForWidth( int w ) const;
QScrollBar *horizontalScrollBar() const;
QScrollBar *verticalScrollBar() const;
virtual void renderLegend( QPainter *,
const QRectF &, bool fillBackground ) const;
virtual void renderItem( QPainter *,
const QWidget *, const QRectF &, bool fillBackground ) const;
virtual bool isEmpty() const;
virtual int scrollExtent( Qt::Orientation ) const;
Q_SIGNALS:
/*!
A signal which is emitted when the user has clicked on
a legend label, which is in QwtLegendData::Clickable mode.
\param itemInfo Info for the item item of the
selected legend item
\param index Index of the legend label in the list of widgets
that are associated with the plot item
\note clicks are disabled as default
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
*/
void clicked( const QVariant &itemInfo, int index );
/*!
A signal which is emitted when the user has clicked on
a legend label, which is in QwtLegendData::Checkable mode
\param itemInfo Info for the item of the
selected legend label
\param index Index of the legend label in the list of widgets
that are associated with the plot item
\param on True when the legend label is checked
\note clicks are disabled as default
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
*/
void checked( const QVariant &itemInfo, bool on, int index );
public Q_SLOTS:
virtual void updateLegend( const QVariant &,
const QList<QwtLegendData> & );
protected Q_SLOTS:
void itemClicked();
void itemChecked( bool );
protected:
virtual QWidget *createWidget( const QwtLegendData & ) const;
virtual void updateWidget( QWidget *widget, const QwtLegendData &data );
private:
void updateTabOrder();
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,129 @@
/* -*- 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_legend_data.h"
//! Constructor
QwtLegendData::QwtLegendData()
{
}
//! Destructor
QwtLegendData::~QwtLegendData()
{
}
/*!
Set the legend attributes
QwtLegendData actually is a QMap<int, QVariant> with some
convenience interfaces
\param map Values
\sa values()
*/
void QwtLegendData::setValues( const QMap<int, QVariant> &map )
{
d_map = map;
}
/*!
\return Legend attributes
\sa setValues()
*/
const QMap<int, QVariant> &QwtLegendData::values() const
{
return d_map;
}
/*!
\param role Attribute role
\return True, when the internal map has an entry for role
*/
bool QwtLegendData::hasRole( int role ) const
{
return d_map.contains( role );
}
/*!
Set an attribute value
\param role Attribute role
\param data Attribute value
\sa value()
*/
void QwtLegendData::setValue( int role, const QVariant &data )
{
d_map[role] = data;
}
/*!
\param role Attribute role
\return Attribute value for a specific role
*/
QVariant QwtLegendData::value( int role ) const
{
if ( !d_map.contains( role ) )
return QVariant();
return d_map[role];
}
//! \return True, when the internal map is empty
bool QwtLegendData::isValid() const
{
return !d_map.isEmpty();
}
//! \return Value of the TitleRole attribute
QwtText QwtLegendData::title() const
{
QwtText text;
const QVariant titleValue = value( QwtLegendData::TitleRole );
if ( titleValue.canConvert<QwtText>() )
{
text = qvariant_cast<QwtText>( titleValue );
}
else if ( titleValue.canConvert<QString>() )
{
text.setText( qvariant_cast<QString>( titleValue ) );
}
return text;
}
//! \return Value of the IconRole attribute
QwtGraphic QwtLegendData::icon() const
{
const QVariant iconValue = value( QwtLegendData::IconRole );
QwtGraphic graphic;
if ( iconValue.canConvert<QwtGraphic>() )
{
graphic = qvariant_cast<QwtGraphic>( iconValue );
}
return graphic;
}
//! \return Value of the ModeRole attribute
QwtLegendData::Mode QwtLegendData::mode() const
{
const QVariant modeValue = value( QwtLegendData::ModeRole );
if ( modeValue.canConvert<int>() )
{
const int mode = qvariant_cast<int>( modeValue );
return static_cast<QwtLegendData::Mode>( mode );
}
return QwtLegendData::ReadOnly;
}

View File

@@ -0,0 +1,87 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_LEGEND_DATA_H
#define QWT_LEGEND_DATA_H
#include "qwt_global.h"
#include "qwt_text.h"
#include "qwt_graphic.h"
#include <qvariant.h>
#include <qpixmap.h>
#include <qmap.h>
/*!
\brief Attributes of an entry on a legend
QwtLegendData is an abstract container ( like QAbstractModel )
to exchange attributes, that are only known between to
the plot item and the legend.
By overloading QwtPlotItem::legendData() any other set of attributes
could be used, that can be handled by a modified ( or completely
different ) implementation of a legend.
\sa QwtLegend, QwtPlotLegendItem
\note The stockchart example implements a legend as a tree
with checkable items
*/
class QWT_EXPORT QwtLegendData
{
public:
//! Mode defining how a legend entry interacts
enum Mode
{
//! The legend item is not interactive, like a label
ReadOnly,
//! The legend item is clickable, like a push button
Clickable,
//! The legend item is checkable, like a checkable button
Checkable
};
//! Identifier how to interprete a QVariant
enum Role
{
// The value is a Mode
ModeRole,
// The value is a title
TitleRole,
// The value is an icon
IconRole,
// Values < UserRole are reserved for internal use
UserRole = 32
};
QwtLegendData();
~QwtLegendData();
void setValues( const QMap<int, QVariant> & );
const QMap<int, QVariant> &values() const;
void setValue( int role, const QVariant & );
QVariant value( int role ) const;
bool hasRole( int role ) const;
bool isValid() const;
QwtGraphic icon() const;
QwtText title() const;
Mode mode() const;
private:
QMap<int, QVariant> d_map;
};
#endif

View File

@@ -0,0 +1,421 @@
/* -*- 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_legend_label.h"
#include "qwt_legend_data.h"
#include "qwt_math.h"
#include "qwt_painter.h"
#include "qwt_symbol.h"
#include "qwt_graphic.h"
#include <qpainter.h>
#include <qdrawutil.h>
#include <qstyle.h>
#include <qpen.h>
#include <qevent.h>
#include <qstyleoption.h>
#include <qapplication.h>
static const int ButtonFrame = 2;
static const int Margin = 2;
static QSize buttonShift( const QwtLegendLabel *w )
{
QStyleOption option;
option.init( w );
const int ph = w->style()->pixelMetric(
QStyle::PM_ButtonShiftHorizontal, &option, w );
const int pv = w->style()->pixelMetric(
QStyle::PM_ButtonShiftVertical, &option, w );
return QSize( ph, pv );
}
class QwtLegendLabel::PrivateData
{
public:
PrivateData():
itemMode( QwtLegendData::ReadOnly ),
isDown( false ),
spacing( Margin )
{
}
QwtLegendData::Mode itemMode;
QwtLegendData legendData;
bool isDown;
QPixmap icon;
int spacing;
};
/*!
Set the attributes of the legend label
\param legendData Attributes of the label
\sa data()
*/
void QwtLegendLabel::setData( const QwtLegendData &legendData )
{
d_data->legendData = legendData;
const bool doUpdate = updatesEnabled();
setUpdatesEnabled( false );
setText( legendData.title() );
setIcon( legendData.icon().toPixmap() );
if ( legendData.hasRole( QwtLegendData::ModeRole ) )
setItemMode( legendData.mode() );
if ( doUpdate )
{
setUpdatesEnabled( true );
update();
}
}
/*!
\return Attributes of the label
\sa setData(), QwtPlotItem::legendData()
*/
const QwtLegendData &QwtLegendLabel::data() const
{
return d_data->legendData;
}
/*!
\param parent Parent widget
*/
QwtLegendLabel::QwtLegendLabel( QWidget *parent ):
QwtTextLabel( parent )
{
d_data = new PrivateData;
setMargin( Margin );
setIndent( Margin );
}
//! Destructor
QwtLegendLabel::~QwtLegendLabel()
{
delete d_data;
d_data = NULL;
}
/*!
Set the text to the legend item
\param text Text label
\sa QwtTextLabel::text()
*/
void QwtLegendLabel::setText( const QwtText &text )
{
const int flags = Qt::AlignLeft | Qt::AlignVCenter
| Qt::TextExpandTabs | Qt::TextWordWrap;
QwtText txt = text;
txt.setRenderFlags( flags );
QwtTextLabel::setText( txt );
}
/*!
Set the item mode
The default is QwtLegendData::ReadOnly
\param mode Item mode
\sa itemMode()
*/
void QwtLegendLabel::setItemMode( QwtLegendData::Mode mode )
{
if ( mode != d_data->itemMode )
{
d_data->itemMode = mode;
d_data->isDown = false;
setFocusPolicy( ( mode != QwtLegendData::ReadOnly )
? Qt::TabFocus : Qt::NoFocus );
setMargin( ButtonFrame + Margin );
updateGeometry();
}
}
/*!
\return Item mode
\sa setItemMode()
*/
QwtLegendData::Mode QwtLegendLabel::itemMode() const
{
return d_data->itemMode;
}
/*!
Assign the icon
\param icon Pixmap representing a plot item
\sa icon(), QwtPlotItem::legendIcon()
*/
void QwtLegendLabel::setIcon( const QPixmap &icon )
{
d_data->icon = icon;
int indent = margin() + d_data->spacing;
if ( icon.width() > 0 )
indent += icon.width() + d_data->spacing;
setIndent( indent );
}
/*!
\return Pixmap representing a plot item
\sa setIcon()
*/
QPixmap QwtLegendLabel::icon() const
{
return d_data->icon;
}
/*!
\brief Change the spacing between icon and text
\param spacing Spacing
\sa spacing(), QwtTextLabel::margin()
*/
void QwtLegendLabel::setSpacing( int spacing )
{
spacing = qMax( spacing, 0 );
if ( spacing != d_data->spacing )
{
d_data->spacing = spacing;
int indent = margin() + d_data->spacing;
if ( d_data->icon.width() > 0 )
indent += d_data->icon.width() + d_data->spacing;
setIndent( indent );
}
}
/*!
\return Spacing between icon and text
\sa setSpacing(), QwtTextLabel::margin()
*/
int QwtLegendLabel::spacing() const
{
return d_data->spacing;
}
/*!
Check/Uncheck a the item
\param on check/uncheck
\sa setItemMode()
*/
void QwtLegendLabel::setChecked( bool on )
{
if ( d_data->itemMode == QwtLegendData::Checkable )
{
const bool isBlocked = signalsBlocked();
blockSignals( true );
setDown( on );
blockSignals( isBlocked );
}
}
//! Return true, if the item is checked
bool QwtLegendLabel::isChecked() const
{
return d_data->itemMode == QwtLegendData::Checkable && isDown();
}
//! Set the item being down
void QwtLegendLabel::setDown( bool down )
{
if ( down == d_data->isDown )
return;
d_data->isDown = down;
update();
if ( d_data->itemMode == QwtLegendData::Clickable )
{
if ( d_data->isDown )
Q_EMIT pressed();
else
{
Q_EMIT released();
Q_EMIT clicked();
}
}
if ( d_data->itemMode == QwtLegendData::Checkable )
Q_EMIT checked( d_data->isDown );
}
//! Return true, if the item is down
bool QwtLegendLabel::isDown() const
{
return d_data->isDown;
}
//! Return a size hint
QSize QwtLegendLabel::sizeHint() const
{
QSize sz = QwtTextLabel::sizeHint();
sz.setHeight( qMax( sz.height(), d_data->icon.height() + 4 ) );
if ( d_data->itemMode != QwtLegendData::ReadOnly )
{
sz += buttonShift( this );
sz = sz.expandedTo( QApplication::globalStrut() );
}
return sz;
}
//! Paint event
void QwtLegendLabel::paintEvent( QPaintEvent *e )
{
const QRect cr = contentsRect();
QPainter painter( this );
painter.setClipRegion( e->region() );
if ( d_data->isDown )
{
qDrawWinButton( &painter, 0, 0, width(), height(),
palette(), true );
}
painter.save();
if ( d_data->isDown )
{
const QSize shiftSize = buttonShift( this );
painter.translate( shiftSize.width(), shiftSize.height() );
}
painter.setClipRect( cr );
drawContents( &painter );
if ( !d_data->icon.isNull() )
{
QRect iconRect = cr;
iconRect.setX( iconRect.x() + margin() );
if ( d_data->itemMode != QwtLegendData::ReadOnly )
iconRect.setX( iconRect.x() + ButtonFrame );
iconRect.setSize( d_data->icon.size() );
iconRect.moveCenter( QPoint( iconRect.center().x(), cr.center().y() ) );
painter.drawPixmap( iconRect, d_data->icon );
}
painter.restore();
}
//! Handle mouse press events
void QwtLegendLabel::mousePressEvent( QMouseEvent *e )
{
if ( e->button() == Qt::LeftButton )
{
switch ( d_data->itemMode )
{
case QwtLegendData::Clickable:
{
setDown( true );
return;
}
case QwtLegendData::Checkable:
{
setDown( !isDown() );
return;
}
default:;
}
}
QwtTextLabel::mousePressEvent( e );
}
//! Handle mouse release events
void QwtLegendLabel::mouseReleaseEvent( QMouseEvent *e )
{
if ( e->button() == Qt::LeftButton )
{
switch ( d_data->itemMode )
{
case QwtLegendData::Clickable:
{
setDown( false );
return;
}
case QwtLegendData::Checkable:
{
return; // do nothing, but accept
}
default:;
}
}
QwtTextLabel::mouseReleaseEvent( e );
}
//! Handle key press events
void QwtLegendLabel::keyPressEvent( QKeyEvent *e )
{
if ( e->key() == Qt::Key_Space )
{
switch ( d_data->itemMode )
{
case QwtLegendData::Clickable:
{
if ( !e->isAutoRepeat() )
setDown( true );
return;
}
case QwtLegendData::Checkable:
{
if ( !e->isAutoRepeat() )
setDown( !isDown() );
return;
}
default:;
}
}
QwtTextLabel::keyPressEvent( e );
}
//! Handle key release events
void QwtLegendLabel::keyReleaseEvent( QKeyEvent *e )
{
if ( e->key() == Qt::Key_Space )
{
switch ( d_data->itemMode )
{
case QwtLegendData::Clickable:
{
if ( !e->isAutoRepeat() )
setDown( false );
return;
}
case QwtLegendData::Checkable:
{
return; // do nothing, but accept
}
default:;
}
}
QwtTextLabel::keyReleaseEvent( e );
}

View File

@@ -0,0 +1,80 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_LEGEND_LABEL_H
#define QWT_LEGEND_LABEL_H
#include "qwt_global.h"
#include "qwt_legend_data.h"
#include "qwt_text.h"
#include "qwt_text_label.h"
#include <qpixmap.h>
class QwtLegendData;
/*!
\brief A widget representing something on a QwtLegend.
*/
class QWT_EXPORT QwtLegendLabel: public QwtTextLabel
{
Q_OBJECT
public:
explicit QwtLegendLabel( QWidget *parent = 0 );
virtual ~QwtLegendLabel();
void setData( const QwtLegendData & );
const QwtLegendData &data() const;
void setItemMode( QwtLegendData::Mode );
QwtLegendData::Mode itemMode() const;
void setSpacing( int spacing );
int spacing() const;
virtual void setText( const QwtText & );
void setIcon( const QPixmap & );
QPixmap icon() const;
virtual QSize sizeHint() const;
bool isChecked() const;
public Q_SLOTS:
void setChecked( bool on );
Q_SIGNALS:
//! Signal, when the legend item has been clicked
void clicked();
//! Signal, when the legend item has been pressed
void pressed();
//! Signal, when the legend item has been released
void released();
//! Signal, when the legend item has been toggled
void checked( bool );
protected:
void setDown( bool );
bool isDown() const;
virtual void paintEvent( QPaintEvent * );
virtual void mousePressEvent( QMouseEvent * );
virtual void mouseReleaseEvent( QMouseEvent * );
virtual void keyPressEvent( QKeyEvent * );
virtual void keyReleaseEvent( QKeyEvent * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,492 @@
/* -*- 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_magnifier.h"
#include "qwt_math.h"
#include <qevent.h>
#include <qwidget.h>
class QwtMagnifier::PrivateData
{
public:
PrivateData():
isEnabled( false ),
wheelFactor( 0.9 ),
wheelModifiers( Qt::NoModifier ),
mouseFactor( 0.95 ),
mouseButton( Qt::RightButton ),
mouseButtonModifiers( Qt::NoModifier ),
keyFactor( 0.9 ),
zoomInKey( Qt::Key_Plus ),
zoomInKeyModifiers( Qt::NoModifier ),
zoomOutKey( Qt::Key_Minus ),
zoomOutKeyModifiers( Qt::NoModifier ),
mousePressed( false )
{
}
bool isEnabled;
double wheelFactor;
Qt::KeyboardModifiers wheelModifiers;
double mouseFactor;
Qt::MouseButton mouseButton;
Qt::KeyboardModifiers mouseButtonModifiers;
double keyFactor;
int zoomInKey;
Qt::KeyboardModifiers zoomInKeyModifiers;
int zoomOutKey;
Qt::KeyboardModifiers zoomOutKeyModifiers;
bool mousePressed;
bool hasMouseTracking;
QPoint mousePos;
};
/*!
Constructor
\param parent Widget to be magnified
*/
QwtMagnifier::QwtMagnifier( QWidget *parent ):
QObject( parent )
{
d_data = new PrivateData();
setEnabled( true );
}
//! Destructor
QwtMagnifier::~QwtMagnifier()
{
delete d_data;
}
/*!
\brief En/disable the magnifier
When enabled is true an event filter is installed for
the observed widget, otherwise the event filter is removed.
\param on true or false
\sa isEnabled(), eventFilter()
*/
void QwtMagnifier::setEnabled( bool on )
{
if ( d_data->isEnabled != on )
{
d_data->isEnabled = on;
QObject *o = parent();
if ( o )
{
if ( d_data->isEnabled )
o->installEventFilter( this );
else
o->removeEventFilter( this );
}
}
}
/*!
\return true when enabled, false otherwise
\sa setEnabled(), eventFilter()
*/
bool QwtMagnifier::isEnabled() const
{
return d_data->isEnabled;
}
/*!
\brief Change the wheel factor
The wheel factor defines the ratio between the current range
on the parent widget and the zoomed range for each step of the wheel.
Use values > 1 for magnification (i.e. 2.0) and values < 1 for
scaling down (i.e. 1/2.0 = 0.5). You can use this feature for
inverting the direction of the wheel.
The default value is 0.9.
\param factor Wheel factor
\sa wheelFactor(), setWheelButtonState(),
setMouseFactor(), setKeyFactor()
*/
void QwtMagnifier::setWheelFactor( double factor )
{
d_data->wheelFactor = factor;
}
/*!
\return Wheel factor
\sa setWheelFactor()
*/
double QwtMagnifier::wheelFactor() const
{
return d_data->wheelFactor;
}
/*!
Assign keyboard modifiers for zooming in/out using the wheel.
The default modifiers are Qt::NoModifiers.
\param modifiers Keyboard modifiers
\sa wheelModifiers()
*/
void QwtMagnifier::setWheelModifiers( Qt::KeyboardModifiers modifiers )
{
d_data->wheelModifiers = modifiers;
}
/*!
\return Wheel modifiers
\sa setWheelModifiers()
*/
Qt::KeyboardModifiers QwtMagnifier::wheelModifiers() const
{
return d_data->wheelModifiers;
}
/*!
\brief Change the mouse factor
The mouse factor defines the ratio between the current range
on the parent widget and the zoomed range for each vertical mouse movement.
The default value is 0.95.
\param factor Wheel factor
\sa mouseFactor(), setMouseButton(), setWheelFactor(), setKeyFactor()
*/
void QwtMagnifier::setMouseFactor( double factor )
{
d_data->mouseFactor = factor;
}
/*!
\return Mouse factor
\sa setMouseFactor()
*/
double QwtMagnifier::mouseFactor() const
{
return d_data->mouseFactor;
}
/*!
Assign the mouse button, that is used for zooming in/out.
The default value is Qt::RightButton.
\param button Button
\param modifiers Keyboard modifiers
\sa getMouseButton()
*/
void QwtMagnifier::setMouseButton(
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
{
d_data->mouseButton = button;
d_data->mouseButtonModifiers = modifiers;
}
//! \sa setMouseButton()
void QwtMagnifier::getMouseButton(
Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const
{
button = d_data->mouseButton;
modifiers = d_data->mouseButtonModifiers;
}
/*!
\brief Change the key factor
The key factor defines the ratio between the current range
on the parent widget and the zoomed range for each key press of
the zoom in/out keys. The default value is 0.9.
\param factor Key factor
\sa keyFactor(), setZoomInKey(), setZoomOutKey(),
setWheelFactor, setMouseFactor()
*/
void QwtMagnifier::setKeyFactor( double factor )
{
d_data->keyFactor = factor;
}
/*!
\return Key factor
\sa setKeyFactor()
*/
double QwtMagnifier::keyFactor() const
{
return d_data->keyFactor;
}
/*!
Assign the key, that is used for zooming in.
The default combination is Qt::Key_Plus + Qt::NoModifier.
\param key
\param modifiers
\sa getZoomInKey(), setZoomOutKey()
*/
void QwtMagnifier::setZoomInKey( int key,
Qt::KeyboardModifiers modifiers )
{
d_data->zoomInKey = key;
d_data->zoomInKeyModifiers = modifiers;
}
/*!
\brief Retrieve the settings of the zoom in key
\param key Key code, see Qt::Key
\param modifiers Keyboard modifiers
\sa setZoomInKey()
*/
void QwtMagnifier::getZoomInKey( int &key,
Qt::KeyboardModifiers &modifiers ) const
{
key = d_data->zoomInKey;
modifiers = d_data->zoomInKeyModifiers;
}
/*!
Assign the key, that is used for zooming out.
The default combination is Qt::Key_Minus + Qt::NoModifier.
\param key
\param modifiers
\sa getZoomOutKey(), setZoomOutKey()
*/
void QwtMagnifier::setZoomOutKey( int key,
Qt::KeyboardModifiers modifiers )
{
d_data->zoomOutKey = key;
d_data->zoomOutKeyModifiers = modifiers;
}
/*!
\brief Retrieve the settings of the zoom out key
\param key Key code, see Qt::Key
\param modifiers Keyboard modifiers
\sa setZoomOutKey()
*/
void QwtMagnifier::getZoomOutKey( int &key,
Qt::KeyboardModifiers &modifiers ) const
{
key = d_data->zoomOutKey;
modifiers = d_data->zoomOutKeyModifiers;
}
/*!
\brief Event filter
When isEnabled() is true, the mouse events of the
observed widget are filtered.
\param object Object to be filtered
\param event Event
\return Forwarded to QObject::eventFilter()
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent()
widgetKeyReleaseEvent()
*/
bool QwtMagnifier::eventFilter( QObject *object, QEvent *event )
{
if ( object && object == parent() )
{
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::MouseMove:
{
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::MouseButtonRelease:
{
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::Wheel:
{
widgetWheelEvent( static_cast<QWheelEvent *>( event ) );
break;
}
case QEvent::KeyPress:
{
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
break;
}
case QEvent::KeyRelease:
{
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
break;
}
default:;
}
}
return QObject::eventFilter( object, event );
}
/*!
Handle a mouse press event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent()
*/
void QwtMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent )
{
if ( parentWidget() == NULL )
return;
if ( ( mouseEvent->button() != d_data->mouseButton ) ||
( mouseEvent->modifiers() != d_data->mouseButtonModifiers ) )
{
return;
}
d_data->hasMouseTracking = parentWidget()->hasMouseTracking();
parentWidget()->setMouseTracking( true );
d_data->mousePos = mouseEvent->pos();
d_data->mousePressed = true;
}
/*!
Handle a mouse release event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(),
*/
void QwtMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
{
Q_UNUSED( mouseEvent );
if ( d_data->mousePressed && parentWidget() )
{
d_data->mousePressed = false;
parentWidget()->setMouseTracking( d_data->hasMouseTracking );
}
}
/*!
Handle a mouse move event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
*/
void QwtMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
{
if ( !d_data->mousePressed )
return;
const int dy = mouseEvent->pos().y() - d_data->mousePos.y();
if ( dy != 0 )
{
double f = d_data->mouseFactor;
if ( dy < 0 )
f = 1 / f;
rescale( f );
}
d_data->mousePos = mouseEvent->pos();
}
/*!
Handle a wheel event for the observed widget.
\param wheelEvent Wheel event
\sa eventFilter()
*/
void QwtMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent )
{
if ( wheelEvent->modifiers() != d_data->wheelModifiers )
{
return;
}
if ( d_data->wheelFactor != 0.0 )
{
/*
A positive delta indicates that the wheel was
rotated forwards away from the user; a negative
value indicates that the wheel was rotated
backwards toward the user.
Most mouse types work in steps of 15 degrees,
in which case the delta value is a multiple
of 120 (== 15 * 8).
*/
double f = qPow( d_data->wheelFactor,
qAbs( wheelEvent->delta() / 120.0 ) );
if ( wheelEvent->delta() > 0 )
f = 1 / f;
rescale( f );
}
}
/*!
Handle a key press event for the observed widget.
\param keyEvent Key event
\sa eventFilter(), widgetKeyReleaseEvent()
*/
void QwtMagnifier::widgetKeyPressEvent( QKeyEvent *keyEvent )
{
if ( keyEvent->key() == d_data->zoomInKey &&
keyEvent->modifiers() == d_data->zoomInKeyModifiers )
{
rescale( d_data->keyFactor );
}
else if ( keyEvent->key() == d_data->zoomOutKey &&
keyEvent->modifiers() == d_data->zoomOutKeyModifiers )
{
rescale( 1.0 / d_data->keyFactor );
}
}
/*!
Handle a key release event for the observed widget.
\param keyEvent Key event
\sa eventFilter(), widgetKeyReleaseEvent()
*/
void QwtMagnifier::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
{
Q_UNUSED( keyEvent );
}
//! \return Parent widget, where the rescaling happens
QWidget *QwtMagnifier::parentWidget()
{
return qobject_cast<QWidget *>( parent() );
}
//! \return Parent widget, where the rescaling happens
const QWidget *QwtMagnifier::parentWidget() const
{
return qobject_cast<const QWidget *>( parent() );
}

View File

@@ -0,0 +1,86 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_MAGNIFIER_H
#define QWT_MAGNIFIER_H 1
#include "qwt_global.h"
#include <qobject.h>
class QWidget;
class QMouseEvent;
class QWheelEvent;
class QKeyEvent;
/*!
\brief QwtMagnifier provides zooming, by magnifying in steps.
Using QwtMagnifier a plot can be zoomed in/out in steps using
keys, the mouse wheel or moving a mouse button in vertical direction.
*/
class QWT_EXPORT QwtMagnifier: public QObject
{
Q_OBJECT
public:
explicit QwtMagnifier( QWidget * );
virtual ~QwtMagnifier();
QWidget *parentWidget();
const QWidget *parentWidget() const;
void setEnabled( bool );
bool isEnabled() const;
// mouse
void setMouseFactor( double );
double mouseFactor() const;
void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier );
void getMouseButton( Qt::MouseButton &, Qt::KeyboardModifiers & ) const;
// mouse wheel
void setWheelFactor( double );
double wheelFactor() const;
void setWheelModifiers( Qt::KeyboardModifiers );
Qt::KeyboardModifiers wheelModifiers() const;
// keyboard
void setKeyFactor( double );
double keyFactor() const;
void setZoomInKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
void getZoomInKey( int &key, Qt::KeyboardModifiers & ) const;
void setZoomOutKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
void getZoomOutKey( int &key, Qt::KeyboardModifiers & ) const;
virtual bool eventFilter( QObject *, QEvent * );
protected:
/*!
Rescale the parent widget
\param factor Scale factor
*/
virtual void rescale( double factor ) = 0;
virtual void widgetMousePressEvent( QMouseEvent * );
virtual void widgetMouseReleaseEvent( QMouseEvent * );
virtual void widgetMouseMoveEvent( QMouseEvent * );
virtual void widgetWheelEvent( QWheelEvent * );
virtual void widgetKeyPressEvent( QKeyEvent * );
virtual void widgetKeyReleaseEvent( QKeyEvent * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,74 @@
/* -*- 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_math.h"
/*!
\brief Find the smallest value in an array
\param array Pointer to an array
\param size Array size
*/
double qwtGetMin( const double *array, int size )
{
if ( size <= 0 )
return 0.0;
double rv = array[0];
for ( int i = 1; i < size; i++ )
rv = qMin( rv, array[i] );
return rv;
}
/*!
\brief Find the largest value in an array
\param array Pointer to an array
\param size Array size
*/
double qwtGetMax( const double *array, int size )
{
if ( size <= 0 )
return 0.0;
double rv = array[0];
for ( int i = 1; i < size; i++ )
rv = qMax( rv, array[i] );
return rv;
}
/*!
\brief Normalize an angle to be int the range [0.0, 2 * PI[
\param radians Angle in radians
\return Normalized angle in radians
*/
double qwtNormalizeRadians( double radians )
{
double a = ::fmod( radians, 2.0 * M_PI );
if ( a < 0.0 )
a += 2.0 * M_PI;
return a;
}
/*!
\brief Normalize an angle to be int the range [0.0, 360.0[
\param radians Angle in degrees
\return Normalized angle in degrees
*/
double qwtNormalizeDegrees( double degrees )
{
double a = ::fmod( degrees, 360.0 );
if ( a < 0.0 )
a += 360.0;
return a;
}

View File

@@ -0,0 +1,149 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_MATH_H
#define QWT_MATH_H
#include "qwt_global.h"
#if defined(_MSC_VER)
/*
Microsoft says:
Define _USE_MATH_DEFINES before including math.h to expose these macro
definitions for common math constants. These are placed under an #ifdef
since these commonly-defined names are not part of the C/C++ standards.
*/
#define _USE_MATH_DEFINES 1
#endif
#include <qmath.h>
#include "qwt_global.h"
#ifndef M_PI_2
// For Qt <= 4.8.4 M_PI_2 is not known by MinGW-w64
// when compiling with -std=c++11
#define M_PI_2 (1.57079632679489661923)
#endif
#ifndef LOG_MIN
//! Minimum value for logarithmic scales
#define LOG_MIN 1.0e-100
#endif
#ifndef LOG_MAX
//! Maximum value for logarithmic scales
#define LOG_MAX 1.0e100
#endif
QWT_EXPORT double qwtGetMin( const double *array, int size );
QWT_EXPORT double qwtGetMax( const double *array, int size );
QWT_EXPORT double qwtNormalizeRadians( double radians );
QWT_EXPORT double qwtNormalizeDegrees( double degrees );
/*!
\brief Compare 2 values, relative to an interval
Values are "equal", when :
\f$\cdot value2 - value1 <= abs(intervalSize * 10e^{-6})\f$
\param value1 First value to compare
\param value2 Second value to compare
\param intervalSize interval size
\return 0: if equal, -1: if value2 > value1, 1: if value1 > value2
*/
inline int qwtFuzzyCompare( double value1, double value2, double intervalSize )
{
const double eps = qAbs( 1.0e-6 * intervalSize );
if ( value2 - value1 > eps )
return -1;
if ( value1 - value2 > eps )
return 1;
return 0;
}
inline bool qwtFuzzyGreaterOrEqual( double d1, double d2 )
{
return ( d1 >= d2 ) || qFuzzyCompare( d1, d2 );
}
inline bool qwtFuzzyLessOrEqual( double d1, double d2 )
{
return ( d1 <= d2 ) || qFuzzyCompare( d1, d2 );
}
//! Return the sign
inline int qwtSign( double x )
{
if ( x > 0.0 )
return 1;
else if ( x < 0.0 )
return ( -1 );
else
return 0;
}
//! Return the square of a number
inline double qwtSqr( double x )
{
return x * x;
}
//! Approximation of arc tangent ( error below 0,005 radians )
inline double qwtFastAtan( double x )
{
if ( x < -1.0 )
return -M_PI_2 - x / ( x * x + 0.28 );
if ( x > 1.0 )
return M_PI_2 - x / ( x * x + 0.28 );
return x / ( 1.0 + x * x * 0.28 );
}
//! Approximation of arc tangent ( error below 0,005 radians )
inline double qwtFastAtan2( double y, double x )
{
if ( x > 0 )
return qwtFastAtan( y / x );
if ( x < 0 )
{
const double d = qwtFastAtan( y / x );
return ( y >= 0 ) ? d + M_PI : d - M_PI;
}
if ( y < 0.0 )
return -M_PI_2;
if ( y > 0.0 )
return M_PI_2;
return 0.0;
}
//! Translate degrees into radians
inline double qwtRadians( double degrees )
{
return degrees * M_PI / 180.0;
}
//! Translate radians into degrees
inline double qwtDegrees( double degrees )
{
return degrees * 180.0 / M_PI;
}
#endif

View File

@@ -0,0 +1,298 @@
/* -*- 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_matrix_raster_data.h"
#include <qnumeric.h>
#include <qmath.h>
class QwtMatrixRasterData::PrivateData
{
public:
PrivateData():
resampleMode(QwtMatrixRasterData::NearestNeighbour),
numColumns(0)
{
}
inline double value(int row, int col) const
{
return values.data()[ row * numColumns + col ];
}
QwtMatrixRasterData::ResampleMode resampleMode;
QVector<double> values;
int numColumns;
int numRows;
double dx;
double dy;
};
//! Constructor
QwtMatrixRasterData::QwtMatrixRasterData()
{
d_data = new PrivateData();
update();
}
//! Destructor
QwtMatrixRasterData::~QwtMatrixRasterData()
{
delete d_data;
}
/*!
\brief Set the resampling algorithm
\param mode Resampling mode
\sa resampleMode(), value()
*/
void QwtMatrixRasterData::setResampleMode( ResampleMode mode )
{
d_data->resampleMode = mode;
}
/*!
\return resampling algorithm
\sa setResampleMode(), value()
*/
QwtMatrixRasterData::ResampleMode QwtMatrixRasterData::resampleMode() const
{
return d_data->resampleMode;
}
/*!
\brief Assign the bounding interval for an axis
Setting the bounding intervals for the X/Y axis is mandatory
to define the positions for the values of the value matrix.
The interval in Z direction defines the possible range for
the values in the matrix, what is f.e used by QwtPlotSpectrogram
to map values to colors. The Z-interval might be the bounding
interval of the values in the matrix, but usually it isn't.
( f.e a interval of 0.0-100.0 for values in percentage )
\param axis X, Y or Z axis
\param interval Interval
\sa QwtRasterData::interval(), setValueMatrix()
*/
void QwtMatrixRasterData::setInterval(
Qt::Axis axis, const QwtInterval &interval )
{
QwtRasterData::setInterval( axis, interval );
update();
}
/*!
\brief Assign a value matrix
The positions of the values are calculated by dividing
the bounding rectangle of the X/Y intervals into equidistant
rectangles ( pixels ). Each value corresponds to the center of
a pixel.
\param values Vector of values
\param numColumns Number of columns
\sa valueMatrix(), numColumns(), numRows(), setInterval()()
*/
void QwtMatrixRasterData::setValueMatrix(
const QVector<double> &values, int numColumns )
{
d_data->values = values;
d_data->numColumns = qMax( numColumns, 0 );
update();
}
/*!
\return Value matrix
\sa setValueMatrix(), numColumns(), numRows(), setInterval()
*/
const QVector<double> QwtMatrixRasterData::valueMatrix() const
{
return d_data->values;
}
/*!
\brief Change a single value in the matrix
\param row Row index
\param col Column index
\param value New value
\sa value(), setValueMatrix()
*/
void QwtMatrixRasterData::setValue( int row, int col, double value )
{
if ( row >= 0 && row < d_data->numRows &&
col >= 0 && col < d_data->numColumns )
{
const int index = row * d_data->numColumns + col;
d_data->values.data()[ index ] = value;
}
}
/*!
\return Number of columns of the value matrix
\sa valueMatrix(), numRows(), setValueMatrix()
*/
int QwtMatrixRasterData::numColumns() const
{
return d_data->numColumns;
}
/*!
\return Number of rows of the value matrix
\sa valueMatrix(), numColumns(), setValueMatrix()
*/
int QwtMatrixRasterData::numRows() const
{
return d_data->numRows;
}
/*!
\brief Calculate the pixel hint
pixelHint() returns the geometry of a pixel, that can be used
to calculate the resolution and alignment of the plot item, that is
representing the data.
- NearestNeighbour\n
pixelHint() returns the surrounding pixel of the top left value
in the matrix.
- BilinearInterpolation\n
Returns an empty rectangle recommending
to render in target device ( f.e. screen ) resolution.
\param area Requested area, ignored
\return Calculated hint
\sa ResampleMode, setMatrix(), setInterval()
*/
QRectF QwtMatrixRasterData::pixelHint( const QRectF &area ) const
{
Q_UNUSED( area )
QRectF rect;
if ( d_data->resampleMode == NearestNeighbour )
{
const QwtInterval intervalX = interval( Qt::XAxis );
const QwtInterval intervalY = interval( Qt::YAxis );
if ( intervalX.isValid() && intervalY.isValid() )
{
rect = QRectF( intervalX.minValue(), intervalY.minValue(),
d_data->dx, d_data->dy );
}
}
return rect;
}
/*!
\return the value at a raster position
\param x X value in plot coordinates
\param y Y value in plot coordinates
\sa ResampleMode
*/
double QwtMatrixRasterData::value( double x, double y ) const
{
const QwtInterval xInterval = interval( Qt::XAxis );
const QwtInterval yInterval = interval( Qt::YAxis );
if ( !( xInterval.contains(x) && yInterval.contains(y) ) )
return qQNaN();
double value;
switch( d_data->resampleMode )
{
case BilinearInterpolation:
{
int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1;
int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1;
int col2 = col1 + 1;
int row2 = row1 + 1;
if ( col1 < 0 )
col1 = col2;
else if ( col2 >= static_cast<int>( d_data->numColumns ) )
col2 = col1;
if ( row1 < 0 )
row1 = row2;
else if ( row2 >= static_cast<int>( d_data->numRows ) )
row2 = row1;
const double v11 = d_data->value( row1, col1 );
const double v21 = d_data->value( row1, col2 );
const double v12 = d_data->value( row2, col1 );
const double v22 = d_data->value( row2, col2 );
const double x2 = xInterval.minValue() +
( col2 + 0.5 ) * d_data->dx;
const double y2 = yInterval.minValue() +
( row2 + 0.5 ) * d_data->dy;
const double rx = ( x2 - x ) / d_data->dx;
const double ry = ( y2 - y ) / d_data->dy;
const double vr1 = rx * v11 + ( 1.0 - rx ) * v21;
const double vr2 = rx * v12 + ( 1.0 - rx ) * v22;
value = ry * vr1 + ( 1.0 - ry ) * vr2;
break;
}
case NearestNeighbour:
default:
{
int row = int( (y - yInterval.minValue() ) / d_data->dy );
int col = int( (x - xInterval.minValue() ) / d_data->dx );
// In case of intervals, where the maximum is included
// we get out of bound for row/col, when the value for the
// maximum is requested. Instead we return the value
// from the last row/col
if ( row >= d_data->numRows )
row = d_data->numRows - 1;
if ( col >= d_data->numColumns )
col = d_data->numColumns - 1;
value = d_data->value( row, col );
}
}
return value;
}
void QwtMatrixRasterData::update()
{
d_data->numRows = 0;
d_data->dx = 0.0;
d_data->dy = 0.0;
if ( d_data->numColumns > 0 )
{
d_data->numRows = d_data->values.size() / d_data->numColumns;
const QwtInterval xInterval = interval( Qt::XAxis );
const QwtInterval yInterval = interval( Qt::YAxis );
if ( xInterval.isValid() )
d_data->dx = xInterval.width() / d_data->numColumns;
if ( yInterval.isValid() )
d_data->dy = yInterval.width() / d_data->numRows;
}
}

View File

@@ -0,0 +1,74 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_MATRIX_RASTER_DATA_H
#define QWT_MATRIX_RASTER_DATA_H 1
#include "qwt_global.h"
#include "qwt_raster_data.h"
#include <qvector.h>
/*!
\brief A class representing a matrix of values as raster data
QwtMatrixRasterData implements an interface for a matrix of
equidistant values, that can be used by a QwtPlotRasterItem.
It implements a couple of resampling algorithms, to provide
values for positions, that or not on the value matrix.
*/
class QWT_EXPORT QwtMatrixRasterData: public QwtRasterData
{
public:
/*!
\brief Resampling algorithm
The default setting is NearestNeighbour;
*/
enum ResampleMode
{
/*!
Return the value from the matrix, that is nearest to the
the requested position.
*/
NearestNeighbour,
/*!
Interpolate the value from the distances and values of the
4 surrounding values in the matrix,
*/
BilinearInterpolation
};
QwtMatrixRasterData();
virtual ~QwtMatrixRasterData();
void setResampleMode(ResampleMode mode);
ResampleMode resampleMode() const;
virtual void setInterval( Qt::Axis, const QwtInterval & );
void setValueMatrix( const QVector<double> &values, int numColumns );
const QVector<double> valueMatrix() const;
void setValue( int row, int col, double value );
int numColumns() const;
int numRows() const;
virtual QRectF pixelHint( const QRectF & ) const;
virtual double value( double x, double y ) const;
private:
void update();
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,593 @@
/* -*- 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_null_paintdevice.h"
#include <qpaintengine.h>
#include <qpixmap.h>
class QwtNullPaintDevice::PrivateData
{
public:
PrivateData():
mode( QwtNullPaintDevice::NormalMode )
{
}
QwtNullPaintDevice::Mode mode;
};
class QwtNullPaintDevice::PaintEngine: public QPaintEngine
{
public:
PaintEngine();
virtual bool begin( QPaintDevice * );
virtual bool end();
virtual Type type () const;
virtual void updateState(const QPaintEngineState &);
virtual void drawRects(const QRect *, int );
virtual void drawRects(const QRectF *, int );
virtual void drawLines(const QLine *, int );
virtual void drawLines(const QLineF *, int );
virtual void drawEllipse(const QRectF &);
virtual void drawEllipse(const QRect &);
virtual void drawPath(const QPainterPath &);
virtual void drawPoints(const QPointF *, int );
virtual void drawPoints(const QPoint *, int );
virtual void drawPolygon(const QPointF *, int , PolygonDrawMode );
virtual void drawPolygon(const QPoint *, int , PolygonDrawMode );
virtual void drawPixmap(const QRectF &,
const QPixmap &, const QRectF &);
virtual void drawTextItem(const QPointF &, const QTextItem &);
virtual void drawTiledPixmap(const QRectF &,
const QPixmap &, const QPointF &s);
virtual void drawImage(const QRectF &,
const QImage &, const QRectF &, Qt::ImageConversionFlags );
private:
QwtNullPaintDevice *nullDevice();
};
QwtNullPaintDevice::PaintEngine::PaintEngine():
QPaintEngine( QPaintEngine::AllFeatures )
{
}
bool QwtNullPaintDevice::PaintEngine::begin( QPaintDevice * )
{
setActive( true );
return true;
}
bool QwtNullPaintDevice::PaintEngine::end()
{
setActive( false );
return true;
}
QPaintEngine::Type QwtNullPaintDevice::PaintEngine::type() const
{
return QPaintEngine::User;
}
void QwtNullPaintDevice::PaintEngine::drawRects(
const QRect *rects, int rectCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawRects( rects, rectCount );
return;
}
device->drawRects( rects, rectCount );
}
void QwtNullPaintDevice::PaintEngine::drawRects(
const QRectF *rects, int rectCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawRects( rects, rectCount );
return;
}
device->drawRects( rects, rectCount );
}
void QwtNullPaintDevice::PaintEngine::drawLines(
const QLine *lines, int lineCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawLines( lines, lineCount );
return;
}
device->drawLines( lines, lineCount );
}
void QwtNullPaintDevice::PaintEngine::drawLines(
const QLineF *lines, int lineCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawLines( lines, lineCount );
return;
}
device->drawLines( lines, lineCount );
}
void QwtNullPaintDevice::PaintEngine::drawEllipse(
const QRectF &rect)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawEllipse( rect );
return;
}
device->drawEllipse( rect );
}
void QwtNullPaintDevice::PaintEngine::drawEllipse(
const QRect &rect)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawEllipse( rect );
return;
}
device->drawEllipse( rect );
}
void QwtNullPaintDevice::PaintEngine::drawPath(
const QPainterPath &path)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
device->drawPath( path );
}
void QwtNullPaintDevice::PaintEngine::drawPoints(
const QPointF *points, int pointCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawPoints( points, pointCount );
return;
}
device->drawPoints( points, pointCount );
}
void QwtNullPaintDevice::PaintEngine::drawPoints(
const QPoint *points, int pointCount)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawPoints( points, pointCount );
return;
}
device->drawPoints( points, pointCount );
}
void QwtNullPaintDevice::PaintEngine::drawPolygon(
const QPointF *points, int pointCount, PolygonDrawMode mode)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() == QwtNullPaintDevice::PathMode )
{
QPainterPath path;
if ( pointCount > 0 )
{
path.moveTo( points[0] );
for ( int i = 1; i < pointCount; i++ )
path.lineTo( points[i] );
if ( mode != PolylineMode )
path.closeSubpath();
}
device->drawPath( path );
return;
}
device->drawPolygon( points, pointCount, mode );
}
void QwtNullPaintDevice::PaintEngine::drawPolygon(
const QPoint *points, int pointCount, PolygonDrawMode mode)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() == QwtNullPaintDevice::PathMode )
{
QPainterPath path;
if ( pointCount > 0 )
{
path.moveTo( points[0] );
for ( int i = 1; i < pointCount; i++ )
path.lineTo( points[i] );
if ( mode != PolylineMode )
path.closeSubpath();
}
device->drawPath( path );
return;
}
device->drawPolygon( points, pointCount, mode );
}
void QwtNullPaintDevice::PaintEngine::drawPixmap(
const QRectF &rect, const QPixmap &pm, const QRectF &subRect )
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
device->drawPixmap( rect, pm, subRect );
}
void QwtNullPaintDevice::PaintEngine::drawTextItem(
const QPointF &pos, const QTextItem &textItem)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawTextItem( pos, textItem );
return;
}
device->drawTextItem( pos, textItem );
}
void QwtNullPaintDevice::PaintEngine::drawTiledPixmap(
const QRectF &rect, const QPixmap &pixmap,
const QPointF &subRect)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
if ( device->mode() != QwtNullPaintDevice::NormalMode )
{
QPaintEngine::drawTiledPixmap( rect, pixmap, subRect );
return;
}
device->drawTiledPixmap( rect, pixmap, subRect );
}
void QwtNullPaintDevice::PaintEngine::drawImage(
const QRectF &rect, const QImage &image,
const QRectF &subRect, Qt::ImageConversionFlags flags)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
device->drawImage( rect, image, subRect, flags );
}
void QwtNullPaintDevice::PaintEngine::updateState(
const QPaintEngineState &state)
{
QwtNullPaintDevice *device = nullDevice();
if ( device == NULL )
return;
device->updateState( state );
}
inline QwtNullPaintDevice *QwtNullPaintDevice::PaintEngine::nullDevice()
{
if ( !isActive() )
return NULL;
return static_cast<QwtNullPaintDevice *>( paintDevice() );
}
//! Constructor
QwtNullPaintDevice::QwtNullPaintDevice():
d_engine( NULL )
{
d_data = new PrivateData;
}
//! Destructor
QwtNullPaintDevice::~QwtNullPaintDevice()
{
delete d_engine;
delete d_data;
}
/*!
Set the render mode
\param mode New mode
\sa mode()
*/
void QwtNullPaintDevice::setMode( Mode mode )
{
d_data->mode = mode;
}
/*!
\return Render mode
\sa setMode()
*/
QwtNullPaintDevice::Mode QwtNullPaintDevice::mode() const
{
return d_data->mode;
}
//! See QPaintDevice::paintEngine()
QPaintEngine *QwtNullPaintDevice::paintEngine() const
{
if ( d_engine == NULL )
{
QwtNullPaintDevice *that =
const_cast< QwtNullPaintDevice * >( this );
that->d_engine = new PaintEngine();
}
return d_engine;
}
/*!
See QPaintDevice::metric()
\param deviceMetric Type of metric
\return Metric information for the given paint device metric.
\sa sizeMetrics()
*/
int QwtNullPaintDevice::metric( PaintDeviceMetric deviceMetric ) const
{
int value;
switch ( deviceMetric )
{
case PdmWidth:
{
value = sizeMetrics().width();
break;
}
case PdmHeight:
{
value = sizeMetrics().height();
break;
}
case PdmNumColors:
{
value = 0xffffffff;
break;
}
case PdmDepth:
{
value = 32;
break;
}
case PdmPhysicalDpiX:
case PdmPhysicalDpiY:
case PdmDpiY:
case PdmDpiX:
{
value = 72;
break;
}
case PdmWidthMM:
{
value = qRound( metric( PdmWidth ) * 25.4 / metric( PdmDpiX ) );
break;
}
case PdmHeightMM:
{
value = qRound( metric( PdmHeight ) * 25.4 / metric( PdmDpiY ) );
break;
}
default:
value = 0;
}
return value;
}
//! See QPaintEngine::drawRects()
void QwtNullPaintDevice::drawRects(
const QRect *rects, int rectCount)
{
Q_UNUSED(rects);
Q_UNUSED(rectCount);
}
//! See QPaintEngine::drawRects()
void QwtNullPaintDevice::drawRects(
const QRectF *rects, int rectCount)
{
Q_UNUSED(rects);
Q_UNUSED(rectCount);
}
//! See QPaintEngine::drawLines()
void QwtNullPaintDevice::drawLines(
const QLine *lines, int lineCount)
{
Q_UNUSED(lines);
Q_UNUSED(lineCount);
}
//! See QPaintEngine::drawLines()
void QwtNullPaintDevice::drawLines(
const QLineF *lines, int lineCount)
{
Q_UNUSED(lines);
Q_UNUSED(lineCount);
}
//! See QPaintEngine::drawEllipse()
void QwtNullPaintDevice::drawEllipse( const QRectF &rect )
{
Q_UNUSED(rect);
}
//! See QPaintEngine::drawEllipse()
void QwtNullPaintDevice::drawEllipse( const QRect &rect )
{
Q_UNUSED(rect);
}
//! See QPaintEngine::drawPath()
void QwtNullPaintDevice::drawPath( const QPainterPath &path )
{
Q_UNUSED(path);
}
//! See QPaintEngine::drawPoints()
void QwtNullPaintDevice::drawPoints(
const QPointF *points, int pointCount)
{
Q_UNUSED(points);
Q_UNUSED(pointCount);
}
//! See QPaintEngine::drawPoints()
void QwtNullPaintDevice::drawPoints(
const QPoint *points, int pointCount)
{
Q_UNUSED(points);
Q_UNUSED(pointCount);
}
//! See QPaintEngine::drawPolygon()
void QwtNullPaintDevice::drawPolygon(
const QPointF *points, int pointCount,
QPaintEngine::PolygonDrawMode mode)
{
Q_UNUSED(points);
Q_UNUSED(pointCount);
Q_UNUSED(mode);
}
//! See QPaintEngine::drawPolygon()
void QwtNullPaintDevice::drawPolygon(
const QPoint *points, int pointCount,
QPaintEngine::PolygonDrawMode mode)
{
Q_UNUSED(points);
Q_UNUSED(pointCount);
Q_UNUSED(mode);
}
//! See QPaintEngine::drawPixmap()
void QwtNullPaintDevice::drawPixmap( const QRectF &rect,
const QPixmap &pm, const QRectF &subRect )
{
Q_UNUSED(rect);
Q_UNUSED(pm);
Q_UNUSED(subRect);
}
//! See QPaintEngine::drawTextItem()
void QwtNullPaintDevice::drawTextItem(
const QPointF &pos, const QTextItem &textItem)
{
Q_UNUSED(pos);
Q_UNUSED(textItem);
}
//! See QPaintEngine::drawTiledPixmap()
void QwtNullPaintDevice::drawTiledPixmap(
const QRectF &rect, const QPixmap &pixmap,
const QPointF &subRect)
{
Q_UNUSED(rect);
Q_UNUSED(pixmap);
Q_UNUSED(subRect);
}
//! See QPaintEngine::drawImage()
void QwtNullPaintDevice::drawImage(
const QRectF &rect, const QImage &image,
const QRectF &subRect, Qt::ImageConversionFlags flags)
{
Q_UNUSED(rect);
Q_UNUSED(image);
Q_UNUSED(subRect);
Q_UNUSED(flags);
}
//! See QPaintEngine::updateState()
void QwtNullPaintDevice::updateState(
const QPaintEngineState &state )
{
Q_UNUSED(state);
}

View File

@@ -0,0 +1,126 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_NULL_PAINT_DEVICE_H
#define QWT_NULL_PAINT_DEVICE_H 1
#include "qwt_global.h"
#include <qpaintdevice.h>
#include <qpaintengine.h>
/*!
\brief A null paint device doing nothing
Sometimes important layout/rendering geometries are not
available or changeable from the public Qt class interface.
( f.e hidden in the style implementation ).
QwtNullPaintDevice can be used to manipulate or filter out
this information by analyzing the stream of paint primitives.
F.e. QwtNullPaintDevice is used by QwtPlotCanvas to identify
styled backgrounds with rounded corners.
*/
class QWT_EXPORT QwtNullPaintDevice: public QPaintDevice
{
public:
/*!
\brief Render mode
\sa setMode(), mode()
*/
enum Mode
{
/*!
All vector graphic primitives are painted by
the corresponding draw methods
*/
NormalMode,
/*!
Vector graphic primitives ( beside polygons ) are mapped to a QPainterPath
and are painted by drawPath. In PathMode mode
only a few draw methods are called:
- drawPath()
- drawPixmap()
- drawImage()
- drawPolygon()
*/
PolygonPathMode,
/*!
Vector graphic primitives are mapped to a QPainterPath
and are painted by drawPath. In PathMode mode
only a few draw methods are called:
- drawPath()
- drawPixmap()
- drawImage()
*/
PathMode
};
QwtNullPaintDevice();
virtual ~QwtNullPaintDevice();
void setMode( Mode );
Mode mode() const;
virtual QPaintEngine *paintEngine() const;
virtual int metric( PaintDeviceMetric metric ) const;
virtual void drawRects(const QRect *, int );
virtual void drawRects(const QRectF *, int );
virtual void drawLines(const QLine *, int );
virtual void drawLines(const QLineF *, int );
virtual void drawEllipse(const QRectF &);
virtual void drawEllipse(const QRect &);
virtual void drawPath(const QPainterPath &);
virtual void drawPoints(const QPointF *, int );
virtual void drawPoints(const QPoint *, int );
virtual void drawPolygon(
const QPointF *, int , QPaintEngine::PolygonDrawMode );
virtual void drawPolygon(
const QPoint *, int , QPaintEngine::PolygonDrawMode );
virtual void drawPixmap(const QRectF &,
const QPixmap &, const QRectF &);
virtual void drawTextItem(const QPointF &, const QTextItem &);
virtual void drawTiledPixmap(const QRectF &,
const QPixmap &, const QPointF &s);
virtual void drawImage(const QRectF &,
const QImage &, const QRectF &, Qt::ImageConversionFlags );
virtual void updateState( const QPaintEngineState &state );
protected:
//! \return Size needed to implement metric()
virtual QSize sizeMetrics() const = 0;
private:
class PaintEngine;
PaintEngine *d_engine;
class PrivateData;
PrivateData *d_data;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PAINTER_H
#define QWT_PAINTER_H
#include "qwt_global.h"
#include <qpoint.h>
#include <qrect.h>
#include <qpen.h>
#include <qline.h>
#include <qpalette.h>
class QPainter;
class QBrush;
class QColor;
class QWidget;
class QPolygonF;
class QRectF;
class QImage;
class QPixmap;
class QwtScaleMap;
class QwtColorMap;
class QwtInterval;
class QTextDocument;
class QPainterPath;
/*!
\brief A collection of QPainter workarounds
*/
class QWT_EXPORT QwtPainter
{
public:
static void setPolylineSplitting( bool );
static bool polylineSplitting();
static void setRoundingAlignment( bool );
static bool roundingAlignment();
static bool roundingAlignment(QPainter *);
static void drawText( QPainter *, double x, double y, const QString & );
static void drawText( QPainter *, const QPointF &, const QString & );
static void drawText( QPainter *, double x, double y, double w, double h,
int flags, const QString & );
static void drawText( QPainter *, const QRectF &,
int flags, const QString & );
#ifndef QT_NO_RICHTEXT
static void drawSimpleRichText( QPainter *, const QRectF &,
int flags, const QTextDocument & );
#endif
static void drawRect( QPainter *, double x, double y, double w, double h );
static void drawRect( QPainter *, const QRectF &rect );
static void fillRect( QPainter *, const QRectF &, const QBrush & );
static void drawEllipse( QPainter *, const QRectF & );
static void drawPie( QPainter *, const QRectF & r, int a, int alen );
static void drawLine( QPainter *, double x1, double y1, double x2, double y2 );
static void drawLine( QPainter *, const QPointF &p1, const QPointF &p2 );
static void drawLine( QPainter *, const QLineF & );
static void drawPolygon( QPainter *, const QPolygonF & );
static void drawPolyline( QPainter *, const QPolygonF & );
static void drawPolyline( QPainter *, const QPointF *, int pointCount );
static void drawPolygon( QPainter *, const QPolygon & );
static void drawPolyline( QPainter *, const QPolygon & );
static void drawPolyline( QPainter *, const QPoint *, int pointCount );
static void drawPoint( QPainter *, const QPoint & );
static void drawPoints( QPainter *, const QPolygon & );
static void drawPoints( QPainter *, const QPoint *, int pointCount );
static void drawPoint( QPainter *, double x, double y );
static void drawPoint( QPainter *, const QPointF & );
static void drawPoints( QPainter *, const QPolygonF & );
static void drawPoints( QPainter *, const QPointF *, int pointCount );
static void drawPath( QPainter *, const QPainterPath & );
static void drawImage( QPainter *, const QRectF &, const QImage & );
static void drawPixmap( QPainter *, const QRectF &, const QPixmap & );
static void drawRoundFrame( QPainter *,
const QRectF &, const QPalette &, int lineWidth, int frameStyle );
static void drawRoundedFrame( QPainter *,
const QRectF &, double xRadius, double yRadius,
const QPalette &, int lineWidth, int frameStyle );
static void drawFrame( QPainter *, const QRectF &rect,
const QPalette &palette, QPalette::ColorRole foregroundRole,
int lineWidth, int midLineWidth, int frameStyle );
static void drawFocusRect( QPainter *, const QWidget * );
static void drawFocusRect( QPainter *, const QWidget *, const QRect & );
static void drawColorBar( QPainter *painter,
const QwtColorMap &, const QwtInterval &,
const QwtScaleMap &, Qt::Orientation, const QRectF & );
static bool isAligning( QPainter *painter );
static bool isX11GraphicsSystem();
static void fillPixmap( const QWidget *,
QPixmap &, const QPoint &offset = QPoint() );
static void drawBackgound( QPainter *painter,
const QRectF &rect, const QWidget *widget );
static QPixmap backingStore( QWidget *, const QSize & );
private:
static bool d_polylineSplitting;
static bool d_roundingAlignment;
};
//! Wrapper for QPainter::drawPoint()
inline void QwtPainter::drawPoint( QPainter *painter, double x, double y )
{
QwtPainter::drawPoint( painter, QPointF( x, y ) );
}
//! Wrapper for QPainter::drawPoints()
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygon &polygon )
{
drawPoints( painter, polygon.data(), polygon.size() );
}
//! Wrapper for QPainter::drawPoints()
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygonF &polygon )
{
drawPoints( painter, polygon.data(), polygon.size() );
}
//! Wrapper for QPainter::drawLine()
inline void QwtPainter::drawLine( QPainter *painter,
double x1, double y1, double x2, double y2 )
{
QwtPainter::drawLine( painter, QPointF( x1, y1 ), QPointF( x2, y2 ) );
}
//! Wrapper for QPainter::drawLine()
inline void QwtPainter::drawLine( QPainter *painter, const QLineF &line )
{
QwtPainter::drawLine( painter, line.p1(), line.p2() );
}
/*!
\return True, when line splitting for the raster paint engine is enabled.
\sa setPolylineSplitting()
*/
inline bool QwtPainter::polylineSplitting()
{
return d_polylineSplitting;
}
/*!
Check whether coordinates should be rounded, before they are painted
to a paint engine that rounds to integer values. For other paint engines
( PDF, SVG ), this flag has no effect.
\return True, when rounding is enabled
\sa setRoundingAlignment(), isAligning()
*/
inline bool QwtPainter::roundingAlignment()
{
return d_roundingAlignment;
}
/*!
\return roundingAlignment() && isAligning(painter);
\param painter Painter
*/
inline bool QwtPainter::roundingAlignment(QPainter *painter)
{
return d_roundingAlignment && isAligning(painter);
}
#endif

View File

@@ -0,0 +1,237 @@
/* -*- 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_command.h"
//! Construct an invalid command
QwtPainterCommand::QwtPainterCommand():
d_type( Invalid )
{
}
//! Copy constructor
QwtPainterCommand::QwtPainterCommand( const QPainterPath &path ):
d_type( Path )
{
d_path = new QPainterPath( path );
}
/*!
Constructor for Pixmap paint operation
\param rect Target rectangle
\param pixmap Pixmap
\param subRect Rectangle inside the pixmap
\sa QPainter::drawPixmap()
*/
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
const QPixmap &pixmap, const QRectF& subRect ):
d_type( Pixmap )
{
d_pixmapData = new PixmapData();
d_pixmapData->rect = rect;
d_pixmapData->pixmap = pixmap;
d_pixmapData->subRect = subRect;
}
/*!
Constructor for Image paint operation
\param rect Target rectangle
\param image Image
\param subRect Rectangle inside the image
\param flags Conversion flags
\sa QPainter::drawImage()
*/
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
const QImage &image, const QRectF& subRect,
Qt::ImageConversionFlags flags ):
d_type( Image )
{
d_imageData = new ImageData();
d_imageData->rect = rect;
d_imageData->image = image;
d_imageData->subRect = subRect;
d_imageData->flags = flags;
}
/*!
Constructor for State paint operation
\param state Paint engine state
*/
QwtPainterCommand::QwtPainterCommand( const QPaintEngineState &state ):
d_type( State )
{
d_stateData = new StateData();
d_stateData->flags = state.state();
if ( d_stateData->flags & QPaintEngine::DirtyPen )
d_stateData->pen = state.pen();
if ( d_stateData->flags & QPaintEngine::DirtyBrush )
d_stateData->brush = state.brush();
if ( d_stateData->flags & QPaintEngine::DirtyBrushOrigin )
d_stateData->brushOrigin = state.brushOrigin();
if ( d_stateData->flags & QPaintEngine::DirtyFont )
d_stateData->font = state.font();
if ( d_stateData->flags & QPaintEngine::DirtyBackground )
{
d_stateData->backgroundMode = state.backgroundMode();
d_stateData->backgroundBrush = state.backgroundBrush();
}
if ( d_stateData->flags & QPaintEngine::DirtyTransform )
d_stateData->transform = state.transform();
if ( d_stateData->flags & QPaintEngine::DirtyClipEnabled )
d_stateData->isClipEnabled = state.isClipEnabled();
if ( d_stateData->flags & QPaintEngine::DirtyClipRegion )
{
d_stateData->clipRegion = state.clipRegion();
d_stateData->clipOperation = state.clipOperation();
}
if ( d_stateData->flags & QPaintEngine::DirtyClipPath )
{
d_stateData->clipPath = state.clipPath();
d_stateData->clipOperation = state.clipOperation();
}
if ( d_stateData->flags & QPaintEngine::DirtyHints )
d_stateData->renderHints = state.renderHints();
if ( d_stateData->flags & QPaintEngine::DirtyCompositionMode )
d_stateData->compositionMode = state.compositionMode();
if ( d_stateData->flags & QPaintEngine::DirtyOpacity )
d_stateData->opacity = state.opacity();
}
/*!
Copy constructor
\param other Command to be copied
*/
QwtPainterCommand::QwtPainterCommand(const QwtPainterCommand &other)
{
copy( other );
}
//! Destructor
QwtPainterCommand::~QwtPainterCommand()
{
reset();
}
/*!
Assignment operator
\param other Command to be copied
\return Modified command
*/
QwtPainterCommand &QwtPainterCommand::operator=(const QwtPainterCommand &other)
{
reset();
copy( other );
return *this;
}
void QwtPainterCommand::copy( const QwtPainterCommand &other )
{
d_type = other.d_type;
switch( other.d_type )
{
case Path:
{
d_path = new QPainterPath( *other.d_path );
break;
}
case Pixmap:
{
d_pixmapData = new PixmapData( *other.d_pixmapData );
break;
}
case Image:
{
d_imageData = new ImageData( *other.d_imageData );
break;
}
case State:
{
d_stateData = new StateData( *other.d_stateData );
break;
}
default:
break;
}
}
void QwtPainterCommand::reset()
{
switch( d_type )
{
case Path:
{
delete d_path;
break;
}
case Pixmap:
{
delete d_pixmapData;
break;
}
case Image:
{
delete d_imageData;
break;
}
case State:
{
delete d_stateData;
break;
}
default:
break;
}
d_type = Invalid;
}
//! \return Painter path to be painted
QPainterPath *QwtPainterCommand::path()
{
return d_path;
}
//! \return Attributes how to paint a QPixmap
QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData()
{
return d_pixmapData;
}
//! \return Attributes how to paint a QImage
QwtPainterCommand::ImageData* QwtPainterCommand::imageData()
{
return d_imageData;
}
//! \return Attributes of a state change
QwtPainterCommand::StateData* QwtPainterCommand::stateData()
{
return d_stateData;
}

View File

@@ -0,0 +1,173 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PAINTER_COMMAND_H
#define QWT_PAINTER_COMMAND_H
#include "qwt_global.h"
#include <qpaintengine.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qpolygon.h>
class QPainterPath;
/*!
QwtPainterCommand represents the attributes of a paint operation
how it is used between QPainter and QPaintDevice
It is used by QwtGraphic to record and replay paint operations
\sa QwtGraphic::commands()
*/
class QWT_EXPORT QwtPainterCommand
{
public:
//! Type of the paint command
enum Type
{
//! Invalid command
Invalid = -1,
//! Draw a QPainterPath
Path,
//! Draw a QPixmap
Pixmap,
//! Draw a QImage
Image,
//! QPainter state change
State
};
//! Attributes how to paint a QPixmap
struct PixmapData
{
QRectF rect;
QPixmap pixmap;
QRectF subRect;
};
//! Attributes how to paint a QImage
struct ImageData
{
QRectF rect;
QImage image;
QRectF subRect;
Qt::ImageConversionFlags flags;
};
//! Attributes of a state change
struct StateData
{
QPaintEngine::DirtyFlags flags;
QPen pen;
QBrush brush;
QPointF brushOrigin;
QBrush backgroundBrush;
Qt::BGMode backgroundMode;
QFont font;
QMatrix matrix;
QTransform transform;
Qt::ClipOperation clipOperation;
QRegion clipRegion;
QPainterPath clipPath;
bool isClipEnabled;
QPainter::RenderHints renderHints;
QPainter::CompositionMode compositionMode;
qreal opacity;
};
QwtPainterCommand();
QwtPainterCommand(const QwtPainterCommand &);
QwtPainterCommand( const QPainterPath & );
QwtPainterCommand( const QRectF &rect,
const QPixmap &, const QRectF& subRect );
QwtPainterCommand( const QRectF &rect,
const QImage &, const QRectF& subRect,
Qt::ImageConversionFlags );
QwtPainterCommand( const QPaintEngineState & );
~QwtPainterCommand();
QwtPainterCommand &operator=(const QwtPainterCommand & );
Type type() const;
QPainterPath *path();
const QPainterPath *path() const;
PixmapData* pixmapData();
const PixmapData* pixmapData() const;
ImageData* imageData();
const ImageData* imageData() const;
StateData* stateData();
const StateData* stateData() const;
private:
void copy( const QwtPainterCommand & );
void reset();
Type d_type;
union
{
QPainterPath *d_path;
PixmapData *d_pixmapData;
ImageData *d_imageData;
StateData *d_stateData;
};
};
//! \return Type of the command
inline QwtPainterCommand::Type QwtPainterCommand::type() const
{
return d_type;
}
//! \return Painter path to be painted
inline const QPainterPath *QwtPainterCommand::path() const
{
return d_path;
}
//! \return Attributes how to paint a QPixmap
inline const QwtPainterCommand::PixmapData*
QwtPainterCommand::pixmapData() const
{
return d_pixmapData;
}
//! \return Attributes how to paint a QImage
inline const QwtPainterCommand::ImageData *
QwtPainterCommand::imageData() const
{
return d_imageData;
}
//! \return Attributes of a state change
inline const QwtPainterCommand::StateData *
QwtPainterCommand::stateData() const
{
return d_stateData;
}
#endif

View File

@@ -0,0 +1,538 @@
/* -*- 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_panner.h"
#include "qwt_picker.h"
#include "qwt_painter.h"
#include <qpainter.h>
#include <qpixmap.h>
#include <qevent.h>
#include <qcursor.h>
#include <qbitmap.h>
static QVector<QwtPicker *> qwtActivePickers( QWidget *w )
{
QVector<QwtPicker *> pickers;
QObjectList children = w->children();
for ( int i = 0; i < children.size(); i++ )
{
QwtPicker *picker = qobject_cast<QwtPicker *>( children[i] );
if ( picker && picker->isEnabled() )
pickers += picker;
}
return pickers;
}
class QwtPanner::PrivateData
{
public:
PrivateData():
button( Qt::LeftButton ),
buttonModifiers( Qt::NoModifier ),
abortKey( Qt::Key_Escape ),
abortKeyModifiers( Qt::NoModifier ),
#ifndef QT_NO_CURSOR
cursor( NULL ),
restoreCursor( NULL ),
hasCursor( false ),
#endif
isEnabled( false )
{
orientations = Qt::Vertical | Qt::Horizontal;
}
~PrivateData()
{
#ifndef QT_NO_CURSOR
delete cursor;
delete restoreCursor;
#endif
}
Qt::MouseButton button;
Qt::KeyboardModifiers buttonModifiers;
int abortKey;
Qt::KeyboardModifiers abortKeyModifiers;
QPoint initialPos;
QPoint pos;
QPixmap pixmap;
QBitmap contentsMask;
#ifndef QT_NO_CURSOR
QCursor *cursor;
QCursor *restoreCursor;
bool hasCursor;
#endif
bool isEnabled;
Qt::Orientations orientations;
};
/*!
Creates an panner that is enabled for the left mouse button.
\param parent Parent widget to be panned
*/
QwtPanner::QwtPanner( QWidget *parent ):
QWidget( parent )
{
d_data = new PrivateData();
setAttribute( Qt::WA_TransparentForMouseEvents );
setAttribute( Qt::WA_NoSystemBackground );
setFocusPolicy( Qt::NoFocus );
hide();
setEnabled( true );
}
//! Destructor
QwtPanner::~QwtPanner()
{
delete d_data;
}
/*!
Change the mouse button and modifiers used for panning
The defaults are Qt::LeftButton and Qt::NoModifier
*/
void QwtPanner::setMouseButton( Qt::MouseButton button,
Qt::KeyboardModifiers modifiers )
{
d_data->button = button;
d_data->buttonModifiers = modifiers;
}
//! Get mouse button and modifiers used for panning
void QwtPanner::getMouseButton( Qt::MouseButton &button,
Qt::KeyboardModifiers &modifiers ) const
{
button = d_data->button;
modifiers = d_data->buttonModifiers;
}
/*!
Change the abort key
The defaults are Qt::Key_Escape and Qt::NoModifiers
\param key Key ( See Qt::Keycode )
\param modifiers Keyboard modifiers
*/
void QwtPanner::setAbortKey( int key,
Qt::KeyboardModifiers modifiers )
{
d_data->abortKey = key;
d_data->abortKeyModifiers = modifiers;
}
//! Get the abort key and modifiers
void QwtPanner::getAbortKey( int &key,
Qt::KeyboardModifiers &modifiers ) const
{
key = d_data->abortKey;
modifiers = d_data->abortKeyModifiers;
}
/*!
Change the cursor, that is active while panning
The default is the cursor of the parent widget.
\param cursor New cursor
\sa setCursor()
*/
#ifndef QT_NO_CURSOR
void QwtPanner::setCursor( const QCursor &cursor )
{
d_data->cursor = new QCursor( cursor );
}
#endif
/*!
\return Cursor that is active while panning
\sa setCursor()
*/
#ifndef QT_NO_CURSOR
const QCursor QwtPanner::cursor() const
{
if ( d_data->cursor )
return *d_data->cursor;
if ( parentWidget() )
return parentWidget()->cursor();
return QCursor();
}
#endif
/*!
\brief En/disable the panner
When enabled is true an event filter is installed for
the observed widget, otherwise the event filter is removed.
\param on true or false
\sa isEnabled(), eventFilter()
*/
void QwtPanner::setEnabled( bool on )
{
if ( d_data->isEnabled != on )
{
d_data->isEnabled = on;
QWidget *w = parentWidget();
if ( w )
{
if ( d_data->isEnabled )
{
w->installEventFilter( this );
}
else
{
w->removeEventFilter( this );
hide();
}
}
}
}
/*!
Set the orientations, where panning is enabled
The default value is in both directions: Qt::Horizontal | Qt::Vertical
/param o Orientation
*/
void QwtPanner::setOrientations( Qt::Orientations o )
{
d_data->orientations = o;
}
//! Return the orientation, where paning is enabled
Qt::Orientations QwtPanner::orientations() const
{
return d_data->orientations;
}
/*!
\return True if an orientation is enabled
\sa orientations(), setOrientations()
*/
bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const
{
return d_data->orientations & o;
}
/*!
\return true when enabled, false otherwise
\sa setEnabled, eventFilter()
*/
bool QwtPanner::isEnabled() const
{
return d_data->isEnabled;
}
/*!
\brief Paint event
Repaint the grabbed pixmap on its current position and
fill the empty spaces by the background of the parent widget.
\param pe Paint event
*/
void QwtPanner::paintEvent( QPaintEvent *pe )
{
int dx = d_data->pos.x() - d_data->initialPos.x();
int dy = d_data->pos.y() - d_data->initialPos.y();
QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() );
r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) );
QPixmap pm( size() );
QwtPainter::fillPixmap( parentWidget(), pm );
QPainter painter( &pm );
if ( !d_data->contentsMask.isNull() )
{
QPixmap masked = d_data->pixmap;
masked.setMask( d_data->contentsMask );
painter.drawPixmap( r, masked );
}
else
{
painter.drawPixmap( r, d_data->pixmap );
}
painter.end();
if ( !d_data->contentsMask.isNull() )
pm.setMask( d_data->contentsMask );
painter.begin( this );
painter.setClipRegion( pe->region() );
painter.drawPixmap( 0, 0, pm );
}
/*!
\brief Calculate a mask for the contents of the panned widget
Sometimes only parts of the contents of a widget should be
panned. F.e. for a widget with a styled background with rounded borders
only the area inside of the border should be panned.
\return An empty bitmap, indicating no mask
*/
QBitmap QwtPanner::contentsMask() const
{
return QBitmap();
}
/*!
Grab the widget into a pixmap.
\return Grabbed pixmap
*/
QPixmap QwtPanner::grab() const
{
#if QT_VERSION >= 0x050000
return parentWidget()->grab( parentWidget()->rect() );
#else
return QPixmap::grabWidget( parentWidget() );
#endif
}
/*!
\brief Event filter
When isEnabled() is true mouse events of the
observed widget are filtered.
\param object Object to be filtered
\param event Event
\return Always false, beside for paint events for the
parent widget.
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
widgetMouseMoveEvent()
*/
bool QwtPanner::eventFilter( QObject *object, QEvent *event )
{
if ( object == NULL || object != parentWidget() )
return false;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::MouseMove:
{
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::MouseButtonRelease:
{
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
break;
}
case QEvent::KeyPress:
{
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
break;
}
case QEvent::KeyRelease:
{
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
break;
}
case QEvent::Paint:
{
if ( isVisible() )
return true;
break;
}
default:;
}
return false;
}
/*!
Handle a mouse press event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMouseReleaseEvent(),
widgetMouseMoveEvent(),
*/
void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent )
{
if ( ( mouseEvent->button() != d_data->button )
|| ( mouseEvent->modifiers() != d_data->buttonModifiers ) )
{
return;
}
QWidget *w = parentWidget();
if ( w == NULL )
return;
#ifndef QT_NO_CURSOR
showCursor( true );
#endif
d_data->initialPos = d_data->pos = mouseEvent->pos();
setGeometry( parentWidget()->rect() );
// We don't want to grab the picker !
QVector<QwtPicker *> pickers = qwtActivePickers( parentWidget() );
for ( int i = 0; i < pickers.size(); i++ )
pickers[i]->setEnabled( false );
d_data->pixmap = grab();
d_data->contentsMask = contentsMask();
for ( int i = 0; i < pickers.size(); i++ )
pickers[i]->setEnabled( true );
show();
}
/*!
Handle a mouse move event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent()
*/
void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
{
if ( !isVisible() )
return;
QPoint pos = mouseEvent->pos();
if ( !isOrientationEnabled( Qt::Horizontal ) )
pos.setX( d_data->initialPos.x() );
if ( !isOrientationEnabled( Qt::Vertical ) )
pos.setY( d_data->initialPos.y() );
if ( pos != d_data->pos && rect().contains( pos ) )
{
d_data->pos = pos;
update();
Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(),
d_data->pos.y() - d_data->initialPos.y() );
}
}
/*!
Handle a mouse release event for the observed widget.
\param mouseEvent Mouse event
\sa eventFilter(), widgetMousePressEvent(),
widgetMouseMoveEvent(),
*/
void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
{
if ( isVisible() )
{
hide();
#ifndef QT_NO_CURSOR
showCursor( false );
#endif
QPoint pos = mouseEvent->pos();
if ( !isOrientationEnabled( Qt::Horizontal ) )
pos.setX( d_data->initialPos.x() );
if ( !isOrientationEnabled( Qt::Vertical ) )
pos.setY( d_data->initialPos.y() );
d_data->pixmap = QPixmap();
d_data->contentsMask = QBitmap();
d_data->pos = pos;
if ( d_data->pos != d_data->initialPos )
{
Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(),
d_data->pos.y() - d_data->initialPos.y() );
}
}
}
/*!
Handle a key press event for the observed widget.
\param keyEvent Key event
\sa eventFilter(), widgetKeyReleaseEvent()
*/
void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent )
{
if ( ( keyEvent->key() == d_data->abortKey )
&& ( keyEvent->modifiers() == d_data->abortKeyModifiers ) )
{
hide();
#ifndef QT_NO_CURSOR
showCursor( false );
#endif
d_data->pixmap = QPixmap();
}
}
/*!
Handle a key release event for the observed widget.
\param keyEvent Key event
\sa eventFilter(), widgetKeyReleaseEvent()
*/
void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
{
Q_UNUSED( keyEvent );
}
#ifndef QT_NO_CURSOR
void QwtPanner::showCursor( bool on )
{
if ( on == d_data->hasCursor )
return;
QWidget *w = parentWidget();
if ( w == NULL || d_data->cursor == NULL )
return;
d_data->hasCursor = on;
if ( on )
{
if ( w->testAttribute( Qt::WA_SetCursor ) )
{
delete d_data->restoreCursor;
d_data->restoreCursor = new QCursor( w->cursor() );
}
w->setCursor( *d_data->cursor );
}
else
{
if ( d_data->restoreCursor )
{
w->setCursor( *d_data->restoreCursor );
delete d_data->restoreCursor;
d_data->restoreCursor = NULL;
}
else
w->unsetCursor();
}
}
#endif

View File

@@ -0,0 +1,103 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PANNER_H
#define QWT_PANNER_H 1
#include "qwt_global.h"
#include <qwidget.h>
#include <qpixmap.h>
class QCursor;
/*!
\brief QwtPanner provides panning of a widget
QwtPanner grabs the contents of a widget, that can be dragged
in all directions. The offset between the start and the end position
is emitted by the panned signal.
QwtPanner grabs the content of the widget into a pixmap and moves
the pixmap around, without initiating any repaint events for the widget.
Areas, that are not part of content are not painted while panning.
This makes panning fast enough for widgets, where
repaints are too slow for mouse movements.
For widgets, where repaints are very fast it might be better to
implement panning manually by mapping mouse events into paint events.
*/
class QWT_EXPORT QwtPanner: public QWidget
{
Q_OBJECT
public:
QwtPanner( QWidget* parent );
virtual ~QwtPanner();
void setEnabled( bool );
bool isEnabled() const;
void setMouseButton( Qt::MouseButton,
Qt::KeyboardModifiers = Qt::NoModifier );
void getMouseButton( Qt::MouseButton &button,
Qt::KeyboardModifiers & ) const;
void setAbortKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
void getAbortKey( int &key, Qt::KeyboardModifiers & ) const;
void setCursor( const QCursor & );
const QCursor cursor() const;
void setOrientations( Qt::Orientations );
Qt::Orientations orientations() const;
bool isOrientationEnabled( Qt::Orientation ) const;
virtual bool eventFilter( QObject *, QEvent * );
Q_SIGNALS:
/*!
Signal emitted, when panning is done
\param dx Offset in horizontal direction
\param dy Offset in vertical direction
*/
void panned( int dx, int dy );
/*!
Signal emitted, while the widget moved, but panning
is not finished.
\param dx Offset in horizontal direction
\param dy Offset in vertical direction
*/
void moved( int dx, int dy );
protected:
virtual void widgetMousePressEvent( QMouseEvent * );
virtual void widgetMouseReleaseEvent( QMouseEvent * );
virtual void widgetMouseMoveEvent( QMouseEvent * );
virtual void widgetKeyPressEvent( QKeyEvent * );
virtual void widgetKeyReleaseEvent( QKeyEvent * );
virtual void paintEvent( QPaintEvent * );
virtual QBitmap contentsMask() const;
virtual QPixmap grab() const;
private:
#ifndef QT_NO_CURSOR
void showCursor( bool );
#endif
class PrivateData;
PrivateData *d_data;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,329 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PICKER
#define QWT_PICKER 1
#include "qwt_global.h"
#include "qwt_text.h"
#include "qwt_event_pattern.h"
#include <qobject.h>
#include <qpen.h>
#include <qfont.h>
#include <qrect.h>
#include <qpainterpath.h>
class QWidget;
class QMouseEvent;
class QWheelEvent;
class QKeyEvent;
class QwtPickerMachine;
class QwtWidgetOverlay;
/*!
\brief QwtPicker provides selections on a widget
QwtPicker filters all enter, leave, mouse and keyboard events of a widget
and translates them into an array of selected points.
The way how the points are collected depends on type of state machine
that is connected to the picker. Qwt offers a couple of predefined
state machines for selecting:
- Nothing\n
QwtPickerTrackerMachine
- Single points\n
QwtPickerClickPointMachine, QwtPickerDragPointMachine
- Rectangles\n
QwtPickerClickRectMachine, QwtPickerDragRectMachine
- Polygons\n
QwtPickerPolygonMachine
While these state machines cover the most common ways to collect points
it is also possible to implement individual machines as well.
QwtPicker translates the picked points into a selection using the
adjustedPoints() method. adjustedPoints() is intended to be reimplemented
to fix up the selection according to application specific requirements.
(F.e. when an application accepts rectangles of a fixed aspect ratio only.)
Optionally QwtPicker support the process of collecting points by a
rubber band and tracker displaying a text for the current mouse
position.
\par Example
\verbatim #include <qwt_picker.h>
#include <qwt_picker_machine.h>
QwtPicker *picker = new QwtPicker(widget);
picker->setStateMachine(new QwtPickerDragRectMachine);
picker->setTrackerMode(QwtPicker::ActiveOnly);
picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n
The state machine triggers the following commands:
- begin()\n
Activate/Initialize the selection.
- append()\n
Add a new point
- move() \n
Change the position of the last point.
- remove()\n
Remove the last point.
- end()\n
Terminate the selection and call accept to validate the picked points.
The picker is active (isActive()), between begin() and end().
In active state the rubber band is displayed, and the tracker is visible
in case of trackerMode is ActiveOnly or AlwaysOn.
The cursor can be moved using the arrow keys. All selections can be aborted
using the abort key. (QwtEventPattern::KeyPatternCode)
\warning In case of QWidget::NoFocus the focus policy of the observed
widget is set to QWidget::WheelFocus and mouse tracking
will be manipulated while the picker is active,
or if trackerMode() is AlwayOn.
*/
class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern
{
Q_OBJECT
Q_ENUMS( RubberBand DisplayMode ResizeMode )
Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled )
Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode )
Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode )
Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen )
Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont )
Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand )
Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen )
public:
/*!
Rubber band style
The default value is QwtPicker::NoRubberBand.
\sa setRubberBand(), rubberBand()
*/
enum RubberBand
{
//! No rubberband.
NoRubberBand = 0,
//! A horizontal line ( only for QwtPickerMachine::PointSelection )
HLineRubberBand,
//! A vertical line ( only for QwtPickerMachine::PointSelection )
VLineRubberBand,
//! A crosshair ( only for QwtPickerMachine::PointSelection )
CrossRubberBand,
//! A rectangle ( only for QwtPickerMachine::RectSelection )
RectRubberBand,
//! An ellipse ( only for QwtPickerMachine::RectSelection )
EllipseRubberBand,
//! A polygon ( only for QwtPickerMachine::PolygonSelection )
PolygonRubberBand,
/*!
Values >= UserRubberBand can be used to define additional
rubber bands.
*/
UserRubberBand = 100
};
/*!
\brief Display mode
\sa setTrackerMode(), trackerMode(), isActive()
*/
enum DisplayMode
{
//! Display never
AlwaysOff,
//! Display always
AlwaysOn,
//! Display only when the selection is active
ActiveOnly
};
/*!
Controls what to do with the selected points of an active
selection when the observed widget is resized.
The default value is QwtPicker::Stretch.
\sa setResizeMode()
*/
enum ResizeMode
{
//! All points are scaled according to the new size,
Stretch,
//! All points remain unchanged.
KeepSize
};
explicit QwtPicker( QWidget *parent );
explicit QwtPicker( RubberBand rubberBand,
DisplayMode trackerMode, QWidget * );
virtual ~QwtPicker();
void setStateMachine( QwtPickerMachine * );
const QwtPickerMachine *stateMachine() const;
QwtPickerMachine *stateMachine();
void setRubberBand( RubberBand );
RubberBand rubberBand() const;
void setTrackerMode( DisplayMode );
DisplayMode trackerMode() const;
void setResizeMode( ResizeMode );
ResizeMode resizeMode() const;
void setRubberBandPen( const QPen & );
QPen rubberBandPen() const;
void setTrackerPen( const QPen & );
QPen trackerPen() const;
void setTrackerFont( const QFont & );
QFont trackerFont() const;
bool isEnabled() const;
bool isActive() const;
virtual bool eventFilter( QObject *, QEvent * );
QWidget *parentWidget();
const QWidget *parentWidget() const;
virtual QPainterPath pickArea() const;
virtual void drawRubberBand( QPainter * ) const;
virtual void drawTracker( QPainter * ) const;
virtual QRegion rubberBandMask() const;
virtual QwtText trackerText( const QPoint &pos ) const;
QPoint trackerPosition() const;
virtual QRect trackerRect( const QFont & ) const;
QPolygon selection() const;
public Q_SLOTS:
void setEnabled( bool );
Q_SIGNALS:
/*!
A signal indicating, when the picker has been activated.
Together with setEnabled() it can be used to implement
selections with more than one picker.
\param on True, when the picker has been activated
*/
void activated( bool on );
/*!
A signal emitting the selected points,
at the end of a selection.
\param polygon Selected points
*/
void selected( const QPolygon &polygon );
/*!
A signal emitted when a point has been appended to the selection
\param pos Position of the appended point.
\sa append(). moved()
*/
void appended( const QPoint &pos );
/*!
A signal emitted whenever the last appended point of the
selection has been moved.
\param pos Position of the moved last point of the selection.
\sa move(), appended()
*/
void moved( const QPoint &pos );
/*!
A signal emitted whenever the last appended point of the
selection has been removed.
\param pos Position of the point, that has been removed
\sa remove(), appended()
*/
void removed( const QPoint &pos );
/*!
A signal emitted when the active selection has been changed.
This might happen when the observed widget is resized.
\param selection Changed selection
\sa stretchSelection()
*/
void changed( const QPolygon &selection );
protected:
virtual QPolygon adjustedPoints( const QPolygon & ) const;
virtual void transition( const QEvent * );
virtual void begin();
virtual void append( const QPoint & );
virtual void move( const QPoint & );
virtual void remove();
virtual bool end( bool ok = true );
virtual bool accept( QPolygon & ) const;
virtual void reset();
virtual void widgetMousePressEvent( QMouseEvent * );
virtual void widgetMouseReleaseEvent( QMouseEvent * );
virtual void widgetMouseDoubleClickEvent( QMouseEvent * );
virtual void widgetMouseMoveEvent( QMouseEvent * );
virtual void widgetWheelEvent( QWheelEvent * );
virtual void widgetKeyPressEvent( QKeyEvent * );
virtual void widgetKeyReleaseEvent( QKeyEvent * );
virtual void widgetEnterEvent( QEvent * );
virtual void widgetLeaveEvent( QEvent * );
virtual void stretchSelection( const QSize &oldSize,
const QSize &newSize );
virtual void updateDisplay();
const QwtWidgetOverlay *rubberBandOverlay() const;
const QwtWidgetOverlay *trackerOverlay() const;
const QPolygon &pickedPoints() const;
private:
void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode );
void setMouseTracking( bool );
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,541 @@
/* -*- 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_picker_machine.h"
#include "qwt_event_pattern.h"
#include <qevent.h>
//! Constructor
QwtPickerMachine::QwtPickerMachine( SelectionType type ):
d_selectionType( type ),
d_state( 0 )
{
}
//! Destructor
QwtPickerMachine::~QwtPickerMachine()
{
}
//! Return the selection type
QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const
{
return d_selectionType;
}
//! Return the current state
int QwtPickerMachine::state() const
{
return d_state;
}
//! Change the current state
void QwtPickerMachine::setState( int state )
{
d_state = state;
}
//! Set the current state to 0.
void QwtPickerMachine::reset()
{
setState( 0 );
}
//! Constructor
QwtPickerTrackerMachine::QwtPickerTrackerMachine():
QwtPickerMachine( NoSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerTrackerMachine::transition(
const QwtEventPattern &, const QEvent *e )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( e->type() )
{
case QEvent::Enter:
case QEvent::MouseMove:
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
setState( 1 );
}
else
{
cmdList += Move;
}
break;
}
case QEvent::Leave:
{
cmdList += Remove;
cmdList += End;
setState( 0 );
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerClickPointMachine::QwtPickerClickPointMachine():
QwtPickerMachine( PointSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerClickPointMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
cmdList += Begin;
cmdList += Append;
cmdList += End;
}
break;
}
case QEvent::KeyPress:
{
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
{
if ( !keyEvent->isAutoRepeat() )
{
cmdList += Begin;
cmdList += Append;
cmdList += End;
}
}
break;
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerDragPointMachine::QwtPickerDragPointMachine():
QwtPickerMachine( PointSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerDragPointMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
setState( 1 );
}
}
break;
}
case QEvent::MouseMove:
case QEvent::Wheel:
{
if ( state() != 0 )
cmdList += Move;
break;
}
case QEvent::MouseButtonRelease:
{
if ( state() != 0 )
{
cmdList += End;
setState( 0 );
}
break;
}
case QEvent::KeyPress:
{
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
{
if ( !keyEvent->isAutoRepeat() )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
setState( 1 );
}
else
{
cmdList += End;
setState( 0 );
}
}
}
break;
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerClickRectMachine::QwtPickerClickRectMachine():
QwtPickerMachine( RectSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerClickRectMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
switch ( state() )
{
case 0:
{
cmdList += Begin;
cmdList += Append;
setState( 1 );
break;
}
case 1:
{
// Uh, strange we missed the MouseButtonRelease
break;
}
default:
{
cmdList += End;
setState( 0 );
}
}
}
break;
}
case QEvent::MouseMove:
case QEvent::Wheel:
{
if ( state() != 0 )
cmdList += Move;
break;
}
case QEvent::MouseButtonRelease:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 1 )
{
cmdList += Append;
setState( 2 );
}
}
break;
}
case QEvent::KeyPress:
{
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
{
if ( !keyEvent->isAutoRepeat() )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
setState( 1 );
}
else
{
if ( state() == 1 )
{
cmdList += Append;
setState( 2 );
}
else if ( state() == 2 )
{
cmdList += End;
setState( 0 );
}
}
}
}
break;
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerDragRectMachine::QwtPickerDragRectMachine():
QwtPickerMachine( RectSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerDragRectMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 2 );
}
}
break;
}
case QEvent::MouseMove:
case QEvent::Wheel:
{
if ( state() != 0 )
cmdList += Move;
break;
}
case QEvent::MouseButtonRelease:
{
if ( state() == 2 )
{
cmdList += End;
setState( 0 );
}
break;
}
case QEvent::KeyPress:
{
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1,
static_cast<const QKeyEvent *> ( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 2 );
}
else
{
cmdList += End;
setState( 0 );
}
}
break;
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerPolygonMachine::QwtPickerPolygonMachine():
QwtPickerMachine( PolygonSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerPolygonMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 1 );
}
else
{
cmdList += Append;
}
}
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect2,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 1 )
{
cmdList += End;
setState( 0 );
}
}
break;
}
case QEvent::MouseMove:
case QEvent::Wheel:
{
if ( state() != 0 )
cmdList += Move;
break;
}
case QEvent::KeyPress:
{
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
{
if ( !keyEvent->isAutoRepeat() )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 1 );
}
else
{
cmdList += Append;
}
}
}
else if ( eventPattern.keyMatch( QwtEventPattern::KeySelect2, keyEvent ) )
{
if ( !keyEvent->isAutoRepeat() )
{
if ( state() == 1 )
{
cmdList += End;
setState( 0 );
}
}
}
break;
}
default:
break;
}
return cmdList;
}
//! Constructor
QwtPickerDragLineMachine::QwtPickerDragLineMachine():
QwtPickerMachine( PolygonSelection )
{
}
//! Transition
QList<QwtPickerMachine::Command> QwtPickerDragLineMachine::transition(
const QwtEventPattern &eventPattern, const QEvent *event )
{
QList<QwtPickerMachine::Command> cmdList;
switch( event->type() )
{
case QEvent::MouseButtonPress:
{
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
static_cast<const QMouseEvent *>( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 1 );
}
}
break;
}
case QEvent::KeyPress:
{
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1,
static_cast<const QKeyEvent *> ( event ) ) )
{
if ( state() == 0 )
{
cmdList += Begin;
cmdList += Append;
cmdList += Append;
setState( 1 );
}
else
{
cmdList += End;
setState( 0 );
}
}
break;
}
case QEvent::MouseMove:
case QEvent::Wheel:
{
if ( state() != 0 )
cmdList += Move;
break;
}
case QEvent::MouseButtonRelease:
{
if ( state() != 0 )
{
cmdList += End;
setState( 0 );
}
}
default:
break;
}
return cmdList;
}

View File

@@ -0,0 +1,214 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PICKER_MACHINE
#define QWT_PICKER_MACHINE 1
#include "qwt_global.h"
#include <qlist.h>
class QEvent;
class QwtEventPattern;
/*!
\brief A state machine for QwtPicker selections
QwtPickerMachine accepts key and mouse events and translates them
into selection commands.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerMachine
{
public:
/*!
Type of a selection.
\sa selectionType()
*/
enum SelectionType
{
//! The state machine not usable for any type of selection.
NoSelection = -1,
//! The state machine is for selecting a single point.
PointSelection,
//! The state machine is for selecting a rectangle (2 points).
RectSelection,
//! The state machine is for selecting a polygon (many points).
PolygonSelection
};
//! Commands - the output of a state machine
enum Command
{
Begin,
Append,
Move,
Remove,
End
};
QwtPickerMachine( SelectionType );
virtual ~QwtPickerMachine();
//! Transition
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * ) = 0;
void reset();
int state() const;
void setState( int );
SelectionType selectionType() const;
private:
const SelectionType d_selectionType;
int d_state;
};
/*!
\brief A state machine for indicating mouse movements
QwtPickerTrackerMachine supports displaying information
corresponding to mouse movements, but is not intended for
selecting anything. Begin/End are related to Enter/Leave events.
*/
class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine
{
public:
QwtPickerTrackerMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for point selections
Pressing QwtEventPattern::MouseSelect1 or
QwtEventPattern::KeySelect1 selects a point.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine
{
public:
QwtPickerClickPointMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for point selections
Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
starts the selection, releasing QwtEventPattern::MouseSelect1 or
a second press of QwtEventPattern::KeySelect1 terminates it.
*/
class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine
{
public:
QwtPickerDragPointMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for rectangle selections
Pressing QwtEventPattern::MouseSelect1 starts
the selection, releasing it selects the first point. Pressing it
again selects the second point and terminates the selection.
Pressing QwtEventPattern::KeySelect1 also starts the
selection, a second press selects the first point. A third one selects
the second point and terminates the selection.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine
{
public:
QwtPickerClickRectMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for rectangle selections
Pressing QwtEventPattern::MouseSelect1 selects
the first point, releasing it the second point.
Pressing QwtEventPattern::KeySelect1 also selects the
first point, a second press selects the second point and terminates
the selection.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine
{
public:
QwtPickerDragRectMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for line selections
Pressing QwtEventPattern::MouseSelect1 selects
the first point, releasing it the second point.
Pressing QwtEventPattern::KeySelect1 also selects the
first point, a second press selects the second point and terminates
the selection.
A common use case of QwtPickerDragLineMachine are pickers for
distance measurements.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerDragLineMachine: public QwtPickerMachine
{
public:
QwtPickerDragLineMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
/*!
\brief A state machine for polygon selections
Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
starts the selection and selects the first point, or appends a point.
Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2
appends the last point and terminates the selection.
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
*/
class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine
{
public:
QwtPickerPolygonMachine();
virtual QList<Command> transition(
const QwtEventPattern &, const QEvent * );
};
#endif

View File

@@ -0,0 +1,51 @@
/* -*- 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_pixel_matrix.h"
/*!
\brief Constructor
\param rect Bounding rectangle for the matrix
*/
QwtPixelMatrix::QwtPixelMatrix( const QRect& rect ):
QBitArray( qMax( rect.width() * rect.height(), 0 ) ),
d_rect( rect )
{
}
//! Destructor
QwtPixelMatrix::~QwtPixelMatrix()
{
}
/*!
Set the bounding rectangle of the matrix
\param rect Bounding rectangle
\note All bits are cleared
*/
void QwtPixelMatrix::setRect( const QRect& rect )
{
if ( rect != d_rect )
{
d_rect = rect;
const int sz = qMax( rect.width() * rect.height(), 0 );
resize( sz );
}
fill( false );
}
//! \return Bounding rectangle
QRect QwtPixelMatrix::rect() const
{
return d_rect;
}

View File

@@ -0,0 +1,98 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PIXEL_MATRIX_H
#define QWT_PIXEL_MATRIX_H
#include "qwt_global.h"
#include <qbitarray.h>
#include <qrect.h>
/*!
\brief A bit field corresponding to the pixels of a rectangle
QwtPixelMatrix is intended to filter out duplicates in an
unsorted array of points.
*/
class QWT_EXPORT QwtPixelMatrix: public QBitArray
{
public:
QwtPixelMatrix( const QRect& rect );
~QwtPixelMatrix();
void setRect( const QRect& rect );
QRect rect() const;
bool testPixel( int x, int y ) const;
bool testAndSetPixel( int x, int y, bool on );
int index( int x, int y ) const;
private:
QRect d_rect;
};
/*!
\brief Test if a pixel has been set
\param x X-coordinate
\param y Y-coordinate
\return true, when pos is outside of rect(), or when the pixel
has already been set.
*/
inline bool QwtPixelMatrix::testPixel( int x, int y ) const
{
const int idx = index( x, y );
return ( idx >= 0 ) ? testBit( idx ) : true;
}
/*!
\brief Set a pixel and test if a pixel has been set before
\param x X-coordinate
\param y Y-coordinate
\param on Set/Clear the pixel
\return true, when pos is outside of rect(), or when the pixel
was set before.
*/
inline bool QwtPixelMatrix::testAndSetPixel( int x, int y, bool on )
{
const int idx = index( x, y );
if ( idx < 0 )
return true;
const bool onBefore = testBit( idx );
setBit( idx, on );
return onBefore;
}
/*!
\brief Calculate the index in the bit field corresponding to a position
\param x X-coordinate
\param y Y-coordinate
\return Index, when rect() contains pos - otherwise -1.
*/
inline int QwtPixelMatrix::index( int x, int y ) const
{
const int dx = x - d_rect.x();
if ( dx < 0 || dx >= d_rect.width() )
return -1;
const int dy = y - d_rect.y();
if ( dy < 0 || dy >= d_rect.height() )
return -1;
return dy * d_rect.width() + dx;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_H
#define QWT_PLOT_H
#include "qwt_global.h"
#include "qwt_text.h"
#include "qwt_plot_dict.h"
#include "qwt_scale_map.h"
#include "qwt_interval.h"
#include <qframe.h>
#include <qlist.h>
#include <qvariant.h>
class QwtPlotLayout;
class QwtAbstractLegend;
class QwtScaleWidget;
class QwtScaleEngine;
class QwtScaleDiv;
class QwtScaleDraw;
class QwtTextLabel;
/*!
\brief A 2-D plotting widget
QwtPlot is a widget for plotting two-dimensional graphs.
An unlimited number of plot items can be displayed on
its canvas. Plot items might be curves (QwtPlotCurve), markers
(QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived
from QwtPlotItem.
A plot can have up to four axes, with each plot item attached to an x- and
a y axis. The scales at the axes can be explicitly set (QwtScaleDiv), or
are calculated from the plot items, using algorithms (QwtScaleEngine) which
can be configured separately for each axis.
The simpleplot example is a good starting point to see how to set up a
plot widget.
\image html plot.png
\par Example
The following example shows (schematically) the most simple
way to use QwtPlot. By default, only the left and bottom axes are
visible and their scales are computed automatically.
\verbatim
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
QwtPlot *myPlot = new QwtPlot("Two Curves", parent);
// add curves
QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1");
QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2");
// connect or copy the data to the curves
curve1->setData(...);
curve2->setData(...);
curve1->attach(myPlot);
curve2->attach(myPlot);
// finally, refresh the plot
myPlot->replot();
\endverbatim
*/
class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict
{
Q_OBJECT
Q_PROPERTY( QBrush canvasBackground
READ canvasBackground WRITE setCanvasBackground )
Q_PROPERTY( bool autoReplot READ autoReplot WRITE setAutoReplot )
#if 0
// This property is intended to configure the plot
// widget from a special dialog in the deigner plugin.
// Disabled until such a dialog has been implemented.
Q_PROPERTY( QString propertiesDocument
READ grabProperties WRITE applyProperties )
#endif
public:
//! \brief Axis index
enum Axis
{
//! Y axis left of the canvas
yLeft,
//! Y axis right of the canvas
yRight,
//! X axis below the canvas
xBottom,
//! X axis above the canvas
xTop,
//! Number of axes
axisCnt
};
/*!
Position of the legend, relative to the canvas.
\sa insertLegend()
*/
enum LegendPosition
{
//! The legend will be left from the QwtPlot::yLeft axis.
LeftLegend,
//! The legend will be right from the QwtPlot::yRight axis.
RightLegend,
//! The legend will be below the footer
BottomLegend,
//! The legend will be above the title
TopLegend
};
explicit QwtPlot( QWidget * = NULL );
explicit QwtPlot( const QwtText &title, QWidget * = NULL );
virtual ~QwtPlot();
void applyProperties( const QString & );
QString grabProperties() const;
void setAutoReplot( bool = true );
bool autoReplot() const;
// Layout
void setPlotLayout( QwtPlotLayout * );
QwtPlotLayout *plotLayout();
const QwtPlotLayout *plotLayout() const;
// Title
void setTitle( const QString & );
void setTitle( const QwtText &t );
QwtText title() const;
QwtTextLabel *titleLabel();
const QwtTextLabel *titleLabel() const;
// Footer
void setFooter( const QString & );
void setFooter( const QwtText &t );
QwtText footer() const;
QwtTextLabel *footerLabel();
const QwtTextLabel *footerLabel() const;
// Canvas
void setCanvas( QWidget * );
QWidget *canvas();
const QWidget *canvas() const;
void setCanvasBackground( const QBrush & );
QBrush canvasBackground() const;
virtual QwtScaleMap canvasMap( int axisId ) const;
double invTransform( int axisId, int pos ) const;
double transform( int axisId, double value ) const;
// Axes
QwtScaleEngine *axisScaleEngine( int axisId );
const QwtScaleEngine *axisScaleEngine( int axisId ) const;
void setAxisScaleEngine( int axisId, QwtScaleEngine * );
void setAxisAutoScale( int axisId, bool on = true );
bool axisAutoScale( int axisId ) const;
void enableAxis( int axisId, bool tf = true );
bool axisEnabled( int axisId ) const;
void setAxisFont( int axisId, const QFont &f );
QFont axisFont( int axisId ) const;
void setAxisScale( int axisId, double min, double max, double step = 0 );
void setAxisScaleDiv( int axisId, const QwtScaleDiv & );
void setAxisScaleDraw( int axisId, QwtScaleDraw * );
double axisStepSize( int axisId ) const;
QwtInterval axisInterval( int axisId ) const;
const QwtScaleDiv &axisScaleDiv( int axisId ) const;
const QwtScaleDraw *axisScaleDraw( int axisId ) const;
QwtScaleDraw *axisScaleDraw( int axisId );
const QwtScaleWidget *axisWidget( int axisId ) const;
QwtScaleWidget *axisWidget( int axisId );
void setAxisLabelAlignment( int axisId, Qt::Alignment );
void setAxisLabelRotation( int axisId, double rotation );
void setAxisTitle( int axisId, const QString & );
void setAxisTitle( int axisId, const QwtText & );
QwtText axisTitle( int axisId ) const;
void setAxisMaxMinor( int axisId, int maxMinor );
int axisMaxMinor( int axisId ) const;
void setAxisMaxMajor( int axisId, int maxMajor );
int axisMaxMajor( int axisId ) const;
// Legend
void insertLegend( QwtAbstractLegend *,
LegendPosition = QwtPlot::RightLegend, double ratio = -1.0 );
QwtAbstractLegend *legend();
const QwtAbstractLegend *legend() const;
void updateLegend();
void updateLegend( const QwtPlotItem * );
// Misc
virtual QSize sizeHint() const;
virtual QSize minimumSizeHint() const;
virtual void updateLayout();
virtual void drawCanvas( QPainter * );
void updateAxes();
void updateCanvasMargins();
virtual void getCanvasMarginsHint(
const QwtScaleMap maps[], const QRectF &canvasRect,
double &left, double &top, double &right, double &bottom) const;
virtual bool event( QEvent * );
virtual bool eventFilter( QObject *, QEvent * );
virtual void drawItems( QPainter *, const QRectF &,
const QwtScaleMap maps[axisCnt] ) const;
virtual QVariant itemToInfo( QwtPlotItem * ) const;
virtual QwtPlotItem *infoToItem( const QVariant & ) const;
Q_SIGNALS:
/*!
A signal indicating, that an item has been attached/detached
\param plotItem Plot item
\param on Attached/Detached
*/
void itemAttached( QwtPlotItem *plotItem, bool on );
/*!
A signal with the attributes how to update
the legend entries for a plot item.
\param itemInfo Info about a plot item, build from itemToInfo()
\param data Attributes of the entries ( usually <= 1 ) for
the plot item.
\sa itemToInfo(), infoToItem(), QwtAbstractLegend::updateLegend()
*/
void legendDataChanged( const QVariant &itemInfo,
const QList<QwtLegendData> &data );
public Q_SLOTS:
virtual void replot();
void autoRefresh();
protected:
static bool axisValid( int axisId );
virtual void resizeEvent( QResizeEvent *e );
private Q_SLOTS:
void updateLegendItems( const QVariant &itemInfo,
const QList<QwtLegendData> &data );
private:
friend class QwtPlotItem;
void attachItem( QwtPlotItem *, bool );
void initAxesData();
void deleteAxesData();
void updateScaleDiv();
void initPlot( const QwtText &title );
class AxisData;
AxisData *d_axisData[axisCnt];
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,368 @@
/* -*- 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_plot_abstract_barchart.h"
#include "qwt_scale_map.h"
static inline double qwtTransformWidth(
const QwtScaleMap &map, double value, double width )
{
const double w2 = 0.5 * width;
const double v1 = map.transform( value - w2 );
const double v2 = map.transform( value + w2 );
return qAbs( v2 - v1 );
}
class QwtPlotAbstractBarChart::PrivateData
{
public:
PrivateData():
layoutPolicy( QwtPlotAbstractBarChart::AutoAdjustSamples ),
layoutHint( 0.5 ),
spacing( 10 ),
margin( 5 ),
baseline( 0.0 )
{
}
QwtPlotAbstractBarChart::LayoutPolicy layoutPolicy;
double layoutHint;
int spacing;
int margin;
double baseline;
};
/*!
Constructor
\param title Title of the chart
*/
QwtPlotAbstractBarChart::QwtPlotAbstractBarChart( const QwtText &title ):
QwtPlotSeriesItem( title )
{
d_data = new PrivateData;
setItemAttribute( QwtPlotItem::Legend, true );
setItemAttribute( QwtPlotItem::AutoScale, true );
setItemAttribute( QwtPlotItem::Margins, true );
setZ( 19.0 );
}
//! Destructor
QwtPlotAbstractBarChart::~QwtPlotAbstractBarChart()
{
delete d_data;
}
/*!
The combination of layoutPolicy() and layoutHint() define how the width
of the bars is calculated
\param policy Layout policy
\sa layoutPolicy(), layoutHint()
*/
void QwtPlotAbstractBarChart::setLayoutPolicy( LayoutPolicy policy )
{
if ( policy != d_data->layoutPolicy )
{
d_data->layoutPolicy = policy;
itemChanged();
}
}
/*!
The combination of layoutPolicy() and layoutHint() define how the width
of the bars is calculated
\return Layout policy of the chart item
\sa setLayoutPolicy(), layoutHint()
*/
QwtPlotAbstractBarChart::LayoutPolicy QwtPlotAbstractBarChart::layoutPolicy() const
{
return d_data->layoutPolicy;
}
/*!
The combination of layoutPolicy() and layoutHint() define how the width
of the bars is calculated
\param hint Layout hint
\sa LayoutPolicy, layoutPolicy(), layoutHint()
*/
void QwtPlotAbstractBarChart::setLayoutHint( double hint )
{
hint = qMax( 0.0, hint );
if ( hint != d_data->layoutHint )
{
d_data->layoutHint = hint;
itemChanged();
}
}
/*!
The combination of layoutPolicy() and layoutHint() define how the width
of the bars is calculated
\return Layout policy of the chart item
\sa LayoutPolicy, setLayoutHint(), layoutPolicy()
*/
double QwtPlotAbstractBarChart::layoutHint() const
{
return d_data->layoutHint;
}
/*!
\brief Set the spacing
The spacing is the distance between 2 samples ( bars for QwtPlotBarChart or
a group of bars for QwtPlotMultiBarChart ) in paint device coordinates.
\sa spacing()
*/
void QwtPlotAbstractBarChart::setSpacing( int spacing )
{
spacing = qMax( spacing, 0 );
if ( spacing != d_data->spacing )
{
d_data->spacing = spacing;
itemChanged();
}
}
/*!
\return Spacing between 2 samples ( bars or groups of bars )
\sa setSpacing(), margin()
*/
int QwtPlotAbstractBarChart::spacing() const
{
return d_data->spacing;
}
/*!
\brief Set the margin
The margin is the distance between the outmost bars and the contentsRect()
of the canvas. The default setting is 5 pixels.
\param margin Margin
\sa spacing(), margin()
*/
void QwtPlotAbstractBarChart::setMargin( int margin )
{
margin = qMax( margin, 0 );
if ( margin != d_data->margin )
{
d_data->margin = margin;
itemChanged();
}
}
/*!
\return Margin between the outmost bars and the contentsRect()
of the canvas.
\sa setMargin(), spacing()
*/
int QwtPlotAbstractBarChart::margin() const
{
return d_data->margin;
}
/*!
\brief Set the baseline
The baseline is the origin for the chart. Each bar is
painted from the baseline in the direction of the sample
value. In case of a horizontal orientation() the baseline
is interpreted as x - otherwise as y - value.
The default value for the baseline is 0.
\param value Value for the baseline
\sa baseline(), QwtPlotSeriesItem::orientation()
*/
void QwtPlotAbstractBarChart::setBaseline( double value )
{
if ( value != d_data->baseline )
{
d_data->baseline = value;
itemChanged();
}
}
/*!
\return Value for the origin of the bar chart
\sa setBaseline(), QwtPlotSeriesItem::orientation()
*/
double QwtPlotAbstractBarChart::baseline() const
{
return d_data->baseline;
}
/*!
Calculate the width for a sample in paint device coordinates
\param map Scale map for the corresponding scale
\param canvasSize Size of the canvas in paint device coordinates
\param boundingSize Bounding size of the chart in plot coordinates
( used in AutoAdjustSamples mode )
\param value Value of the sample
\return Sample width
\sa layoutPolicy(), layoutHint()
*/
double QwtPlotAbstractBarChart::sampleWidth( const QwtScaleMap &map,
double canvasSize, double boundingSize, double value ) const
{
double width;
switch( d_data->layoutPolicy )
{
case ScaleSamplesToAxes:
{
width = qwtTransformWidth( map, value, d_data->layoutHint );
break;
}
case ScaleSampleToCanvas:
{
width = canvasSize * d_data->layoutHint;
break;
}
case FixedSampleSize:
{
width = d_data->layoutHint;
break;
}
case AutoAdjustSamples:
default:
{
const size_t numSamples = dataSize();
double w = 1.0;
if ( numSamples > 1 )
{
w = qAbs( boundingSize / ( numSamples - 1 ) );
}
width = qwtTransformWidth( map, value, w );
width -= d_data->spacing;
width = qMax( width, d_data->layoutHint );
}
}
return width;
}
/*!
\brief Calculate a hint for the canvas margin
Bar charts need to reserve some space for displaying the bars
for the first and the last sample. The hint is calculated
from the layoutHint() depending on the layoutPolicy().
The margins are in target device coordinates ( pixels on screen )
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param canvasRect Contents rectangle of the canvas in painter coordinates
\param left Returns the left margin
\param top Returns the top margin
\param right Returns the right margin
\param bottom Returns the bottom margin
\return Margin
\sa layoutPolicy(), layoutHint(), QwtPlotItem::Margins
QwtPlot::getCanvasMarginsHint(), QwtPlot::updateCanvasMargins()
*/
void QwtPlotAbstractBarChart::getCanvasMarginHint( const QwtScaleMap &xMap,
const QwtScaleMap &yMap, const QRectF &canvasRect,
double &left, double &top, double &right, double &bottom ) const
{
double hint = -1.0;
switch( layoutPolicy() )
{
case ScaleSampleToCanvas:
{
if ( orientation() == Qt::Vertical )
hint = 0.5 * canvasRect.width() * d_data->layoutHint;
else
hint = 0.5 * canvasRect.height() * d_data->layoutHint;
break;
}
case FixedSampleSize:
{
hint = 0.5 * d_data->layoutHint;
break;
}
case AutoAdjustSamples:
case ScaleSamplesToAxes:
default:
{
const size_t numSamples = dataSize();
if ( numSamples <= 0 )
break;
// doesn't work for nonlinear scales
const QRectF br = dataRect();
double spacing = 0.0;
double sampleWidthS = 1.0;
if ( layoutPolicy() == ScaleSamplesToAxes )
{
sampleWidthS = qMax( d_data->layoutHint, 0.0 );
}
else
{
spacing = d_data->spacing;
if ( numSamples > 1 )
{
sampleWidthS = qAbs( br.width() / ( numSamples - 1 ) );
}
}
double ds, w;
if ( orientation() == Qt::Vertical )
{
ds = qAbs( xMap.sDist() );
w = canvasRect.width();
}
else
{
ds = qAbs( yMap.sDist() );
w = canvasRect.height();
}
const double sampleWidthP = ( w - spacing * ( numSamples - 1 ) )
* sampleWidthS / ( ds + sampleWidthS );
hint = 0.5 * sampleWidthP;
hint += qMax( d_data->margin, 0 );
}
}
if ( orientation() == Qt::Vertical )
{
left = right = hint;
top = bottom = -1.0; // no hint
}
else
{
left = right = -1.0; // no hint
top = bottom = hint;
}
}

View File

@@ -0,0 +1,97 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_ABSTRACT_BAR_CHART_H
#define QWT_PLOT_ABSTRACT_BAR_CHART_H
#include "qwt_global.h"
#include "qwt_plot_seriesitem.h"
#include "qwt_series_data.h"
/*!
\brief Abstract base class for bar chart items
In opposite to almost all other plot items bar charts can't be
displayed inside of their bounding rectangle and need a special
API how to calculate the width of the bars and how they affect
the layout of the attached plot.
*/
class QWT_EXPORT QwtPlotAbstractBarChart: public QwtPlotSeriesItem
{
public:
/*!
\brief Mode how to calculate the bar width
setLayoutPolicy(), setLayoutHint(), barWidthHint()
*/
enum LayoutPolicy
{
/*!
The sample width is calculated by dividing the bounding rectangle
by the number of samples. The layoutHint() is used as a minimum width
in paint device coordinates.
\sa boundingRectangle()
*/
AutoAdjustSamples,
/*!
layoutHint() defines an interval in axis coordinates
*/
ScaleSamplesToAxes,
/*!
The bar width is calculated by multiplying layoutHint()
with the height or width of the canvas.
\sa boundingRectangle()
*/
ScaleSampleToCanvas,
/*!
layoutHint() defines a fixed width in paint device coordinates.
*/
FixedSampleSize
};
explicit QwtPlotAbstractBarChart( const QwtText &title );
virtual ~QwtPlotAbstractBarChart();
void setLayoutPolicy( LayoutPolicy );
LayoutPolicy layoutPolicy() const;
void setLayoutHint( double );
double layoutHint() const;
void setSpacing( int );
int spacing() const;
void setMargin( int );
int margin() const;
void setBaseline( double );
double baseline() const;
virtual void getCanvasMarginHint(
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect,
double &left, double &top, double &right, double &bottom) const;
protected:
double sampleWidth( const QwtScaleMap &map,
double canvasSize, double dataSize,
double value ) const;
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,719 @@
/* -*- 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_plot.h"
#include "qwt_math.h"
#include "qwt_scale_widget.h"
#include "qwt_scale_div.h"
#include "qwt_scale_engine.h"
class QwtPlot::AxisData
{
public:
bool isEnabled;
bool doAutoScale;
double minValue;
double maxValue;
double stepSize;
int maxMajor;
int maxMinor;
bool isValid;
QwtScaleDiv scaleDiv;
QwtScaleEngine *scaleEngine;
QwtScaleWidget *scaleWidget;
};
//! Initialize axes
void QwtPlot::initAxesData()
{
int axisId;
for ( axisId = 0; axisId < axisCnt; axisId++ )
d_axisData[axisId] = new AxisData;
d_axisData[yLeft]->scaleWidget =
new QwtScaleWidget( QwtScaleDraw::LeftScale, this );
d_axisData[yRight]->scaleWidget =
new QwtScaleWidget( QwtScaleDraw::RightScale, this );
d_axisData[xTop]->scaleWidget =
new QwtScaleWidget( QwtScaleDraw::TopScale, this );
d_axisData[xBottom]->scaleWidget =
new QwtScaleWidget( QwtScaleDraw::BottomScale, this );
d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" );
d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" );
d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" );
d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" );
#if 1
// better find the font sizes from the application font
QFont fscl( fontInfo().family(), 10 );
QFont fttl( fontInfo().family(), 12, QFont::Bold );
#endif
for ( axisId = 0; axisId < axisCnt; axisId++ )
{
AxisData &d = *d_axisData[axisId];
d.scaleEngine = new QwtLinearScaleEngine;
d.scaleWidget->setTransformation(
d.scaleEngine->transformation() );
d.scaleWidget->setFont( fscl );
d.scaleWidget->setMargin( 2 );
QwtText text = d.scaleWidget->title();
text.setFont( fttl );
d.scaleWidget->setTitle( text );
d.doAutoScale = true;
d.minValue = 0.0;
d.maxValue = 1000.0;
d.stepSize = 0.0;
d.maxMinor = 5;
d.maxMajor = 8;
d.isValid = false;
}
d_axisData[yLeft]->isEnabled = true;
d_axisData[yRight]->isEnabled = false;
d_axisData[xBottom]->isEnabled = true;
d_axisData[xTop]->isEnabled = false;
}
void QwtPlot::deleteAxesData()
{
for ( int axisId = 0; axisId < axisCnt; axisId++ )
{
delete d_axisData[axisId]->scaleEngine;
delete d_axisData[axisId];
d_axisData[axisId] = NULL;
}
}
/*!
\return Scale widget of the specified axis, or NULL if axisId is invalid.
\param axisId Axis index
*/
const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->scaleWidget;
return NULL;
}
/*!
\return Scale widget of the specified axis, or NULL if axisId is invalid.
\param axisId Axis index
*/
QwtScaleWidget *QwtPlot::axisWidget( int axisId )
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->scaleWidget;
return NULL;
}
/*!
Change the scale engine for an axis
\param axisId Axis index
\param scaleEngine Scale engine
\sa axisScaleEngine()
*/
void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine )
{
if ( axisValid( axisId ) && scaleEngine != NULL )
{
AxisData &d = *d_axisData[axisId];
delete d.scaleEngine;
d.scaleEngine = scaleEngine;
d_axisData[axisId]->scaleWidget->setTransformation(
scaleEngine->transformation() );
d.isValid = false;
autoRefresh();
}
}
/*!
\param axisId Axis index
\return Scale engine for a specific axis
*/
QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId )
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->scaleEngine;
else
return NULL;
}
/*!
\param axisId Axis index
\return Scale engine for a specific axis
*/
const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->scaleEngine;
else
return NULL;
}
/*!
\return \c True, if autoscaling is enabled
\param axisId Axis index
*/
bool QwtPlot::axisAutoScale( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->doAutoScale;
else
return false;
}
/*!
\return \c True, if a specified axis is enabled
\param axisId Axis index
*/
bool QwtPlot::axisEnabled( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->isEnabled;
else
return false;
}
/*!
\return The font of the scale labels for a specified axis
\param axisId Axis index
*/
QFont QwtPlot::axisFont( int axisId ) const
{
if ( axisValid( axisId ) )
return axisWidget( axisId )->font();
else
return QFont();
}
/*!
\return The maximum number of major ticks for a specified axis
\param axisId Axis index
\sa setAxisMaxMajor(), QwtScaleEngine::divideScale()
*/
int QwtPlot::axisMaxMajor( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->maxMajor;
else
return 0;
}
/*!
\return the maximum number of minor ticks for a specified axis
\param axisId Axis index
\sa setAxisMaxMinor(), QwtScaleEngine::divideScale()
*/
int QwtPlot::axisMaxMinor( int axisId ) const
{
if ( axisValid( axisId ) )
return d_axisData[axisId]->maxMinor;
else
return 0;
}
/*!
\brief Return the scale division of a specified axis
axisScaleDiv(axisId).lowerBound(), axisScaleDiv(axisId).upperBound()
are the current limits of the axis scale.
\param axisId Axis index
\return Scale division
\sa QwtScaleDiv, setAxisScaleDiv(), QwtScaleEngine::divideScale()
*/
const QwtScaleDiv &QwtPlot::axisScaleDiv( int axisId ) const
{
return d_axisData[axisId]->scaleDiv;
}
/*!
\brief Return the scale draw of a specified axis
\param axisId Axis index
\return Specified scaleDraw for axis, or NULL if axis is invalid.
*/
const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const
{
if ( !axisValid( axisId ) )
return NULL;
return axisWidget( axisId )->scaleDraw();
}
/*!
\brief Return the scale draw of a specified axis
\param axisId Axis index
\return Specified scaleDraw for axis, or NULL if axis is invalid.
*/
QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId )
{
if ( !axisValid( axisId ) )
return NULL;
return axisWidget( axisId )->scaleDraw();
}
/*!
\brief Return the step size parameter that has been set in setAxisScale.
This doesn't need to be the step size of the current scale.
\param axisId Axis index
\return step size parameter value
\sa setAxisScale(), QwtScaleEngine::divideScale()
*/
double QwtPlot::axisStepSize( int axisId ) const
{
if ( !axisValid( axisId ) )
return 0;
return d_axisData[axisId]->stepSize;
}
/*!
\brief Return the current interval of the specified axis
This is only a convenience function for axisScaleDiv( axisId )->interval();
\param axisId Axis index
\return Scale interval
\sa QwtScaleDiv, axisScaleDiv()
*/
QwtInterval QwtPlot::axisInterval( int axisId ) const
{
if ( !axisValid( axisId ) )
return QwtInterval();
return d_axisData[axisId]->scaleDiv.interval();
}
/*!
\return Title of a specified axis
\param axisId Axis index
*/
QwtText QwtPlot::axisTitle( int axisId ) const
{
if ( axisValid( axisId ) )
return axisWidget( axisId )->title();
else
return QwtText();
}
/*!
\brief Enable or disable a specified axis
When an axis is disabled, this only means that it is not
visible on the screen. Curves, markers and can be attached
to disabled axes, and transformation of screen coordinates
into values works as normal.
Only xBottom and yLeft are enabled by default.
\param axisId Axis index
\param tf \c true (enabled) or \c false (disabled)
*/
void QwtPlot::enableAxis( int axisId, bool tf )
{
if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled )
{
d_axisData[axisId]->isEnabled = tf;
updateLayout();
}
}
/*!
Transform the x or y coordinate of a position in the
drawing region into a value.
\param axisId Axis index
\param pos position
\return Position as axis coordinate
\warning The position can be an x or a y coordinate,
depending on the specified axis.
*/
double QwtPlot::invTransform( int axisId, int pos ) const
{
if ( axisValid( axisId ) )
return( canvasMap( axisId ).invTransform( pos ) );
else
return 0.0;
}
/*!
\brief Transform a value into a coordinate in the plotting region
\param axisId Axis index
\param value value
\return X or Y coordinate in the plotting region corresponding
to the value.
*/
double QwtPlot::transform( int axisId, double value ) const
{
if ( axisValid( axisId ) )
return( canvasMap( axisId ).transform( value ) );
else
return 0.0;
}
/*!
\brief Change the font of an axis
\param axisId Axis index
\param font Font
\warning This function changes the font of the tick labels,
not of the axis title.
*/
void QwtPlot::setAxisFont( int axisId, const QFont &font )
{
if ( axisValid( axisId ) )
axisWidget( axisId )->setFont( font );
}
/*!
\brief Enable autoscaling for a specified axis
This member function is used to switch back to autoscaling mode
after a fixed scale has been set. Autoscaling is enabled by default.
\param axisId Axis index
\param on On/Off
\sa setAxisScale(), setAxisScaleDiv(), updateAxes()
\note The autoscaling flag has no effect until updateAxes() is executed
( called by replot() ).
*/
void QwtPlot::setAxisAutoScale( int axisId, bool on )
{
if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) )
{
d_axisData[axisId]->doAutoScale = on;
autoRefresh();
}
}
/*!
\brief Disable autoscaling and specify a fixed scale for a selected axis.
In updateAxes() the scale engine calculates a scale division from the
specified parameters, that will be assigned to the scale widget. So
updates of the scale widget usually happen delayed with the next replot.
\param axisId Axis index
\param min Minimum of the scale
\param max Maximum of the scale
\param stepSize Major step size. If <code>step == 0</code>, the step size is
calculated automatically using the maxMajor setting.
\sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize(), QwtScaleEngine::divideScale()
*/
void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize )
{
if ( axisValid( axisId ) )
{
AxisData &d = *d_axisData[axisId];
d.doAutoScale = false;
d.isValid = false;
d.minValue = min;
d.maxValue = max;
d.stepSize = stepSize;
autoRefresh();
}
}
/*!
\brief Disable autoscaling and specify a fixed scale for a selected axis.
The scale division will be stored locally only until the next call
of updateAxes(). So updates of the scale widget usually happen delayed with
the next replot.
\param axisId Axis index
\param scaleDiv Scale division
\sa setAxisScale(), setAxisAutoScale()
*/
void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv )
{
if ( axisValid( axisId ) )
{
AxisData &d = *d_axisData[axisId];
d.doAutoScale = false;
d.scaleDiv = scaleDiv;
d.isValid = true;
autoRefresh();
}
}
/*!
\brief Set a scale draw
\param axisId Axis index
\param scaleDraw Object responsible for drawing scales.
By passing scaleDraw it is possible to extend QwtScaleDraw
functionality and let it take place in QwtPlot. Please note
that scaleDraw has to be created with new and will be deleted
by the corresponding QwtScale member ( like a child object ).
\sa QwtScaleDraw, QwtScaleWidget
\warning The attributes of scaleDraw will be overwritten by those of the
previous QwtScaleDraw.
*/
void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw )
{
if ( axisValid( axisId ) )
{
axisWidget( axisId )->setScaleDraw( scaleDraw );
autoRefresh();
}
}
/*!
Change the alignment of the tick labels
\param axisId Axis index
\param alignment Or'd Qt::AlignmentFlags see <qnamespace.h>
\sa QwtScaleDraw::setLabelAlignment()
*/
void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment )
{
if ( axisValid( axisId ) )
axisWidget( axisId )->setLabelAlignment( alignment );
}
/*!
Rotate all tick labels
\param axisId Axis index
\param rotation Angle in degrees. When changing the label rotation,
the label alignment might be adjusted too.
\sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment()
*/
void QwtPlot::setAxisLabelRotation( int axisId, double rotation )
{
if ( axisValid( axisId ) )
axisWidget( axisId )->setLabelRotation( rotation );
}
/*!
Set the maximum number of minor scale intervals for a specified axis
\param axisId Axis index
\param maxMinor Maximum number of minor steps
\sa axisMaxMinor()
*/
void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor )
{
if ( axisValid( axisId ) )
{
maxMinor = qBound( 0, maxMinor, 100 );
AxisData &d = *d_axisData[axisId];
if ( maxMinor != d.maxMinor )
{
d.maxMinor = maxMinor;
d.isValid = false;
autoRefresh();
}
}
}
/*!
Set the maximum number of major scale intervals for a specified axis
\param axisId Axis index
\param maxMajor Maximum number of major steps
\sa axisMaxMajor()
*/
void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor )
{
if ( axisValid( axisId ) )
{
maxMajor = qBound( 1, maxMajor, 10000 );
AxisData &d = *d_axisData[axisId];
if ( maxMajor != d.maxMajor )
{
d.maxMajor = maxMajor;
d.isValid = false;
autoRefresh();
}
}
}
/*!
\brief Change the title of a specified axis
\param axisId Axis index
\param title axis title
*/
void QwtPlot::setAxisTitle( int axisId, const QString &title )
{
if ( axisValid( axisId ) )
axisWidget( axisId )->setTitle( title );
}
/*!
\brief Change the title of a specified axis
\param axisId Axis index
\param title Axis title
*/
void QwtPlot::setAxisTitle( int axisId, const QwtText &title )
{
if ( axisValid( axisId ) )
axisWidget( axisId )->setTitle( title );
}
/*!
\brief Rebuild the axes scales
In case of autoscaling the boundaries of a scale are calculated
from the bounding rectangles of all plot items, having the
QwtPlotItem::AutoScale flag enabled ( QwtScaleEngine::autoScale() ).
Then a scale division is calculated ( QwtScaleEngine::didvideScale() )
and assigned to scale widget.
When the scale boundaries have been assigned with setAxisScale() a
scale division is calculated ( QwtScaleEngine::didvideScale() )
for this interval and assigned to the scale widget.
When the scale has been set explicitly by setAxisScaleDiv() the
locally stored scale division gets assigned to the scale widget.
The scale widget indicates modifications by emitting a
QwtScaleWidget::scaleDivChanged() signal.
updateAxes() is usually called by replot().
\sa setAxisAutoScale(), setAxisScale(), setAxisScaleDiv(), replot()
QwtPlotItem::boundingRect()
*/
void QwtPlot::updateAxes()
{
// Find bounding interval of the item data
// for all axes, where autoscaling is enabled
QwtInterval intv[axisCnt];
const QwtPlotItemList& itmList = itemList();
QwtPlotItemIterator it;
for ( it = itmList.begin(); it != itmList.end(); ++it )
{
const QwtPlotItem *item = *it;
if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) )
continue;
if ( !item->isVisible() )
continue;
if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) )
{
const QRectF rect = item->boundingRect();
if ( rect.width() >= 0.0 )
intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() );
if ( rect.height() >= 0.0 )
intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() );
}
}
// Adjust scales
for ( int axisId = 0; axisId < axisCnt; axisId++ )
{
AxisData &d = *d_axisData[axisId];
double minValue = d.minValue;
double maxValue = d.maxValue;
double stepSize = d.stepSize;
if ( d.doAutoScale && intv[axisId].isValid() )
{
d.isValid = false;
minValue = intv[axisId].minValue();
maxValue = intv[axisId].maxValue();
d.scaleEngine->autoScale( d.maxMajor,
minValue, maxValue, stepSize );
}
if ( !d.isValid )
{
d.scaleDiv = d.scaleEngine->divideScale(
minValue, maxValue,
d.maxMajor, d.maxMinor, stepSize );
d.isValid = true;
}
QwtScaleWidget *scaleWidget = axisWidget( axisId );
scaleWidget->setScaleDiv( d.scaleDiv );
int startDist, endDist;
scaleWidget->getBorderDistHint( startDist, endDist );
scaleWidget->setBorderDist( startDist, endDist );
}
for ( it = itmList.begin(); it != itmList.end(); ++it )
{
QwtPlotItem *item = *it;
if ( item->testItemInterest( QwtPlotItem::ScaleInterest ) )
{
item->updateScaleDiv( axisScaleDiv( item->xAxis() ),
axisScaleDiv( item->yAxis() ) );
}
}
}

View File

@@ -0,0 +1,459 @@
/* -*- 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_plot_barchart.h"
#include "qwt_scale_map.h"
#include "qwt_column_symbol.h"
#include "qwt_painter.h"
#include <qpainter.h>
class QwtPlotBarChart::PrivateData
{
public:
PrivateData():
symbol( NULL ),
legendMode( QwtPlotBarChart::LegendChartTitle )
{
}
~PrivateData()
{
delete symbol;
}
QwtColumnSymbol *symbol;
QwtPlotBarChart::LegendMode legendMode;
};
/*!
Constructor
\param title Title of the curve
*/
QwtPlotBarChart::QwtPlotBarChart( const QwtText &title ):
QwtPlotAbstractBarChart( title )
{
init();
}
/*!
Constructor
\param title Title of the curve
*/
QwtPlotBarChart::QwtPlotBarChart( const QString &title ):
QwtPlotAbstractBarChart( QwtText( title ) )
{
init();
}
//! Destructor
QwtPlotBarChart::~QwtPlotBarChart()
{
delete d_data;
}
void QwtPlotBarChart::init()
{
d_data = new PrivateData;
setData( new QwtPointSeriesData() );
}
//! \return QwtPlotItem::Rtti_PlotBarChart
int QwtPlotBarChart::rtti() const
{
return QwtPlotItem::Rtti_PlotBarChart;
}
/*!
Initialize data with an array of points
\param samples Vector of points
\note QVector is implicitly shared
\note QPolygonF is derived from QVector<QPointF>
*/
void QwtPlotBarChart::setSamples(
const QVector<QPointF> &samples )
{
setData( new QwtPointSeriesData( samples ) );
}
/*!
Initialize data with an array of doubles
The indices in the array are taken as x coordinate,
while the doubles are interpreted as y values.
\param samples Vector of y coordinates
\note QVector is implicitly shared
*/
void QwtPlotBarChart::setSamples(
const QVector<double> &samples )
{
QVector<QPointF> points;
for ( int i = 0; i < samples.size(); i++ )
points += QPointF( i, samples[ i ] );
setData( new QwtPointSeriesData( points ) );
}
/*!
Assign a series of samples
setSamples() is just a wrapper for setData() without any additional
value - beside that it is easier to find for the developer.
\param data Data
\warning The item takes ownership of the data object, deleting
it when its not used anymore.
*/
void QwtPlotBarChart::setSamples( QwtSeriesData<QPointF> *data )
{
setData( data );
}
/*!
\brief Assign a symbol
The bar chart will take the ownership of the symbol, hence the previously
set symbol will be delete by setting a new one. If \p symbol is
\c NULL no symbol will be drawn.
\param symbol Symbol
\sa symbol()
*/
void QwtPlotBarChart::setSymbol( QwtColumnSymbol *symbol )
{
if ( symbol != d_data->symbol )
{
delete d_data->symbol;
d_data->symbol = symbol;
legendChanged();
itemChanged();
}
}
/*!
\return Current symbol or NULL, when no symbol has been assigned
\sa setSymbol()
*/
const QwtColumnSymbol *QwtPlotBarChart::symbol() const
{
return d_data->symbol;
}
/*!
Set the mode that decides what to display on the legend
In case of LegendBarTitles barTitle() needs to be overloaded
to return individual titles for each bar.
\param mode New mode
\sa legendMode(), legendData(), barTitle(), QwtPlotItem::ItemAttribute
*/
void QwtPlotBarChart::setLegendMode( LegendMode mode )
{
if ( mode != d_data->legendMode )
{
d_data->legendMode = mode;
legendChanged();
}
}
/*!
\return Legend mode
\sa setLegendMode()
*/
QwtPlotBarChart::LegendMode QwtPlotBarChart::legendMode() const
{
return d_data->legendMode;
}
/*!
\return Bounding rectangle of all samples.
For an empty series the rectangle is invalid.
*/
QRectF QwtPlotBarChart::boundingRect() const
{
const size_t numSamples = dataSize();
if ( numSamples == 0 )
return QwtPlotSeriesItem::boundingRect();
QRectF rect = QwtPlotSeriesItem::boundingRect();
if ( rect.height() >= 0 )
{
const double baseLine = baseline();
if ( rect.bottom() < baseLine )
rect.setBottom( baseLine );
if ( rect.top() > baseLine )
rect.setTop( baseLine );
}
if ( orientation() == Qt::Horizontal )
rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
return rect;
}
/*!
Draw an interval of the bar chart
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param canvasRect Contents rect of the canvas
\param from Index of the first point to be painted
\param to Index of the last point to be painted. If to < 0 the
curve will be painted to its last point.
\sa drawSymbols()
*/
void QwtPlotBarChart::drawSeries( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const
{
if ( to < 0 )
to = dataSize() - 1;
if ( from < 0 )
from = 0;
if ( from > to )
return;
const QRectF br = data()->boundingRect();
const QwtInterval interval( br.left(), br.right() );
painter->save();
for ( int i = from; i <= to; i++ )
{
drawSample( painter, xMap, yMap,
canvasRect, interval, i, sample( i ) );
}
painter->restore();
}
/*!
Draw a sample
\param painter Painter
\param xMap x map
\param yMap y map
\param canvasRect Contents rect of the canvas
\param boundingInterval Bounding interval of sample values
\param index Index of the sample
\param sample Value of the sample
\sa drawSeries()
*/
void QwtPlotBarChart::drawSample( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, const QwtInterval &boundingInterval,
int index, const QPointF &sample ) const
{
QwtColumnRect barRect;
if ( orientation() == Qt::Horizontal )
{
const double barHeight = sampleWidth( yMap, canvasRect.height(),
boundingInterval.width(), sample.y() );
const double x1 = xMap.transform( baseline() );
const double x2 = xMap.transform( sample.y() );
const double y = yMap.transform( sample.x() );
const double y1 = y - 0.5 * barHeight;
const double y2 = y + 0.5 * barHeight;
barRect.direction = ( x1 < x2 ) ?
QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
barRect.hInterval = QwtInterval( x1, x2 ).normalized();
barRect.vInterval = QwtInterval( y1, y2 );
}
else
{
const double barWidth = sampleWidth( xMap, canvasRect.width(),
boundingInterval.width(), sample.y() );
const double x = xMap.transform( sample.x() );
const double x1 = x - 0.5 * barWidth;
const double x2 = x + 0.5 * barWidth;
const double y1 = yMap.transform( baseline() );
const double y2 = yMap.transform( sample.y() );
barRect.direction = ( y1 < y2 ) ?
QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
barRect.hInterval = QwtInterval( x1, x2 );
barRect.vInterval = QwtInterval( y1, y2 ).normalized();
}
drawBar( painter, index, sample, barRect );
}
/*!
Draw a bar
\param painter Painter
\param sampleIndex Index of the sample represented by the bar
\param sample Value of the sample
\param rect Bounding rectangle of the bar
*/
void QwtPlotBarChart::drawBar( QPainter *painter,
int sampleIndex, const QPointF &sample,
const QwtColumnRect &rect ) const
{
const QwtColumnSymbol *specialSym =
specialSymbol( sampleIndex, sample );
const QwtColumnSymbol *sym = specialSym;
if ( sym == NULL )
sym = d_data->symbol;
if ( sym )
{
sym->draw( painter, rect );
}
else
{
// we build a temporary default symbol
QwtColumnSymbol sym( QwtColumnSymbol::Box );
sym.setLineWidth( 1 );
sym.setFrameStyle( QwtColumnSymbol::Plain );
sym.draw( painter, rect );
}
delete specialSym;
}
/*!
Needs to be overloaded to return a
non default symbol for a specific sample
\param sampleIndex Index of the sample represented by the bar
\param sample Value of the sample
\return NULL, indicating to use the default symbol
*/
QwtColumnSymbol *QwtPlotBarChart::specialSymbol(
int sampleIndex, const QPointF &sample ) const
{
Q_UNUSED( sampleIndex );
Q_UNUSED( sample );
return NULL;
}
/*!
\brief Return the title of a bar
In LegendBarTitles mode the title is displayed on
the legend entry corresponding to a bar.
The default implementation is a dummy, that is intended
to be overloaded.
\param sampleIndex Index of the bar
\return An empty text
\sa LegendBarTitles
*/
QwtText QwtPlotBarChart::barTitle( int sampleIndex ) const
{
Q_UNUSED( sampleIndex );
return QwtText();
}
/*!
\brief Return all information, that is needed to represent
the item on the legend
In case of LegendBarTitles an entry for each bar is returned,
otherwise the chart is represented like any other plot item
from its title() and the legendIcon().
\return Information, that is needed to represent the item on the legend
\sa title(), setLegendMode(), barTitle(), QwtLegend, QwtPlotLegendItem
*/
QList<QwtLegendData> QwtPlotBarChart::legendData() const
{
QList<QwtLegendData> list;
if ( d_data->legendMode == LegendBarTitles )
{
const size_t numSamples = dataSize();
for ( size_t i = 0; i < numSamples; i++ )
{
QwtLegendData data;
QVariant titleValue;
qVariantSetValue( titleValue, barTitle( i ) );
data.setValue( QwtLegendData::TitleRole, titleValue );
if ( !legendIconSize().isEmpty() )
{
QVariant iconValue;
qVariantSetValue( iconValue,
legendIcon( i, legendIconSize() ) );
data.setValue( QwtLegendData::IconRole, iconValue );
}
list += data;
}
}
else
{
return QwtPlotAbstractBarChart::legendData();
}
return list;
}
/*!
\return Icon representing a bar or the chart on the legend
When the legendMode() is LegendBarTitles the icon shows
the bar corresponding to index - otherwise the bar
displays the default symbol.
\param index Index of the legend entry
\param size Icon size
\sa setLegendMode(), drawBar(),
QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
*/
QwtGraphic QwtPlotBarChart::legendIcon(
int index, const QSizeF &size ) const
{
QwtColumnRect column;
column.hInterval = QwtInterval( 0.0, size.width() - 1.0 );
column.vInterval = QwtInterval( 0.0, size.height() - 1.0 );
QwtGraphic icon;
icon.setDefaultSize( size );
icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
QPainter painter( &icon );
painter.setRenderHint( QPainter::Antialiasing,
testRenderHint( QwtPlotItem::RenderAntialiased ) );
int barIndex = -1;
if ( d_data->legendMode == QwtPlotBarChart::LegendBarTitles )
barIndex = index;
drawBar( &painter, barIndex, QPointF(), column );
return icon;
}

View File

@@ -0,0 +1,118 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_BAR_CHART_H
#define QWT_PLOT_BAR_CHART_H
#include "qwt_global.h"
#include "qwt_plot_abstract_barchart.h"
#include "qwt_series_data.h"
class QwtColumnRect;
class QwtColumnSymbol;
/*!
\brief QwtPlotBarChart displays a series of a values as bars.
Each bar might be customized individually by implementing
a specialSymbol(). Otherwise it is rendered using a default symbol.
Depending on its orientation() the bars are displayed horizontally
or vertically. The bars cover the interval between the baseline()
and the value.
By activating the LegendBarTitles mode each sample will have
its own entry on the legend.
The most common use case of a bar chart is to display a
list of y coordinates, where the x coordinate is simply the index
in the list. But for other situations ( f.e. when values are related
to dates ) it is also possible to set x coordinates explicitly.
\sa QwtPlotMultiBarChart, QwtPlotHistogram, QwtPlotCurve::Sticks,
QwtPlotSeriesItem::orientation(), QwtPlotAbstractBarChart::baseline()
*/
class QWT_EXPORT QwtPlotBarChart:
public QwtPlotAbstractBarChart, public QwtSeriesStore<QPointF>
{
public:
/*!
\brief Legend modes.
The default setting is QwtPlotBarChart::LegendChartTitle.
\sa setLegendMode(), legendMode()
*/
enum LegendMode
{
/*!
One entry on the legend showing the default symbol
and the title() of the chart
\sa QwtPlotItem::title()
*/
LegendChartTitle,
/*!
One entry for each value showing the individual symbol
of the corresponding bar and the bar title.
\sa specialSymbol(), barTitle()
*/
LegendBarTitles
};
explicit QwtPlotBarChart( const QString &title = QString::null );
explicit QwtPlotBarChart( const QwtText &title );
virtual ~QwtPlotBarChart();
virtual int rtti() const;
void setSamples( const QVector<QPointF> & );
void setSamples( const QVector<double> & );
void setSamples( QwtSeriesData<QPointF> *series );
void setSymbol( QwtColumnSymbol * );
const QwtColumnSymbol *symbol() const;
void setLegendMode( LegendMode );
LegendMode legendMode() const;
virtual void drawSeries( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual QRectF boundingRect() const;
virtual QwtColumnSymbol *specialSymbol(
int sampleIndex, const QPointF& ) const;
virtual QwtText barTitle( int sampleIndex ) const;
protected:
virtual void drawSample( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, const QwtInterval &boundingInterval,
int index, const QPointF& sample ) const;
virtual void drawBar( QPainter *,
int sampleIndex, const QPointF& point,
const QwtColumnRect & ) const;
QList<QwtLegendData> legendData() const;
QwtGraphic legendIcon( int index, const QSizeF & ) const;
private:
void init();
class PrivateData;
PrivateData *d_data;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_CANVAS_H
#define QWT_PLOT_CANVAS_H
#include "qwt_global.h"
#include <qframe.h>
#include <qpainterpath.h>
class QwtPlot;
class QPixmap;
/*!
\brief Canvas of a QwtPlot.
Canvas is the widget where all plot items are displayed
\sa QwtPlot::setCanvas(), QwtPlotGLCanvas
*/
class QWT_EXPORT QwtPlotCanvas : public QFrame
{
Q_OBJECT
Q_PROPERTY( double borderRadius READ borderRadius WRITE setBorderRadius )
public:
/*!
\brief Paint attributes
The default setting enables BackingStore and Opaque.
\sa setPaintAttribute(), testPaintAttribute()
*/
enum PaintAttribute
{
/*!
\brief Paint double buffered reusing the content
of the pixmap buffer when possible.
Using a backing store might improve the performance
significantly, when working with widget overlays ( like rubber bands ).
Disabling the cache might improve the performance for
incremental paints (using QwtPlotDirectPainter ).
\sa backingStore(), invalidateBackingStore()
*/
BackingStore = 1,
/*!
\brief Try to fill the complete contents rectangle
of the plot canvas
When using styled backgrounds Qt assumes, that the
canvas doesn't fill its area completely
( f.e because of rounded borders ) and fills the area
below the canvas. When this is done with gradients it might
result in a serious performance bottleneck - depending on the size.
When the Opaque attribute is enabled the canvas tries to
identify the gaps with some heuristics and to fill those only.
\warning Will not work for semitransparent backgrounds
*/
Opaque = 2,
/*!
\brief Try to improve painting of styled backgrounds
QwtPlotCanvas supports the box model attributes for
customizing the layout with style sheets. Unfortunately
the design of Qt style sheets has no concept how to
handle backgrounds with rounded corners - beside of padding.
When HackStyledBackground is enabled the plot canvas tries
to separate the background from the background border
by reverse engineering to paint the background before and
the border after the plot items. In this order the border
gets perfectly antialiased and you can avoid some pixel
artifacts in the corners.
*/
HackStyledBackground = 4,
/*!
When ImmediatePaint is set replot() calls repaint()
instead of update().
\sa replot(), QWidget::repaint(), QWidget::update()
*/
ImmediatePaint = 8
};
//! Paint attributes
typedef QFlags<PaintAttribute> PaintAttributes;
/*!
\brief Focus indicator
The default setting is NoFocusIndicator
\sa setFocusIndicator(), focusIndicator(), drawFocusIndicator()
*/
enum FocusIndicator
{
//! Don't paint a focus indicator
NoFocusIndicator,
/*!
The focus is related to the complete canvas.
Paint the focus indicator using drawFocusIndicator()
*/
CanvasFocusIndicator,
/*!
The focus is related to an item (curve, point, ...) on
the canvas. It is up to the application to display a
focus indication using f.e. highlighting.
*/
ItemFocusIndicator
};
explicit QwtPlotCanvas( QwtPlot * = NULL );
virtual ~QwtPlotCanvas();
QwtPlot *plot();
const QwtPlot *plot() const;
void setFocusIndicator( FocusIndicator );
FocusIndicator focusIndicator() const;
void setBorderRadius( double );
double borderRadius() const;
void setPaintAttribute( PaintAttribute, bool on = true );
bool testPaintAttribute( PaintAttribute ) const;
const QPixmap *backingStore() const;
void invalidateBackingStore();
virtual bool event( QEvent * );
Q_INVOKABLE QPainterPath borderPath( const QRect & ) const;
public Q_SLOTS:
void replot();
protected:
virtual void paintEvent( QPaintEvent * );
virtual void resizeEvent( QResizeEvent * );
virtual void drawFocusIndicator( QPainter * );
virtual void drawBorder( QPainter * );
void updateStyleSheetInfo();
private:
void drawCanvas( QPainter *, bool withBackground );
class PrivateData;
PrivateData *d_data;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCanvas::PaintAttributes )
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,337 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_CURVE_H
#define QWT_PLOT_CURVE_H
#include "qwt_global.h"
#include "qwt_plot_seriesitem.h"
#include "qwt_series_data.h"
#include "qwt_text.h"
#include <qpen.h>
#include <qstring.h>
class QPainter;
class QPolygonF;
class QwtScaleMap;
class QwtSymbol;
class QwtCurveFitter;
/*!
\brief A plot item, that represents a series of points
A curve is the representation of a series of points in the x-y plane.
It supports different display styles, interpolation ( f.e. spline )
and symbols.
\par Usage
<dl><dt>a) Assign curve properties</dt>
<dd>When a curve is created, it is configured to draw black solid lines
with in QwtPlotCurve::Lines style and no symbols.
You can change this by calling
setPen(), setStyle() and setSymbol().</dd>
<dt>b) Connect/Assign data.</dt>
<dd>QwtPlotCurve gets its points using a QwtSeriesData object offering
a bridge to the real storage of the points ( like QAbstractItemModel ).
There are several convenience classes derived from QwtSeriesData, that also store
the points inside ( like QStandardItemModel ). QwtPlotCurve also offers
a couple of variations of setSamples(), that build QwtSeriesData objects from
arrays internally.</dd>
<dt>c) Attach the curve to a plot</dt>
<dd>See QwtPlotItem::attach()
</dd></dl>
\par Example:
see examples/bode
\sa QwtPointSeriesData, QwtSymbol, QwtScaleMap
*/
class QWT_EXPORT QwtPlotCurve:
public QwtPlotSeriesItem, public QwtSeriesStore<QPointF>
{
public:
/*!
Curve styles.
\sa setStyle(), style()
*/
enum CurveStyle
{
/*!
Don't draw a curve. Note: This doesn't affect the symbols.
*/
NoCurve = -1,
/*!
Connect the points with straight lines. The lines might
be interpolated depending on the 'Fitted' attribute. Curve
fitting can be configured using setCurveFitter().
*/
Lines,
/*!
Draw vertical or horizontal sticks ( depending on the
orientation() ) from a baseline which is defined by setBaseline().
*/
Sticks,
/*!
Connect the points with a step function. The step function
is drawn from the left to the right or vice versa,
depending on the QwtPlotCurve::Inverted attribute.
*/
Steps,
/*!
Draw dots at the locations of the data points. Note:
This is different from a dotted line (see setPen()), and faster
as a curve in QwtPlotCurve::NoStyle style and a symbol
painting a point.
*/
Dots,
/*!
Styles >= QwtPlotCurve::UserCurve are reserved for derived
classes of QwtPlotCurve that overload drawCurve() with
additional application specific curve types.
*/
UserCurve = 100
};
/*!
Attribute for drawing the curve
\sa setCurveAttribute(), testCurveAttribute(), curveFitter()
*/
enum CurveAttribute
{
/*!
For QwtPlotCurve::Steps only.
Draws a step function from the right to the left.
*/
Inverted = 0x01,
/*!
Only in combination with QwtPlotCurve::Lines
A QwtCurveFitter tries to
interpolate/smooth the curve, before it is painted.
\note Curve fitting requires temporary memory
for calculating coefficients and additional points.
If painting in QwtPlotCurve::Fitted mode is slow it might be better
to fit the points, before they are passed to QwtPlotCurve.
*/
Fitted = 0x02
};
//! Curve attributes
typedef QFlags<CurveAttribute> CurveAttributes;
/*!
Attributes how to represent the curve on the legend
\sa setLegendAttribute(), testLegendAttribute(),
QwtPlotItem::legendData(), legendIcon()
*/
enum LegendAttribute
{
/*!
QwtPlotCurve tries to find a color representing the curve
and paints a rectangle with it.
*/
LegendNoAttribute = 0x00,
/*!
If the style() is not QwtPlotCurve::NoCurve a line
is painted with the curve pen().
*/
LegendShowLine = 0x01,
/*!
If the curve has a valid symbol it is painted.
*/
LegendShowSymbol = 0x02,
/*!
If the curve has a brush a rectangle filled with the
curve brush() is painted.
*/
LegendShowBrush = 0x04
};
//! Legend attributes
typedef QFlags<LegendAttribute> LegendAttributes;
/*!
Attributes to modify the drawing algorithm.
The default setting enables ClipPolygons | FilterPoints
\sa setPaintAttribute(), testPaintAttribute()
*/
enum PaintAttribute
{
/*!
Clip polygons before painting them. In situations, where points
are far outside the visible area (f.e when zooming deep) this
might be a substantial improvement for the painting performance
*/
ClipPolygons = 0x01,
/*!
Tries to reduce the data that has to be painted, by sorting out
duplicates, or paintings outside the visible area. Might have a
notable impact on curves with many close points.
Only a couple of very basic filtering algorithms are implemented.
*/
FilterPoints = 0x02,
/*!
Minimize memory usage that is temporarily needed for the
translated points, before they get painted.
This might slow down the performance of painting
*/
MinimizeMemory = 0x04,
/*!
Render the points to a temporary image and paint the image.
This is a very special optimization for Dots style, when
having a huge amount of points.
With a reasonable number of points QPainter::drawPoints()
will be faster.
*/
ImageBuffer = 0x08
};
//! Paint attributes
typedef QFlags<PaintAttribute> PaintAttributes;
explicit QwtPlotCurve( const QString &title = QString::null );
explicit QwtPlotCurve( const QwtText &title );
virtual ~QwtPlotCurve();
virtual int rtti() const;
void setPaintAttribute( PaintAttribute, bool on = true );
bool testPaintAttribute( PaintAttribute ) const;
void setLegendAttribute( LegendAttribute, bool on = true );
bool testLegendAttribute( LegendAttribute ) const;
#ifndef QWT_NO_COMPAT
void setRawSamples( const double *xData, const double *yData, int size );
void setSamples( const double *xData, const double *yData, int size );
void setSamples( const QVector<double> &xData, const QVector<double> &yData );
#endif
void setSamples( const QVector<QPointF> & );
void setSamples( QwtSeriesData<QPointF> * );
int closestPoint( const QPoint &pos, double *dist = NULL ) const;
double minXValue() const;
double maxXValue() const;
double minYValue() const;
double maxYValue() const;
void setCurveAttribute( CurveAttribute, bool on = true );
bool testCurveAttribute( CurveAttribute ) const;
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setPen( const QPen & );
const QPen &pen() const;
void setBrush( const QBrush & );
const QBrush &brush() const;
void setBaseline( double );
double baseline() const;
void setStyle( CurveStyle style );
CurveStyle style() const;
void setSymbol( QwtSymbol * );
const QwtSymbol *symbol() const;
void setCurveFitter( QwtCurveFitter * );
QwtCurveFitter *curveFitter() const;
virtual void drawSeries( QPainter *,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
protected:
void init();
virtual void drawCurve( QPainter *p, int style,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawSymbols( QPainter *p, const QwtSymbol &,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawLines( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawSticks( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawDots( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawSteps( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void fillCurve( QPainter *,
const QwtScaleMap &, const QwtScaleMap &,
const QRectF &canvasRect, QPolygonF & ) const;
void closePolyline( QPainter *,
const QwtScaleMap &, const QwtScaleMap &, QPolygonF & ) const;
private:
class PrivateData;
PrivateData *d_data;
};
//! boundingRect().left()
inline double QwtPlotCurve::minXValue() const
{
return boundingRect().left();
}
//! boundingRect().right()
inline double QwtPlotCurve::maxXValue() const
{
return boundingRect().right();
}
//! boundingRect().top()
inline double QwtPlotCurve::minYValue() const
{
return boundingRect().top();
}
//! boundingRect().bottom()
inline double QwtPlotCurve::maxYValue() const
{
return boundingRect().bottom();
}
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::PaintAttributes )
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::LegendAttributes )
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::CurveAttributes )
#endif

View File

@@ -0,0 +1,191 @@
/* -*- 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_plot_dict.h"
class QwtPlotDict::PrivateData
{
public:
class ItemList: public QList<QwtPlotItem *>
{
public:
void insertItem( QwtPlotItem *item )
{
if ( item == NULL )
return;
QList<QwtPlotItem *>::iterator it =
qUpperBound( begin(), end(), item, LessZThan() );
insert( it, item );
}
void removeItem( QwtPlotItem *item )
{
if ( item == NULL )
return;
QList<QwtPlotItem *>::iterator it =
qLowerBound( begin(), end(), item, LessZThan() );
for ( ; it != end(); ++it )
{
if ( item == *it )
{
erase( it );
break;
}
}
}
private:
class LessZThan
{
public:
inline bool operator()( const QwtPlotItem *item1,
const QwtPlotItem *item2 ) const
{
return item1->z() < item2->z();
}
};
};
ItemList itemList;
bool autoDelete;
};
/*!
Constructor
Auto deletion is enabled.
\sa setAutoDelete(), QwtPlotItem::attach()
*/
QwtPlotDict::QwtPlotDict()
{
d_data = new QwtPlotDict::PrivateData;
d_data->autoDelete = true;
}
/*!
Destructor
If autoDelete() is on, all attached items will be deleted
\sa setAutoDelete(), autoDelete(), QwtPlotItem::attach()
*/
QwtPlotDict::~QwtPlotDict()
{
detachItems( QwtPlotItem::Rtti_PlotItem, d_data->autoDelete );
delete d_data;
}
/*!
En/Disable Auto deletion
If Auto deletion is on all attached plot items will be deleted
in the destructor of QwtPlotDict. The default value is on.
\sa autoDelete(), insertItem()
*/
void QwtPlotDict::setAutoDelete( bool autoDelete )
{
d_data->autoDelete = autoDelete;
}
/*!
\return true if auto deletion is enabled
\sa setAutoDelete(), insertItem()
*/
bool QwtPlotDict::autoDelete() const
{
return d_data->autoDelete;
}
/*!
Insert a plot item
\param item PlotItem
\sa removeItem()
*/
void QwtPlotDict::insertItem( QwtPlotItem *item )
{
d_data->itemList.insertItem( item );
}
/*!
Remove a plot item
\param item PlotItem
\sa insertItem()
*/
void QwtPlotDict::removeItem( QwtPlotItem *item )
{
d_data->itemList.removeItem( item );
}
/*!
Detach items from the dictionary
\param rtti In case of QwtPlotItem::Rtti_PlotItem detach all items
otherwise only those items of the type rtti.
\param autoDelete If true, delete all detached items
*/
void QwtPlotDict::detachItems( int rtti, bool autoDelete )
{
PrivateData::ItemList list = d_data->itemList;
QwtPlotItemIterator it = list.begin();
while ( it != list.end() )
{
QwtPlotItem *item = *it;
++it; // increment before removing item from the list
if ( rtti == QwtPlotItem::Rtti_PlotItem || item->rtti() == rtti )
{
item->attach( NULL );
if ( autoDelete )
delete item;
}
}
}
/*!
\brief A QwtPlotItemList of all attached plot items.
Use caution when iterating these lists, as removing/detaching an item will
invalidate the iterator. Instead you can place pointers to objects to be
removed in a removal list, and traverse that list later.
\return List of all attached plot items.
*/
const QwtPlotItemList &QwtPlotDict::itemList() const
{
return d_data->itemList;
}
/*!
\return List of all attached plot items of a specific type.
\param rtti See QwtPlotItem::RttiValues
\sa QwtPlotItem::rtti()
*/
QwtPlotItemList QwtPlotDict::itemList( int rtti ) const
{
if ( rtti == QwtPlotItem::Rtti_PlotItem )
return d_data->itemList;
QwtPlotItemList items;
PrivateData::ItemList list = d_data->itemList;
for ( QwtPlotItemIterator it = list.begin(); it != list.end(); ++it )
{
QwtPlotItem *item = *it;
if ( item->rtti() == rtti )
items += item;
}
return items;
}

View File

@@ -0,0 +1,58 @@
/* -*- 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
*****************************************************************************/
/*! \file !*/
#ifndef QWT_PLOT_DICT
#define QWT_PLOT_DICT
#include "qwt_global.h"
#include "qwt_plot_item.h"
#include <qlist.h>
/// \var typedef QList< QwtPlotItem *> QwtPlotItemList
/// \brief See QT 4.x assistant documentation for QList
typedef QList<QwtPlotItem *> QwtPlotItemList;
typedef QList<QwtPlotItem *>::ConstIterator QwtPlotItemIterator;
/*!
\brief A dictionary for plot items
QwtPlotDict organizes plot items in increasing z-order.
If autoDelete() is enabled, all attached items will be deleted
in the destructor of the dictionary.
QwtPlotDict can be used to get access to all QwtPlotItem items - or all
items of a specific type - that are currently on the plot.
\sa QwtPlotItem::attach(), QwtPlotItem::detach(), QwtPlotItem::z()
*/
class QWT_EXPORT QwtPlotDict
{
public:
explicit QwtPlotDict();
virtual ~QwtPlotDict();
void setAutoDelete( bool );
bool autoDelete() const;
const QwtPlotItemList& itemList() const;
QwtPlotItemList itemList( int rtti ) const;
void detachItems( int rtti = QwtPlotItem::Rtti_PlotItem,
bool autoDelete = true );
protected:
void insertItem( QwtPlotItem * );
void removeItem( QwtPlotItem * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,321 @@
/* -*- 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_plot_directpainter.h"
#include "qwt_scale_map.h"
#include "qwt_plot.h"
#include "qwt_plot_canvas.h"
#include "qwt_plot_seriesitem.h"
#include <qpainter.h>
#include <qevent.h>
#include <qapplication.h>
#include <qpixmap.h>
static inline void qwtRenderItem(
QPainter *painter, const QRect &canvasRect,
QwtPlotSeriesItem *seriesItem, int from, int to )
{
// A minor performance improvement is possible
// with caching the maps. TODO ...
QwtPlot *plot = seriesItem->plot();
const QwtScaleMap xMap = plot->canvasMap( seriesItem->xAxis() );
const QwtScaleMap yMap = plot->canvasMap( seriesItem->yAxis() );
painter->setRenderHint( QPainter::Antialiasing,
seriesItem->testRenderHint( QwtPlotItem::RenderAntialiased ) );
seriesItem->drawSeries( painter, xMap, yMap, canvasRect, from, to );
}
static inline bool qwtHasBackingStore( const QwtPlotCanvas *canvas )
{
return canvas->testPaintAttribute( QwtPlotCanvas::BackingStore )
&& canvas->backingStore() && !canvas->backingStore()->isNull();
}
class QwtPlotDirectPainter::PrivateData
{
public:
PrivateData():
attributes( 0 ),
hasClipping(false),
seriesItem( NULL ),
from( 0 ),
to( 0 )
{
}
QwtPlotDirectPainter::Attributes attributes;
bool hasClipping;
QRegion clipRegion;
QPainter painter;
QwtPlotSeriesItem *seriesItem;
int from;
int to;
};
//! Constructor
QwtPlotDirectPainter::QwtPlotDirectPainter( QObject *parent ):
QObject( parent )
{
d_data = new PrivateData;
}
//! Destructor
QwtPlotDirectPainter::~QwtPlotDirectPainter()
{
delete d_data;
}
/*!
Change an attribute
\param attribute Attribute to change
\param on On/Off
\sa Attribute, testAttribute()
*/
void QwtPlotDirectPainter::setAttribute( Attribute attribute, bool on )
{
if ( bool( d_data->attributes & attribute ) != on )
{
if ( on )
d_data->attributes |= attribute;
else
d_data->attributes &= ~attribute;
if ( ( attribute == AtomicPainter ) && on )
reset();
}
}
/*!
\return True, when attribute is enabled
\param attribute Attribute to be tested
\sa Attribute, setAttribute()
*/
bool QwtPlotDirectPainter::testAttribute( Attribute attribute ) const
{
return d_data->attributes & attribute;
}
/*!
En/Disables clipping
\param enable Enables clipping is true, disable it otherwise
\sa hasClipping(), clipRegion(), setClipRegion()
*/
void QwtPlotDirectPainter::setClipping( bool enable )
{
d_data->hasClipping = enable;
}
/*!
\return true, when clipping is enabled
\sa setClipping(), clipRegion(), setClipRegion()
*/
bool QwtPlotDirectPainter::hasClipping() const
{
return d_data->hasClipping;
}
/*!
\brief Assign a clip region and enable clipping
Depending on the environment setting a proper clip region might improve
the performance heavily. F.e. on Qt embedded only the clipped part of
the backing store will be copied to a ( maybe unaccelerated ) frame buffer
device.
\param region Clip region
\sa clipRegion(), hasClipping(), setClipping()
*/
void QwtPlotDirectPainter::setClipRegion( const QRegion &region )
{
d_data->clipRegion = region;
d_data->hasClipping = true;
}
/*!
\return Currently set clip region.
\sa setClipRegion(), setClipping(), hasClipping()
*/
QRegion QwtPlotDirectPainter::clipRegion() const
{
return d_data->clipRegion;
}
/*!
\brief Draw a set of points of a seriesItem.
When observing an measurement while it is running, new points have to be
added to an existing seriesItem. drawSeries() can be used to display them avoiding
a complete redraw of the canvas.
Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
will result in faster painting, if the paint engine of the canvas widget
supports this feature.
\param seriesItem Item to be painted
\param from Index of the first point to be painted
\param to Index of the last point to be painted. If to < 0 the
series will be painted to its last point.
*/
void QwtPlotDirectPainter::drawSeries(
QwtPlotSeriesItem *seriesItem, int from, int to )
{
if ( seriesItem == NULL || seriesItem->plot() == NULL )
return;
QWidget *canvas = seriesItem->plot()->canvas();
const QRect canvasRect = canvas->contentsRect();
QwtPlotCanvas *plotCanvas = qobject_cast<QwtPlotCanvas *>( canvas );
if ( plotCanvas && qwtHasBackingStore( plotCanvas ) )
{
QPainter painter( const_cast<QPixmap *>( plotCanvas->backingStore() ) );
if ( d_data->hasClipping )
painter.setClipRegion( d_data->clipRegion );
qwtRenderItem( &painter, canvasRect, seriesItem, from, to );
painter.end();
if ( testAttribute( QwtPlotDirectPainter::FullRepaint ) )
{
plotCanvas->repaint();
return;
}
}
bool immediatePaint = true;
if ( !canvas->testAttribute( Qt::WA_WState_InPaintEvent ) )
{
#if QT_VERSION < 0x050000
if ( !canvas->testAttribute( Qt::WA_PaintOutsidePaintEvent ) )
#endif
immediatePaint = false;
}
if ( immediatePaint )
{
if ( !d_data->painter.isActive() )
{
reset();
d_data->painter.begin( canvas );
canvas->installEventFilter( this );
}
if ( d_data->hasClipping )
{
d_data->painter.setClipRegion(
QRegion( canvasRect ) & d_data->clipRegion );
}
else
{
if ( !d_data->painter.hasClipping() )
d_data->painter.setClipRect( canvasRect );
}
qwtRenderItem( &d_data->painter, canvasRect, seriesItem, from, to );
if ( d_data->attributes & QwtPlotDirectPainter::AtomicPainter )
{
reset();
}
else
{
if ( d_data->hasClipping )
d_data->painter.setClipping( false );
}
}
else
{
reset();
d_data->seriesItem = seriesItem;
d_data->from = from;
d_data->to = to;
QRegion clipRegion = canvasRect;
if ( d_data->hasClipping )
clipRegion &= d_data->clipRegion;
canvas->installEventFilter( this );
canvas->repaint(clipRegion);
canvas->removeEventFilter( this );
d_data->seriesItem = NULL;
}
}
//! Close the internal QPainter
void QwtPlotDirectPainter::reset()
{
if ( d_data->painter.isActive() )
{
QWidget *w = static_cast<QWidget *>( d_data->painter.device() );
if ( w )
w->removeEventFilter( this );
d_data->painter.end();
}
}
//! Event filter
bool QwtPlotDirectPainter::eventFilter( QObject *, QEvent *event )
{
if ( event->type() == QEvent::Paint )
{
reset();
if ( d_data->seriesItem )
{
const QPaintEvent *pe = static_cast< QPaintEvent *>( event );
QWidget *canvas = d_data->seriesItem->plot()->canvas();
QPainter painter( canvas );
painter.setClipRegion( pe->region() );
bool doCopyCache = testAttribute( CopyBackingStore );
if ( doCopyCache )
{
QwtPlotCanvas *plotCanvas =
qobject_cast<QwtPlotCanvas *>( canvas );
if ( plotCanvas )
{
doCopyCache = qwtHasBackingStore( plotCanvas );
if ( doCopyCache )
{
painter.drawPixmap( plotCanvas->contentsRect().topLeft(),
*plotCanvas->backingStore() );
}
}
}
if ( !doCopyCache )
{
qwtRenderItem( &painter, canvas->contentsRect(),
d_data->seriesItem, d_data->from, d_data->to );
}
return true; // don't call QwtPlotCanvas::paintEvent()
}
}
return false;
}

View File

@@ -0,0 +1,100 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_DIRECT_PAINTER_H
#define QWT_PLOT_DIRECT_PAINTER_H
#include "qwt_global.h"
#include <qobject.h>
class QRegion;
class QwtPlotSeriesItem;
/*!
\brief Painter object trying to paint incrementally
Often applications want to display samples while they are
collected. When there are too many samples complete replots
will be expensive to be processed in a collection cycle.
QwtPlotDirectPainter offers an API to paint
subsets ( f.e all additions points ) without erasing/repainting
the plot canvas.
On certain environments it might be important to calculate a proper
clip region before painting. F.e. for Qt Embedded only the clipped part
of the backing store will be copied to a ( maybe unaccelerated )
frame buffer.
\warning Incremental painting will only help when no replot is triggered
by another operation ( like changing scales ) and nothing needs
to be erased.
*/
class QWT_EXPORT QwtPlotDirectPainter: public QObject
{
public:
/*!
\brief Paint attributes
\sa setAttribute(), testAttribute(), drawSeries()
*/
enum Attribute
{
/*!
Initializing a QPainter is an expensive operation.
When AtomicPainter is set each call of drawSeries() opens/closes
a temporary QPainter. Otherwise QwtPlotDirectPainter tries to
use the same QPainter as long as possible.
*/
AtomicPainter = 0x01,
/*!
When FullRepaint is set the plot canvas is explicitly repainted
after the samples have been rendered.
*/
FullRepaint = 0x02,
/*!
When QwtPlotCanvas::BackingStore is enabled the painter
has to paint to the backing store and the widget. In certain
situations/environments it might be faster to paint to
the backing store only and then copy the backing store to the canvas.
This flag can also be useful for settings, where Qt fills the
the clip region with the widget background.
*/
CopyBackingStore = 0x04
};
//! Paint attributes
typedef QFlags<Attribute> Attributes;
QwtPlotDirectPainter( QObject *parent = NULL );
virtual ~QwtPlotDirectPainter();
void setAttribute( Attribute, bool on );
bool testAttribute( Attribute ) const;
void setClipping( bool );
bool hasClipping() const;
void setClipRegion( const QRegion & );
QRegion clipRegion() const;
void drawSeries( QwtPlotSeriesItem *, int from, int to );
void reset();
virtual bool eventFilter( QObject *, QEvent * );
private:
class PrivateData;
PrivateData *d_data;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotDirectPainter::Attributes )
#endif

View File

@@ -0,0 +1,377 @@
/* -*- 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_plot_glcanvas.h"
#include "qwt_plot.h"
#include "qwt_painter.h"
#include <qevent.h>
#include <qpainter.h>
#include <qdrawutil.h>
#include <qstyle.h>
#include <qstyleoption.h>
#define FIX_GL_TRANSLATION 0
static QWidget *qwtBGWidget( QWidget *widget )
{
QWidget *w = widget;
for ( ; w->parentWidget() != NULL; w = w->parentWidget() )
{
if ( w->autoFillBackground() ||
w->testAttribute( Qt::WA_StyledBackground ) )
{
return w;
}
}
return w;
}
static void qwtUpdateContentsRect( QwtPlotGLCanvas *canvas )
{
const int fw = canvas->frameWidth();
canvas->setContentsMargins( fw, fw, fw, fw );
}
class QwtPlotGLCanvas::PrivateData
{
public:
PrivateData():
frameStyle( QFrame::Panel | QFrame::Sunken),
lineWidth( 2 ),
midLineWidth( 0 )
{
}
int frameStyle;
int lineWidth;
int midLineWidth;
};
class QwtPlotGLCanvasFormat: public QGLFormat
{
public:
QwtPlotGLCanvasFormat():
QGLFormat( QGLFormat::defaultFormat() )
{
setSampleBuffers( true );
}
};
/*!
\brief Constructor
\param plot Parent plot widget
\sa QwtPlot::setCanvas()
*/
QwtPlotGLCanvas::QwtPlotGLCanvas( QwtPlot *plot ):
QGLWidget( QwtPlotGLCanvasFormat(), plot )
{
d_data = new PrivateData;
#ifndef QT_NO_CURSOR
setCursor( Qt::CrossCursor );
#endif
setAutoFillBackground( true );
qwtUpdateContentsRect( this );
}
//! Destructor
QwtPlotGLCanvas::~QwtPlotGLCanvas()
{
delete d_data;
}
/*!
Set the frame style
\param style The bitwise OR between a shape and a shadow.
\sa frameStyle(), QFrame::setFrameStyle(),
setFrameShadow(), setFrameShape()
*/
void QwtPlotGLCanvas::setFrameStyle( int style )
{
if ( style != d_data->frameStyle )
{
d_data->frameStyle = style;
qwtUpdateContentsRect( this );
update();
}
}
/*!
\return The bitwise OR between a frameShape() and a frameShadow()
\sa setFrameStyle(), QFrame::frameStyle()
*/
int QwtPlotGLCanvas::frameStyle() const
{
return d_data->frameStyle;
}
/*!
Set the frame shadow
\param shadow Frame shadow
\sa frameShadow(), setFrameShape(), QFrame::setFrameShadow()
*/
void QwtPlotGLCanvas::setFrameShadow( Shadow shadow )
{
setFrameStyle(( d_data->frameStyle & QFrame::Shape_Mask ) | shadow );
}
/*!
\return Frame shadow
\sa setFrameShadow(), QFrame::setFrameShadow()
*/
QwtPlotGLCanvas::Shadow QwtPlotGLCanvas::frameShadow() const
{
return (Shadow) ( d_data->frameStyle & QFrame::Shadow_Mask );
}
/*!
Set the frame shape
\param shape Frame shape
\sa frameShape(), setFrameShadow(), QFrame::frameShape()
*/
void QwtPlotGLCanvas::setFrameShape( Shape shape )
{
setFrameStyle( ( d_data->frameStyle & QFrame::Shadow_Mask ) | shape );
}
/*!
\return Frame shape
\sa setFrameShape(), QFrame::frameShape()
*/
QwtPlotGLCanvas::Shape QwtPlotGLCanvas::frameShape() const
{
return (Shape) ( d_data->frameStyle & QFrame::Shape_Mask );
}
/*!
Set the frame line width
The default line width is 2 pixels.
\param width Line width of the frame
\sa lineWidth(), setMidLineWidth()
*/
void QwtPlotGLCanvas::setLineWidth( int width )
{
width = qMax( width, 0 );
if ( width != d_data->lineWidth )
{
d_data->lineWidth = qMax( width, 0 );
qwtUpdateContentsRect( this );
update();
}
}
/*!
\return Line width of the frame
\sa setLineWidth(), midLineWidth()
*/
int QwtPlotGLCanvas::lineWidth() const
{
return d_data->lineWidth;
}
/*!
Set the frame mid line width
The default midline width is 0 pixels.
\param width Midline width of the frame
\sa midLineWidth(), setLineWidth()
*/
void QwtPlotGLCanvas::setMidLineWidth( int width )
{
width = qMax( width, 0 );
if ( width != d_data->midLineWidth )
{
d_data->midLineWidth = width;
qwtUpdateContentsRect( this );
update();
}
}
/*!
\return Midline width of the frame
\sa setMidLineWidth(), lineWidth()
*/
int QwtPlotGLCanvas::midLineWidth() const
{
return d_data->midLineWidth;
}
/*!
\return Frame width depending on the style, line width and midline width.
*/
int QwtPlotGLCanvas::frameWidth() const
{
return ( frameStyle() != NoFrame ) ? d_data->lineWidth : 0;
}
/*!
Paint event
\param event Paint event
\sa QwtPlot::drawCanvas()
*/
void QwtPlotGLCanvas::paintEvent( QPaintEvent *event )
{
Q_UNUSED( event );
QPainter painter( this );
#if FIX_GL_TRANSLATION
if ( painter.paintEngine()->type() == QPaintEngine::OpenGL2 )
{
// work around a translation bug of QPaintEngine::OpenGL2
painter.translate( 1, 1 );
}
#endif
drawBackground( &painter );
drawItems( &painter );
if ( !testAttribute( Qt::WA_StyledBackground ) )
{
if ( frameWidth() > 0 )
drawBorder( &painter );
}
}
/*!
Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
\param event Qt Event
\return See QGLWidget::event()
*/
bool QwtPlotGLCanvas::event( QEvent *event )
{
const bool ok = QGLWidget::event( event );
if ( event->type() == QEvent::PolishRequest ||
event->type() == QEvent::StyleChange )
{
// assuming, that we always have a styled background
// when we have a style sheet
setAttribute( Qt::WA_StyledBackground,
testAttribute( Qt::WA_StyleSheet ) );
}
return ok;
}
/*!
Draw the plot items
\param painter Painter
\sa QwtPlot::drawCanvas()
*/
void QwtPlotGLCanvas::drawItems( QPainter *painter )
{
painter->save();
painter->setClipRect( contentsRect(), Qt::IntersectClip );
QwtPlot *plot = qobject_cast< QwtPlot *>( parent() );
if ( plot )
plot->drawCanvas( painter );
painter->restore();
}
/*!
Draw the background of the canvas
\param painter Painter
*/
void QwtPlotGLCanvas::drawBackground( QPainter *painter )
{
painter->save();
QWidget *w = qwtBGWidget( this );
const QPoint off = mapTo( w, QPoint() );
painter->translate( -off );
const QRect fillRect = rect().translated( off );
if ( w->testAttribute( Qt::WA_StyledBackground ) )
{
painter->setClipRect( fillRect );
QStyleOption opt;
opt.initFrom( w );
w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
}
else
{
painter->fillRect( fillRect,
w->palette().brush( w->backgroundRole() ) );
}
painter->restore();
}
/*!
Draw the border of the canvas
\param painter Painter
*/
void QwtPlotGLCanvas::drawBorder( QPainter *painter )
{
const int fw = frameWidth();
if ( fw <= 0 )
return;
if ( frameShadow() == QwtPlotGLCanvas::Plain )
{
qDrawPlainRect( painter, frameRect(),
palette().shadow().color(), lineWidth() );
}
else
{
if ( frameShape() == QwtPlotGLCanvas::Box )
{
qDrawShadeRect( painter, frameRect(), palette(),
frameShadow() == Sunken, lineWidth(), midLineWidth() );
}
else
{
qDrawShadePanel( painter, frameRect(), palette(),
frameShadow() == Sunken, lineWidth() );
}
}
}
//! Calls repaint()
void QwtPlotGLCanvas::replot()
{
repaint();
}
/*!
\return Empty path
*/
QPainterPath QwtPlotGLCanvas::borderPath( const QRect &rect ) const
{
Q_UNUSED( rect );
return QPainterPath();
}
//! \return The rectangle where the frame is drawn in.
QRect QwtPlotGLCanvas::frameRect() const
{
const int fw = frameWidth();
return contentsRect().adjusted( -fw, -fw, fw, fw );
}

View File

@@ -0,0 +1,130 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_GLCANVAS_H
#define QWT_PLOT_GLCANVAS_H
#include "qwt_global.h"
#include <qframe.h>
#include <qgl.h>
class QwtPlot;
/*!
\brief An alternative canvas for a QwtPlot derived from QGLWidget
QwtPlotGLCanvas implements the very basics to act as canvas
inside of a QwtPlot widget. It might be extended to a full
featured alternative to QwtPlotCanvas in a future version of Qwt.
Even if QwtPlotGLCanvas is not derived from QFrame it imitates
its API. When using style sheets it supports the box model - beside
backgrounds with rounded borders.
\sa QwtPlot::setCanvas(), QwtPlotCanvas
\note With Qt4 you might want to use the QPaintEngine::OpenGL paint engine
( see QGL::setPreferredPaintEngine() ). On a Linux test system
QPaintEngine::OpenGL2 shows very basic problems like translated
geometries.
*/
class QWT_EXPORT QwtPlotGLCanvas: public QGLWidget
{
Q_OBJECT
Q_ENUMS( Shape Shadow )
Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
Q_PROPERTY( Shape frameShape READ frameShape WRITE setFrameShape )
Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth )
Q_PROPERTY( int midLineWidth READ midLineWidth WRITE setMidLineWidth )
Q_PROPERTY( int frameWidth READ frameWidth )
Q_PROPERTY( QRect frameRect READ frameRect DESIGNABLE false )
public:
/*!
\brief Frame shadow
Unfortunately it is not possible to use QFrame::Shadow
as a property of a widget that is not derived from QFrame.
The following enum is made for the designer only. It is safe
to use QFrame::Shadow instead.
*/
enum Shadow
{
//! QFrame::Plain
Plain = QFrame::Plain,
//! QFrame::Raised
Raised = QFrame::Raised,
//! QFrame::Sunken
Sunken = QFrame::Sunken
};
/*!
\brief Frame shape
Unfortunately it is not possible to use QFrame::Shape
as a property of a widget that is not derived from QFrame.
The following enum is made for the designer only. It is safe
to use QFrame::Shadow instead.
\note QFrame::StyledPanel and QFrame::WinPanel are unsuported
and will be displayed as QFrame::Panel.
*/
enum Shape
{
NoFrame = QFrame::NoFrame,
Box = QFrame::Box,
Panel = QFrame::Panel
};
explicit QwtPlotGLCanvas( QwtPlot * = NULL );
virtual ~QwtPlotGLCanvas();
void setFrameStyle( int style );
int frameStyle() const;
void setFrameShadow( Shadow );
Shadow frameShadow() const;
void setFrameShape( Shape );
Shape frameShape() const;
void setLineWidth( int );
int lineWidth() const;
void setMidLineWidth( int );
int midLineWidth() const;
int frameWidth() const;
QRect frameRect() const;
Q_INVOKABLE QPainterPath borderPath( const QRect & ) const;
virtual bool event( QEvent * );
public Q_SLOTS:
void replot();
protected:
virtual void paintEvent( QPaintEvent * );
virtual void drawBackground( QPainter * );
virtual void drawBorder( QPainter * );
virtual void drawItems( QPainter * );
private:
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,438 @@
/* -*- 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_plot_grid.h"
#include "qwt_painter.h"
#include "qwt_text.h"
#include "qwt_scale_map.h"
#include "qwt_scale_div.h"
#include "qwt_math.h"
#include <qpainter.h>
#include <qpen.h>
class QwtPlotGrid::PrivateData
{
public:
PrivateData():
xEnabled( true ),
yEnabled( true ),
xMinEnabled( false ),
yMinEnabled( false )
{
}
bool xEnabled;
bool yEnabled;
bool xMinEnabled;
bool yMinEnabled;
QwtScaleDiv xScaleDiv;
QwtScaleDiv yScaleDiv;
QPen majorPen;
QPen minorPen;
};
//! Enables major grid, disables minor grid
QwtPlotGrid::QwtPlotGrid():
QwtPlotItem( QwtText( "Grid" ) )
{
d_data = new PrivateData;
setItemInterest( QwtPlotItem::ScaleInterest, true );
setZ( 10.0 );
}
//! Destructor
QwtPlotGrid::~QwtPlotGrid()
{
delete d_data;
}
//! \return QwtPlotItem::Rtti_PlotGrid
int QwtPlotGrid::rtti() const
{
return QwtPlotItem::Rtti_PlotGrid;
}
/*!
\brief Enable or disable vertical grid lines
\param on Enable (true) or disable
\sa Minor grid lines can be enabled or disabled with
enableXMin()
*/
void QwtPlotGrid::enableX( bool on )
{
if ( d_data->xEnabled != on )
{
d_data->xEnabled = on;
legendChanged();
itemChanged();
}
}
/*!
\brief Enable or disable horizontal grid lines
\param on Enable (true) or disable
\sa Minor grid lines can be enabled or disabled with enableYMin()
*/
void QwtPlotGrid::enableY( bool on )
{
if ( d_data->yEnabled != on )
{
d_data->yEnabled = on;
legendChanged();
itemChanged();
}
}
/*!
\brief Enable or disable minor vertical grid lines.
\param on Enable (true) or disable
\sa enableX()
*/
void QwtPlotGrid::enableXMin( bool on )
{
if ( d_data->xMinEnabled != on )
{
d_data->xMinEnabled = on;
legendChanged();
itemChanged();
}
}
/*!
\brief Enable or disable minor horizontal grid lines
\param on Enable (true) or disable
\sa enableY()
*/
void QwtPlotGrid::enableYMin( bool on )
{
if ( d_data->yMinEnabled != on )
{
d_data->yMinEnabled = on;
legendChanged();
itemChanged();
}
}
/*!
Assign an x axis scale division
\param scaleDiv Scale division
*/
void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv )
{
if ( d_data->xScaleDiv != scaleDiv )
{
d_data->xScaleDiv = scaleDiv;
itemChanged();
}
}
/*!
Assign a y axis division
\param scaleDiv Scale division
*/
void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv )
{
if ( d_data->yScaleDiv != scaleDiv )
{
d_data->yScaleDiv = scaleDiv;
itemChanged();
}
}
/*!
Build and assign a pen for both major and minor grid lines
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtPlotGrid::setPen( const QColor &color, qreal width, Qt::PenStyle style )
{
setPen( QPen( color, width, style ) );
}
/*!
Assign a pen for both major and minor grid lines
\param pen Pen
\sa setMajorPen(), setMinorPen()
*/
void QwtPlotGrid::setPen( const QPen &pen )
{
if ( d_data->majorPen != pen || d_data->minorPen != pen )
{
d_data->majorPen = pen;
d_data->minorPen = pen;
legendChanged();
itemChanged();
}
}
/*!
Build and assign a pen for both major grid lines
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtPlotGrid::setMajorPen( const QColor &color, qreal width, Qt::PenStyle style )
{
setMajorPen( QPen( color, width, style ) );
}
/*!
Assign a pen for the major grid lines
\param pen Pen
\sa majorPen(), setMinorPen(), setPen()
*/
void QwtPlotGrid::setMajorPen( const QPen &pen )
{
if ( d_data->majorPen != pen )
{
d_data->majorPen = pen;
legendChanged();
itemChanged();
}
}
/*!
Build and assign a pen for the minor grid lines
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtPlotGrid::setMinorPen( const QColor &color, qreal width, Qt::PenStyle style )
{
setMinorPen( QPen( color, width, style ) );
}
/*!
Assign a pen for the minor grid lines
\param pen Pen
\sa minorPen(), setMajorPen(), setPen()
*/
void QwtPlotGrid::setMinorPen( const QPen &pen )
{
if ( d_data->minorPen != pen )
{
d_data->minorPen = pen;
legendChanged();
itemChanged();
}
}
/*!
\brief Draw the grid
The grid is drawn into the bounding rectangle such that
grid lines begin and end at the rectangle's borders. The X and Y
maps are used to map the scale divisions into the drawing region
screen.
\param painter Painter
\param xMap X axis map
\param yMap Y axis
\param canvasRect Contents rectangle of the plot canvas
*/
void QwtPlotGrid::draw( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect ) const
{
// draw minor grid lines
QPen minorPen = d_data->minorPen;
minorPen.setCapStyle( Qt::FlatCap );
painter->setPen( minorPen );
if ( d_data->xEnabled && d_data->xMinEnabled )
{
drawLines( painter, canvasRect, Qt::Vertical, xMap,
d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
drawLines( painter, canvasRect, Qt::Vertical, xMap,
d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
}
if ( d_data->yEnabled && d_data->yMinEnabled )
{
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
}
// draw major grid lines
QPen majorPen = d_data->majorPen;
majorPen.setCapStyle( Qt::FlatCap );
painter->setPen( majorPen );
if ( d_data->xEnabled )
{
drawLines( painter, canvasRect, Qt::Vertical, xMap,
d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
}
if ( d_data->yEnabled )
{
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
}
}
void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect,
Qt::Orientation orientation, const QwtScaleMap &scaleMap,
const QList<double> &values ) const
{
const double x1 = canvasRect.left();
const double x2 = canvasRect.right() - 1.0;
const double y1 = canvasRect.top();
const double y2 = canvasRect.bottom() - 1.0;
const bool doAlign = QwtPainter::roundingAlignment( painter );
for ( int i = 0; i < values.count(); i++ )
{
double value = scaleMap.transform( values[i] );
if ( doAlign )
value = qRound( value );
if ( orientation == Qt::Horizontal )
{
if ( qwtFuzzyGreaterOrEqual( value, y1 ) &&
qwtFuzzyLessOrEqual( value, y2 ) )
{
QwtPainter::drawLine( painter, x1, value, x2, value );
}
}
else
{
if ( qwtFuzzyGreaterOrEqual( value, x1 ) &&
qwtFuzzyLessOrEqual( value, x2 ) )
{
QwtPainter::drawLine( painter, value, y1, value, y2 );
}
}
}
}
/*!
\return the pen for the major grid lines
\sa setMajorPen(), setMinorPen(), setPen()
*/
const QPen &QwtPlotGrid::majorPen() const
{
return d_data->majorPen;
}
/*!
\return the pen for the minor grid lines
\sa setMinorPen(), setMajorPen(), setPen()
*/
const QPen &QwtPlotGrid::minorPen() const
{
return d_data->minorPen;
}
/*!
\return true if vertical grid lines are enabled
\sa enableX()
*/
bool QwtPlotGrid::xEnabled() const
{
return d_data->xEnabled;
}
/*!
\return true if minor vertical grid lines are enabled
\sa enableXMin()
*/
bool QwtPlotGrid::xMinEnabled() const
{
return d_data->xMinEnabled;
}
/*!
\return true if horizontal grid lines are enabled
\sa enableY()
*/
bool QwtPlotGrid::yEnabled() const
{
return d_data->yEnabled;
}
/*!
\return true if minor horizontal grid lines are enabled
\sa enableYMin()
*/
bool QwtPlotGrid::yMinEnabled() const
{
return d_data->yMinEnabled;
}
/*! \return the scale division of the x axis */
const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const
{
return d_data->xScaleDiv;
}
/*! \return the scale division of the y axis */
const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const
{
return d_data->yScaleDiv;
}
/*!
Update the grid to changes of the axes scale division
\param xScaleDiv Scale division of the x-axis
\param yScaleDiv Scale division of the y-axis
\sa QwtPlot::updateAxes()
*/
void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
const QwtScaleDiv& yScaleDiv )
{
setXDiv( xScaleDiv );
setYDiv( yScaleDiv );
}

View File

@@ -0,0 +1,87 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_GRID_H
#define QWT_PLOT_GRID_H
#include "qwt_global.h"
#include "qwt_plot_item.h"
#include "qwt_scale_div.h"
class QPainter;
class QPen;
class QwtScaleMap;
class QwtScaleDiv;
/*!
\brief A class which draws a coordinate grid
The QwtPlotGrid class can be used to draw a coordinate grid.
A coordinate grid consists of major and minor vertical
and horizontal grid lines. The locations of the grid lines
are determined by the X and Y scale divisions which can
be assigned with setXDiv() and setYDiv().
The draw() member draws the grid within a bounding
rectangle.
*/
class QWT_EXPORT QwtPlotGrid: public QwtPlotItem
{
public:
explicit QwtPlotGrid();
virtual ~QwtPlotGrid();
virtual int rtti() const;
void enableX( bool tf );
bool xEnabled() const;
void enableY( bool tf );
bool yEnabled() const;
void enableXMin( bool tf );
bool xMinEnabled() const;
void enableYMin( bool tf );
bool yMinEnabled() const;
void setXDiv( const QwtScaleDiv &sx );
const QwtScaleDiv &xScaleDiv() const;
void setYDiv( const QwtScaleDiv &sy );
const QwtScaleDiv &yScaleDiv() const;
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setPen( const QPen & );
void setMajorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setMajorPen( const QPen & );
const QPen& majorPen() const;
void setMinorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setMinorPen( const QPen &p );
const QPen& minorPen() const;
virtual void draw( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &rect ) const;
virtual void updateScaleDiv(
const QwtScaleDiv &xMap, const QwtScaleDiv &yMap );
private:
void drawLines( QPainter *painter, const QRectF &,
Qt::Orientation orientation, const QwtScaleMap &,
const QList<double> & ) const;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,690 @@
/* -*- 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_plot_histogram.h"
#include "qwt_plot.h"
#include "qwt_painter.h"
#include "qwt_column_symbol.h"
#include "qwt_scale_map.h"
#include <qstring.h>
#include <qpainter.h>
static inline bool qwtIsCombinable( const QwtInterval &d1,
const QwtInterval &d2 )
{
if ( d1.isValid() && d2.isValid() )
{
if ( d1.maxValue() == d2.minValue() )
{
if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum
&& d2.borderFlags() & QwtInterval::ExcludeMinimum ) )
{
return true;
}
}
}
return false;
}
class QwtPlotHistogram::PrivateData
{
public:
PrivateData():
baseline( 0.0 ),
style( Columns ),
symbol( NULL )
{
}
~PrivateData()
{
delete symbol;
}
double baseline;
QPen pen;
QBrush brush;
QwtPlotHistogram::HistogramStyle style;
const QwtColumnSymbol *symbol;
};
/*!
Constructor
\param title Title of the histogram.
*/
QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ):
QwtPlotSeriesItem( title )
{
init();
}
/*!
Constructor
\param title Title of the histogram.
*/
QwtPlotHistogram::QwtPlotHistogram( const QString &title ):
QwtPlotSeriesItem( title )
{
init();
}
//! Destructor
QwtPlotHistogram::~QwtPlotHistogram()
{
delete d_data;
}
//! Initialize data members
void QwtPlotHistogram::init()
{
d_data = new PrivateData();
setData( new QwtIntervalSeriesData() );
setItemAttribute( QwtPlotItem::AutoScale, true );
setItemAttribute( QwtPlotItem::Legend, true );
setZ( 20.0 );
}
/*!
Set the histogram's drawing style
\param style Histogram style
\sa HistogramStyle, style()
*/
void QwtPlotHistogram::setStyle( HistogramStyle style )
{
if ( style != d_data->style )
{
d_data->style = style;
legendChanged();
itemChanged();
}
}
/*!
\return Style of the histogram
\sa HistogramStyle, setStyle()
*/
QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const
{
return d_data->style;
}
/*!
Build and assign a pen
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtPlotHistogram::setPen( const QColor &color, qreal width, Qt::PenStyle style )
{
setPen( QPen( color, width, style ) );
}
/*!
Assign a pen, that is used in a style() depending way.
\param pen New pen
\sa pen(), brush()
*/
void QwtPlotHistogram::setPen( const QPen &pen )
{
if ( pen != d_data->pen )
{
d_data->pen = pen;
legendChanged();
itemChanged();
}
}
/*!
\return Pen used in a style() depending way.
\sa setPen(), brush()
*/
const QPen &QwtPlotHistogram::pen() const
{
return d_data->pen;
}
/*!
Assign a brush, that is used in a style() depending way.
\param brush New brush
\sa pen(), brush()
*/
void QwtPlotHistogram::setBrush( const QBrush &brush )
{
if ( brush != d_data->brush )
{
d_data->brush = brush;
legendChanged();
itemChanged();
}
}
/*!
\return Brush used in a style() depending way.
\sa setPen(), brush()
*/
const QBrush &QwtPlotHistogram::brush() const
{
return d_data->brush;
}
/*!
\brief Assign a symbol
In Column style an optional symbol can be assigned, that is responsible
for displaying the rectangle that is defined by the interval and
the distance between baseline() and value. When no symbol has been
defined the area is displayed as plain rectangle using pen() and brush().
\sa style(), symbol(), drawColumn(), pen(), brush()
\note In applications, where different intervals need to be displayed
in a different way ( f.e different colors or even using different symbols)
it is recommended to overload drawColumn().
*/
void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol )
{
if ( symbol != d_data->symbol )
{
delete d_data->symbol;
d_data->symbol = symbol;
legendChanged();
itemChanged();
}
}
/*!
\return Current symbol or NULL, when no symbol has been assigned
\sa setSymbol()
*/
const QwtColumnSymbol *QwtPlotHistogram::symbol() const
{
return d_data->symbol;
}
/*!
\brief Set the value of the baseline
Each column representing an QwtIntervalSample is defined by its
interval and the interval between baseline and the value of the sample.
The default value of the baseline is 0.0.
\param value Value of the baseline
\sa baseline()
*/
void QwtPlotHistogram::setBaseline( double value )
{
if ( d_data->baseline != value )
{
d_data->baseline = value;
itemChanged();
}
}
/*!
\return Value of the baseline
\sa setBaseline()
*/
double QwtPlotHistogram::baseline() const
{
return d_data->baseline;
}
/*!
\return Bounding rectangle of all samples.
For an empty series the rectangle is invalid.
*/
QRectF QwtPlotHistogram::boundingRect() const
{
QRectF rect = data()->boundingRect();
if ( !rect.isValid() )
return rect;
if ( orientation() == Qt::Horizontal )
{
rect = QRectF( rect.y(), rect.x(),
rect.height(), rect.width() );
if ( rect.left() > d_data->baseline )
rect.setLeft( d_data->baseline );
else if ( rect.right() < d_data->baseline )
rect.setRight( d_data->baseline );
}
else
{
if ( rect.bottom() < d_data->baseline )
rect.setBottom( d_data->baseline );
else if ( rect.top() > d_data->baseline )
rect.setTop( d_data->baseline );
}
return rect;
}
//! \return QwtPlotItem::Rtti_PlotHistogram
int QwtPlotHistogram::rtti() const
{
return QwtPlotItem::Rtti_PlotHistogram;
}
/*!
Initialize data with an array of samples.
\param samples Vector of points
*/
void QwtPlotHistogram::setSamples(
const QVector<QwtIntervalSample> &samples )
{
setData( new QwtIntervalSeriesData( samples ) );
}
/*!
Assign a series of samples
setSamples() is just a wrapper for setData() without any additional
value - beside that it is easier to find for the developer.
\param data Data
\warning The item takes ownership of the data object, deleting
it when its not used anymore.
*/
void QwtPlotHistogram::setSamples(
QwtSeriesData<QwtIntervalSample> *data )
{
setData( data );
}
/*!
Draw a subset of the histogram samples
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param canvasRect Contents rectangle of the canvas
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
series will be painted to its last sample.
\sa drawOutline(), drawLines(), drawColumns
*/
void QwtPlotHistogram::drawSeries( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &, int from, int to ) const
{
if ( !painter || dataSize() <= 0 )
return;
if ( to < 0 )
to = dataSize() - 1;
switch ( d_data->style )
{
case Outline:
drawOutline( painter, xMap, yMap, from, to );
break;
case Lines:
drawLines( painter, xMap, yMap, from, to );
break;
case Columns:
drawColumns( painter, xMap, yMap, from, to );
break;
default:
break;
}
}
/*!
Draw a histogram in Outline style()
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
histogram will be painted to its last point.
\sa setStyle(), style()
\warning The outline style requires, that the intervals are in increasing
order and not overlapping.
*/
void QwtPlotHistogram::drawOutline( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const
{
const bool doAlign = QwtPainter::roundingAlignment( painter );
double v0 = ( orientation() == Qt::Horizontal ) ?
xMap.transform( baseline() ) : yMap.transform( baseline() );
if ( doAlign )
v0 = qRound( v0 );
QwtIntervalSample previous;
QPolygonF polygon;
for ( int i = from; i <= to; i++ )
{
const QwtIntervalSample sample = this->sample( i );
if ( !sample.interval.isValid() )
{
flushPolygon( painter, v0, polygon );
previous = sample;
continue;
}
if ( previous.interval.isValid() )
{
if ( !qwtIsCombinable( previous.interval, sample.interval ) )
flushPolygon( painter, v0, polygon );
}
if ( orientation() == Qt::Vertical )
{
double x1 = xMap.transform( sample.interval.minValue() );
double x2 = xMap.transform( sample.interval.maxValue() );
double y = yMap.transform( sample.value );
if ( doAlign )
{
x1 = qRound( x1 );
x2 = qRound( x2 );
y = qRound( y );
}
if ( polygon.size() == 0 )
polygon += QPointF( x1, v0 );
polygon += QPointF( x1, y );
polygon += QPointF( x2, y );
}
else
{
double y1 = yMap.transform( sample.interval.minValue() );
double y2 = yMap.transform( sample.interval.maxValue() );
double x = xMap.transform( sample.value );
if ( doAlign )
{
y1 = qRound( y1 );
y2 = qRound( y2 );
x = qRound( x );
}
if ( polygon.size() == 0 )
polygon += QPointF( v0, y1 );
polygon += QPointF( x, y1 );
polygon += QPointF( x, y2 );
}
previous = sample;
}
flushPolygon( painter, v0, polygon );
}
/*!
Draw a histogram in Columns style()
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
histogram will be painted to its last point.
\sa setStyle(), style(), setSymbol(), drawColumn()
*/
void QwtPlotHistogram::drawColumns( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const
{
painter->setPen( d_data->pen );
painter->setBrush( d_data->brush );
const QwtSeriesData<QwtIntervalSample> *series = data();
for ( int i = from; i <= to; i++ )
{
const QwtIntervalSample sample = series->sample( i );
if ( !sample.interval.isNull() )
{
const QwtColumnRect rect = columnRect( sample, xMap, yMap );
drawColumn( painter, rect, sample );
}
}
}
/*!
Draw a histogram in Lines style()
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
histogram will be painted to its last point.
\sa setStyle(), style(), setPen()
*/
void QwtPlotHistogram::drawLines( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const
{
const bool doAlign = QwtPainter::roundingAlignment( painter );
painter->setPen( d_data->pen );
painter->setBrush( Qt::NoBrush );
const QwtSeriesData<QwtIntervalSample> *series = data();
for ( int i = from; i <= to; i++ )
{
const QwtIntervalSample sample = series->sample( i );
if ( !sample.interval.isNull() )
{
const QwtColumnRect rect = columnRect( sample, xMap, yMap );
QRectF r = rect.toRect();
if ( doAlign )
{
r.setLeft( qRound( r.left() ) );
r.setRight( qRound( r.right() ) );
r.setTop( qRound( r.top() ) );
r.setBottom( qRound( r.bottom() ) );
}
switch ( rect.direction )
{
case QwtColumnRect::LeftToRight:
{
QwtPainter::drawLine( painter,
r.topRight(), r.bottomRight() );
break;
}
case QwtColumnRect::RightToLeft:
{
QwtPainter::drawLine( painter,
r.topLeft(), r.bottomLeft() );
break;
}
case QwtColumnRect::TopToBottom:
{
QwtPainter::drawLine( painter,
r.bottomRight(), r.bottomLeft() );
break;
}
case QwtColumnRect::BottomToTop:
{
QwtPainter::drawLine( painter,
r.topRight(), r.topLeft() );
break;
}
}
}
}
}
//! Internal, used by the Outline style.
void QwtPlotHistogram::flushPolygon( QPainter *painter,
double baseLine, QPolygonF &polygon ) const
{
if ( polygon.size() == 0 )
return;
if ( orientation() == Qt::Horizontal )
polygon += QPointF( baseLine, polygon.last().y() );
else
polygon += QPointF( polygon.last().x(), baseLine );
if ( d_data->brush.style() != Qt::NoBrush )
{
painter->setPen( Qt::NoPen );
painter->setBrush( d_data->brush );
if ( orientation() == Qt::Horizontal )
{
polygon += QPointF( polygon.last().x(), baseLine );
polygon += QPointF( polygon.first().x(), baseLine );
}
else
{
polygon += QPointF( baseLine, polygon.last().y() );
polygon += QPointF( baseLine, polygon.first().y() );
}
QwtPainter::drawPolygon( painter, polygon );
polygon.pop_back();
polygon.pop_back();
}
if ( d_data->pen.style() != Qt::NoPen )
{
painter->setBrush( Qt::NoBrush );
painter->setPen( d_data->pen );
QwtPainter::drawPolyline( painter, polygon );
}
polygon.clear();
}
/*!
Calculate the area that is covered by a sample
\param sample Sample
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\return Rectangle, that is covered by a sample
*/
QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample,
const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const
{
QwtColumnRect rect;
const QwtInterval &iv = sample.interval;
if ( !iv.isValid() )
return rect;
if ( orientation() == Qt::Horizontal )
{
const double x0 = xMap.transform( baseline() );
const double x = xMap.transform( sample.value );
const double y1 = yMap.transform( iv.minValue() );
const double y2 = yMap.transform( iv.maxValue() );
rect.hInterval.setInterval( x0, x );
rect.vInterval.setInterval( y1, y2, iv.borderFlags() );
rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft :
QwtColumnRect::LeftToRight;
}
else
{
const double x1 = xMap.transform( iv.minValue() );
const double x2 = xMap.transform( iv.maxValue() );
const double y0 = yMap.transform( baseline() );
const double y = yMap.transform( sample.value );
rect.hInterval.setInterval( x1, x2, iv.borderFlags() );
rect.vInterval.setInterval( y0, y );
rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop :
QwtColumnRect::TopToBottom;
}
return rect;
}
/*!
Draw a column for a sample in Columns style().
When a symbol() has been set the symbol is used otherwise the
column is displayed as plain rectangle using pen() and brush().
\param painter Painter
\param rect Rectangle where to paint the column in paint device coordinates
\param sample Sample to be displayed
\note In applications, where different intervals need to be displayed
in a different way ( f.e different colors or even using different symbols)
it is recommended to overload drawColumn().
*/
void QwtPlotHistogram::drawColumn( QPainter *painter,
const QwtColumnRect &rect, const QwtIntervalSample &sample ) const
{
Q_UNUSED( sample );
if ( d_data->symbol &&
( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) )
{
d_data->symbol->draw( painter, rect );
}
else
{
QRectF r = rect.toRect();
if ( QwtPainter::roundingAlignment( painter ) )
{
r.setLeft( qRound( r.left() ) );
r.setRight( qRound( r.right() ) );
r.setTop( qRound( r.top() ) );
r.setBottom( qRound( r.bottom() ) );
}
QwtPainter::drawRect( painter, r );
}
}
/*!
A plain rectangle without pen using the brush()
\param index Index of the legend entry
( ignored as there is only one )
\param size Icon size
\return A graphic displaying the icon
\sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
*/
QwtGraphic QwtPlotHistogram::legendIcon( int index,
const QSizeF &size ) const
{
Q_UNUSED( index );
return defaultIcon( d_data->brush, size );
}

View File

@@ -0,0 +1,139 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_HISTOGRAM_H
#define QWT_PLOT_HISTOGRAM_H
#include "qwt_global.h"
#include "qwt_plot_seriesitem.h"
#include "qwt_column_symbol.h"
#include <qcolor.h>
#include <qvector.h>
class QwtIntervalData;
class QString;
class QPolygonF;
/*!
\brief QwtPlotHistogram represents a series of samples, where an interval
is associated with a value ( \f$y = f([x1,x2])\f$ ).
The representation depends on the style() and an optional symbol()
that is displayed for each interval.
\note The term "histogram" is used in a different way in the areas of
digital image processing and statistics. Wikipedia introduces the
terms "image histogram" and "color histogram" to avoid confusions.
While "image histograms" can be displayed by a QwtPlotCurve there
is no applicable plot item for a "color histogram" yet.
\sa QwtPlotBarChart, QwtPlotMultiBarChart
*/
class QWT_EXPORT QwtPlotHistogram:
public QwtPlotSeriesItem, public QwtSeriesStore<QwtIntervalSample>
{
public:
/*!
Histogram styles.
The default style is QwtPlotHistogram::Columns.
\sa setStyle(), style(), setSymbol(), symbol(), setBaseline()
*/
enum HistogramStyle
{
/*!
Draw an outline around the area, that is build by all intervals
using the pen() and fill it with the brush(). The outline style
requires, that the intervals are in increasing order and
not overlapping.
*/
Outline,
/*!
Draw a column for each interval. When a symbol() has been set
the symbol is used otherwise the column is displayed as
plain rectangle using pen() and brush().
*/
Columns,
/*!
Draw a simple line using the pen() for each interval.
*/
Lines,
/*!
Styles >= UserStyle are reserved for derived
classes that overload drawSeries() with
additional application specific ways to display a histogram.
*/
UserStyle = 100
};
explicit QwtPlotHistogram( const QString &title = QString::null );
explicit QwtPlotHistogram( const QwtText &title );
virtual ~QwtPlotHistogram();
virtual int rtti() const;
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setPen( const QPen & );
const QPen &pen() const;
void setBrush( const QBrush & );
const QBrush &brush() const;
void setSamples( const QVector<QwtIntervalSample> & );
void setSamples( QwtSeriesData<QwtIntervalSample> * );
void setBaseline( double reference );
double baseline() const;
void setStyle( HistogramStyle style );
HistogramStyle style() const;
void setSymbol( const QwtColumnSymbol * );
const QwtColumnSymbol *symbol() const;
virtual void drawSeries( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual QRectF boundingRect() const;
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
protected:
virtual QwtColumnRect columnRect( const QwtIntervalSample &,
const QwtScaleMap &, const QwtScaleMap & ) const;
virtual void drawColumn( QPainter *, const QwtColumnRect &,
const QwtIntervalSample & ) const;
void drawColumns( QPainter *,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const;
void drawOutline( QPainter *,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const;
void drawLines( QPainter *,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
int from, int to ) const;
private:
void init();
void flushPolygon( QPainter *, double baseLine, QPolygonF & ) const;
class PrivateData;
PrivateData *d_data;
};
#endif

View File

@@ -0,0 +1,603 @@
/* -*- 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_plot_intervalcurve.h"
#include "qwt_interval_symbol.h"
#include "qwt_scale_map.h"
#include "qwt_clipper.h"
#include "qwt_painter.h"
#include <string.h>
#include <qpainter.h>
static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample,
double xMin, double xMax, double yMin, double yMax )
{
const double y = sample.value;
const double x1 = sample.interval.minValue();
const double x2 = sample.interval.maxValue();
const bool isOffScreen = ( y < yMin ) || ( y > yMax )
|| ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax );
return !isOffScreen;
}
static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample,
double xMin, double xMax, double yMin, double yMax )
{
const double x = sample.value;
const double y1 = sample.interval.minValue();
const double y2 = sample.interval.maxValue();
const bool isOffScreen = ( x < xMin ) || ( x > xMax )
|| ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax );
return !isOffScreen;
}
class QwtPlotIntervalCurve::PrivateData
{
public:
PrivateData():
style( QwtPlotIntervalCurve::Tube ),
symbol( NULL ),
pen( Qt::black ),
brush( Qt::white )
{
paintAttributes = QwtPlotIntervalCurve::ClipPolygons;
paintAttributes |= QwtPlotIntervalCurve::ClipSymbol;
pen.setCapStyle( Qt::FlatCap );
}
~PrivateData()
{
delete symbol;
}
QwtPlotIntervalCurve::CurveStyle style;
const QwtIntervalSymbol *symbol;
QPen pen;
QBrush brush;
QwtPlotIntervalCurve::PaintAttributes paintAttributes;
};
/*!
Constructor
\param title Title of the curve
*/
QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ):
QwtPlotSeriesItem( title )
{
init();
}
/*!
Constructor
\param title Title of the curve
*/
QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ):
QwtPlotSeriesItem( QwtText( title ) )
{
init();
}
//! Destructor
QwtPlotIntervalCurve::~QwtPlotIntervalCurve()
{
delete d_data;
}
//! Initialize internal members
void QwtPlotIntervalCurve::init()
{
setItemAttribute( QwtPlotItem::Legend, true );
setItemAttribute( QwtPlotItem::AutoScale, true );
d_data = new PrivateData;
setData( new QwtIntervalSeriesData() );
setZ( 19.0 );
}
//! \return QwtPlotItem::Rtti_PlotIntervalCurve
int QwtPlotIntervalCurve::rtti() const
{
return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve;
}
/*!
Specify an attribute how to draw the curve
\param attribute Paint attribute
\param on On/Off
\sa testPaintAttribute()
*/
void QwtPlotIntervalCurve::setPaintAttribute(
PaintAttribute attribute, bool on )
{
if ( on )
d_data->paintAttributes |= attribute;
else
d_data->paintAttributes &= ~attribute;
}
/*!
\return True, when attribute is enabled
\sa PaintAttribute, setPaintAttribute()
*/
bool QwtPlotIntervalCurve::testPaintAttribute(
PaintAttribute attribute ) const
{
return ( d_data->paintAttributes & attribute );
}
/*!
Initialize data with an array of samples.
\param samples Vector of samples
*/
void QwtPlotIntervalCurve::setSamples(
const QVector<QwtIntervalSample> &samples )
{
setData( new QwtIntervalSeriesData( samples ) );
}
/*!
Assign a series of samples
setSamples() is just a wrapper for setData() without any additional
value - beside that it is easier to find for the developer.
\param data Data
\warning The item takes ownership of the data object, deleting
it when its not used anymore.
*/
void QwtPlotIntervalCurve::setSamples(
QwtSeriesData<QwtIntervalSample> *data )
{
setData( data );
}
/*!
Set the curve's drawing style
\param style Curve style
\sa CurveStyle, style()
*/
void QwtPlotIntervalCurve::setStyle( CurveStyle style )
{
if ( style != d_data->style )
{
d_data->style = style;
legendChanged();
itemChanged();
}
}
/*!
\return Style of the curve
\sa setStyle()
*/
QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const
{
return d_data->style;
}
/*!
Assign a symbol.
\param symbol Symbol
\sa symbol()
*/
void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol )
{
if ( symbol != d_data->symbol )
{
delete d_data->symbol;
d_data->symbol = symbol;
legendChanged();
itemChanged();
}
}
/*!
\return Current symbol or NULL, when no symbol has been assigned
\sa setSymbol()
*/
const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const
{
return d_data->symbol;
}
/*!
Build and assign a pen
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
to hide this incompatibility.
\param color Pen color
\param width Pen width
\param style Pen style
\sa pen(), brush()
*/
void QwtPlotIntervalCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style )
{
setPen( QPen( color, width, style ) );
}
/*!
\brief Assign a pen
\param pen New pen
\sa pen(), brush()
*/
void QwtPlotIntervalCurve::setPen( const QPen &pen )
{
if ( pen != d_data->pen )
{
d_data->pen = pen;
legendChanged();
itemChanged();
}
}
/*!
\return Pen used to draw the lines
\sa setPen(), brush()
*/
const QPen& QwtPlotIntervalCurve::pen() const
{
return d_data->pen;
}
/*!
Assign a brush.
The brush is used to fill the area in Tube style().
\param brush Brush
\sa brush(), pen(), setStyle(), CurveStyle
*/
void QwtPlotIntervalCurve::setBrush( const QBrush &brush )
{
if ( brush != d_data->brush )
{
d_data->brush = brush;
legendChanged();
itemChanged();
}
}
/*!
\return Brush used to fill the area in Tube style()
\sa setBrush(), setStyle(), CurveStyle
*/
const QBrush& QwtPlotIntervalCurve::brush() const
{
return d_data->brush;
}
/*!
\return Bounding rectangle of all samples.
For an empty series the rectangle is invalid.
*/
QRectF QwtPlotIntervalCurve::boundingRect() const
{
QRectF rect = QwtPlotSeriesItem::boundingRect();
if ( rect.isValid() && orientation() == Qt::Vertical )
rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
return rect;
}
/*!
Draw a subset of the samples
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param canvasRect Contents rectangle of the canvas
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
series will be painted to its last sample.
\sa drawTube(), drawSymbols()
*/
void QwtPlotIntervalCurve::drawSeries( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const
{
if ( to < 0 )
to = dataSize() - 1;
if ( from < 0 )
from = 0;
if ( from > to )
return;
switch ( d_data->style )
{
case Tube:
drawTube( painter, xMap, yMap, canvasRect, from, to );
break;
case NoCurve:
default:
break;
}
if ( d_data->symbol &&
( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
{
drawSymbols( painter, *d_data->symbol,
xMap, yMap, canvasRect, from, to );
}
}
/*!
Draw a tube
Builds 2 curves from the upper and lower limits of the intervals
and draws them with the pen(). The area between the curves is
filled with the brush().
\param painter Painter
\param xMap Maps x-values into pixel coordinates.
\param yMap Maps y-values into pixel coordinates.
\param canvasRect Contents rectangle of the canvas
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted. If to < 0 the
series will be painted to its last sample.
\sa drawSeries(), drawSymbols()
*/
void QwtPlotIntervalCurve::drawTube( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const
{
const bool doAlign = QwtPainter::roundingAlignment( painter );
painter->save();
const size_t size = to - from + 1;
QPolygonF polygon( 2 * size );
QPointF *points = polygon.data();
for ( uint i = 0; i < size; i++ )
{
QPointF &minValue = points[i];
QPointF &maxValue = points[2 * size - 1 - i];
const QwtIntervalSample intervalSample = sample( from + i );
if ( orientation() == Qt::Vertical )
{
double x = xMap.transform( intervalSample.value );
double y1 = yMap.transform( intervalSample.interval.minValue() );
double y2 = yMap.transform( intervalSample.interval.maxValue() );
if ( doAlign )
{
x = qRound( x );
y1 = qRound( y1 );
y2 = qRound( y2 );
}
minValue.rx() = x;
minValue.ry() = y1;
maxValue.rx() = x;
maxValue.ry() = y2;
}
else
{
double y = yMap.transform( intervalSample.value );
double x1 = xMap.transform( intervalSample.interval.minValue() );
double x2 = xMap.transform( intervalSample.interval.maxValue() );
if ( doAlign )
{
y = qRound( y );
x1 = qRound( x1 );
x2 = qRound( x2 );
}
minValue.rx() = x1;
minValue.ry() = y;
maxValue.rx() = x2;
maxValue.ry() = y;
}
}
if ( d_data->brush.style() != Qt::NoBrush )
{
painter->setPen( QPen( Qt::NoPen ) );
painter->setBrush( d_data->brush );
if ( d_data->paintAttributes & ClipPolygons )
{
const qreal m = 1.0;
const QPolygonF p = QwtClipper::clipPolygonF(
canvasRect.adjusted( -m, -m, m, m ), polygon, true );
QwtPainter::drawPolygon( painter, p );
}
else
{
QwtPainter::drawPolygon( painter, polygon );
}
}
if ( d_data->pen.style() != Qt::NoPen )
{
painter->setPen( d_data->pen );
painter->setBrush( Qt::NoBrush );
if ( d_data->paintAttributes & ClipPolygons )
{
qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() );
const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw );
QPolygonF p;
p.resize( size );
::memcpy( p.data(), points, size * sizeof( QPointF ) );
p = QwtClipper::clipPolygonF( clipRect, p );
QwtPainter::drawPolyline( painter, p );
p.resize( size );
::memcpy( p.data(), points + size, size * sizeof( QPointF ) );
p = QwtClipper::clipPolygonF( clipRect, p );
QwtPainter::drawPolyline( painter, p );
}
else
{
QwtPainter::drawPolyline( painter, points, size );
QwtPainter::drawPolyline( painter, points + size, size );
}
}
painter->restore();
}
/*!
Draw symbols for a subset of the samples
\param painter Painter
\param symbol Interval symbol
\param xMap x map
\param yMap y map
\param canvasRect Contents rectangle of the canvas
\param from Index of the first sample to be painted
\param to Index of the last sample to be painted
\sa setSymbol(), drawSeries(), drawTube()
*/
void QwtPlotIntervalCurve::drawSymbols(
QPainter *painter, const QwtIntervalSymbol &symbol,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const
{
painter->save();
QPen pen = symbol.pen();
pen.setCapStyle( Qt::FlatCap );
painter->setPen( pen );
painter->setBrush( symbol.brush() );
const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
const double xMin = tr.left();
const double xMax = tr.right();
const double yMin = tr.top();
const double yMax = tr.bottom();
const bool doClip = d_data->paintAttributes & ClipSymbol;
for ( int i = from; i <= to; i++ )
{
const QwtIntervalSample s = sample( i );
if ( orientation() == Qt::Vertical )
{
if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) )
{
const double x = xMap.transform( s.value );
const double y1 = yMap.transform( s.interval.minValue() );
const double y2 = yMap.transform( s.interval.maxValue() );
symbol.draw( painter, orientation(),
QPointF( x, y1 ), QPointF( x, y2 ) );
}
}
else
{
if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) )
{
const double y = yMap.transform( s.value );
const double x1 = xMap.transform( s.interval.minValue() );
const double x2 = xMap.transform( s.interval.maxValue() );
symbol.draw( painter, orientation(),
QPointF( x1, y ), QPointF( x2, y ) );
}
}
}
painter->restore();
}
/*!
\return Icon for the legend
In case of Tube style() the icon is a plain rectangle filled with the brush().
If a symbol is assigned it is scaled to size.
\param index Index of the legend entry
( ignored as there is only one )
\param size Icon size
\sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
*/
QwtGraphic QwtPlotIntervalCurve::legendIcon(
int index, const QSizeF &size ) const
{
Q_UNUSED( index );
if ( size.isEmpty() )
return QwtGraphic();
QwtGraphic icon;
icon.setDefaultSize( size );
icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
QPainter painter( &icon );
painter.setRenderHint( QPainter::Antialiasing,
testRenderHint( QwtPlotItem::RenderAntialiased ) );
if ( d_data->style == Tube )
{
QRectF r( 0, 0, size.width(), size.height() );
painter.fillRect( r, d_data->brush );
}
if ( d_data->symbol &&
( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
{
QPen pen = d_data->symbol->pen();
pen.setWidthF( pen.widthF() );
pen.setCapStyle( Qt::FlatCap );
painter.setPen( pen );
painter.setBrush( d_data->symbol->brush() );
if ( orientation() == Qt::Vertical )
{
const double x = 0.5 * size.width();
d_data->symbol->draw( &painter, orientation(),
QPointF( x, 0 ), QPointF( x, size.height() - 1.0 ) );
}
else
{
const double y = 0.5 * size.height();
d_data->symbol->draw( &painter, orientation(),
QPointF( 0.0, y ), QPointF( size.width() - 1.0, y ) );
}
}
return icon;
}

View File

@@ -0,0 +1,132 @@
/* -*- 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
*****************************************************************************/
#ifndef QWT_PLOT_INTERVAL_CURVE_H
#define QWT_PLOT_INTERVAL_CURVE_H
#include "qwt_global.h"
#include "qwt_plot_seriesitem.h"
#include "qwt_series_data.h"
class QwtIntervalSymbol;
/*!
\brief QwtPlotIntervalCurve represents a series of samples, where each value
is associated with an interval ( \f$[y1,y2] = f(x)\f$ ).
The representation depends on the style() and an optional symbol()
that is displayed for each interval. QwtPlotIntervalCurve might be used
to display error bars or the area between 2 curves.
*/
class QWT_EXPORT QwtPlotIntervalCurve:
public QwtPlotSeriesItem, public QwtSeriesStore<QwtIntervalSample>
{
public:
/*!
\brief Curve styles.
The default setting is QwtPlotIntervalCurve::Tube.
\sa setStyle(), style()
*/
enum CurveStyle
{
/*!
Don't draw a curve. Note: This doesn't affect the symbols.
*/
NoCurve,
/*!
Build 2 curves from the upper and lower limits of the intervals
and draw them with the pen(). The area between the curves is
filled with the brush().
*/
Tube,
/*!
Styles >= QwtPlotIntervalCurve::UserCurve are reserved for derived
classes that overload drawSeries() with
additional application specific curve types.
*/
UserCurve = 100
};
/*!
Attributes to modify the drawing algorithm.
\sa setPaintAttribute(), testPaintAttribute()
*/
enum PaintAttribute
{
/*!
Clip polygons before painting them. In situations, where points
are far outside the visible area (f.e when zooming deep) this
might be a substantial improvement for the painting performance.
*/
ClipPolygons = 0x01,
//! Check if a symbol is on the plot canvas before painting it.
ClipSymbol = 0x02
};
//! Paint attributes
typedef QFlags<PaintAttribute> PaintAttributes;
explicit QwtPlotIntervalCurve( const QString &title = QString::null );
explicit QwtPlotIntervalCurve( const QwtText &title );
virtual ~QwtPlotIntervalCurve();
virtual int rtti() const;
void setPaintAttribute( PaintAttribute, bool on = true );
bool testPaintAttribute( PaintAttribute ) const;
void setSamples( const QVector<QwtIntervalSample> & );
void setSamples( QwtSeriesData<QwtIntervalSample> * );
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
void setPen( const QPen & );
const QPen &pen() const;
void setBrush( const QBrush & );
const QBrush &brush() const;
void setStyle( CurveStyle style );
CurveStyle style() const;
void setSymbol( const QwtIntervalSymbol * );
const QwtIntervalSymbol *symbol() const;
virtual void drawSeries( QPainter *p,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual QRectF boundingRect() const;
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
protected:
void init();
virtual void drawTube( QPainter *,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
virtual void drawSymbols( QPainter *, const QwtIntervalSymbol &,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect, int from, int to ) const;
private:
class PrivateData;
PrivateData *d_data;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotIntervalCurve::PaintAttributes )
#endif

Some files were not shown because too many files have changed in this diff Show More