Released version 6.1.3
This commit is contained in:
commit
a94503cb82
195 changed files with 276310 additions and 0 deletions
22
src/qwt.h
Normal file
22
src/qwt.h
Normal 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
|
||||
38
src/qwt_abstract_legend.cpp
Normal file
38
src/qwt_abstract_legend.cpp
Normal 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
71
src/qwt_abstract_legend.h
Normal 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
449
src/qwt_abstract_scale.cpp
Normal 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
105
src/qwt_abstract_scale.h
Normal 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
|
||||
420
src/qwt_abstract_scale_draw.cpp
Normal file
420
src/qwt_abstract_scale_draw.cpp
Normal 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();
|
||||
}
|
||||
141
src/qwt_abstract_scale_draw.h
Normal file
141
src/qwt_abstract_scale_draw.h
Normal 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
822
src/qwt_abstract_slider.cpp
Normal 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
167
src/qwt_abstract_slider.h
Normal 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
244
src/qwt_analog_clock.cpp
Normal 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 ¢er,
|
||||
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 ¢er, 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
93
src/qwt_analog_clock.h
Normal 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
333
src/qwt_arrow_button.cpp
Normal 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
52
src/qwt_arrow_button.h
Normal 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
510
src/qwt_clipper.cpp
Normal 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 ¢er, double radius )
|
||||
{
|
||||
QwtCircleClipper clipper( clipRect );
|
||||
return clipper.clipCircle( center, radius );
|
||||
}
|
||||
40
src/qwt_clipper.h
Normal file
40
src/qwt_clipper.h
Normal 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
499
src/qwt_color_map.cpp
Normal 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
200
src/qwt_color_map.h
Normal 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
293
src/qwt_column_symbol.cpp
Normal 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
161
src/qwt_column_symbol.h
Normal 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
308
src/qwt_compass.cpp
Normal 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 ¢er, 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 ¢er,
|
||||
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
Loading…
Reference in a new issue