Released version 6.1.3

This commit is contained in:
Wodann 2018-08-02 11:01:31 -04:00
commit a94503cb82
195 changed files with 276310 additions and 0 deletions

22
src/qwt.h Normal file
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;
}

71
src/qwt_abstract_legend.h Normal file
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

449
src/qwt_abstract_scale.cpp Normal file
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 );
}

105
src/qwt_abstract_scale.h Normal file
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

822
src/qwt_abstract_slider.cpp Normal file
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();
}

167
src/qwt_abstract_slider.h Normal file
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

244
src/qwt_analog_clock.cpp Normal file
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 );
}
}

93
src/qwt_analog_clock.h Normal file
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

333
src/qwt_arrow_button.cpp Normal file
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 );
}

52
src/qwt_arrow_button.h Normal file
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

510
src/qwt_clipper.cpp Normal file
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 );
}

40
src/qwt_clipper.h Normal file
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

499
src/qwt_color_map.cpp Normal file
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;
}

200
src/qwt_color_map.h Normal file
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

293
src/qwt_column_symbol.cpp Normal file
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() );
}
}
}

161
src/qwt_column_symbol.h Normal file
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

308
src/qwt_compass.cpp Normal file
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 );
}
}

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