AVT相机arm版本SDK
This commit is contained in:
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_COMPASS_H
|
||||
#define QWT_COMPASS_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_dial.h"
|
||||
#include "qwt_round_scale_draw.h"
|
||||
#include <qstring.h>
|
||||
#include <qmap.h>
|
||||
|
||||
class QwtCompassRose;
|
||||
|
||||
/*!
|
||||
\brief A special scale draw made for QwtCompass
|
||||
|
||||
QwtCompassScaleDraw maps values to strings using
|
||||
a special map, that can be modified by the application
|
||||
|
||||
The default map consists of the labels N, NE, E, SE, S, SW, W, NW.
|
||||
|
||||
\sa QwtCompass
|
||||
*/
|
||||
class QWT_EXPORT QwtCompassScaleDraw: public QwtRoundScaleDraw
|
||||
{
|
||||
public:
|
||||
explicit QwtCompassScaleDraw();
|
||||
explicit QwtCompassScaleDraw( const QMap<double, QString> &map );
|
||||
|
||||
void setLabelMap( const QMap<double, QString> &map );
|
||||
QMap<double, QString> labelMap() const;
|
||||
|
||||
virtual QwtText label( double value ) const;
|
||||
|
||||
private:
|
||||
QMap<double, QString> d_labelMap;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A Compass Widget
|
||||
|
||||
QwtCompass is a widget to display and enter directions. It consists
|
||||
of a scale, an optional needle and rose.
|
||||
|
||||
\image html dials1.png
|
||||
|
||||
\note The examples/dials example shows how to use QwtCompass.
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtCompass: public QwtDial
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QwtCompass( QWidget* parent = NULL );
|
||||
virtual ~QwtCompass();
|
||||
|
||||
void setRose( QwtCompassRose *rose );
|
||||
const QwtCompassRose *rose() const;
|
||||
QwtCompassRose *rose();
|
||||
|
||||
protected:
|
||||
virtual void drawRose( QPainter *, const QPointF ¢er,
|
||||
double radius, double north, QPalette::ColorGroup ) const;
|
||||
|
||||
virtual void drawScaleContents( QPainter *,
|
||||
const QPointF ¢er, double radius ) const;
|
||||
|
||||
virtual void keyPressEvent( QKeyEvent * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,269 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_compass_rose.h"
|
||||
#include "qwt_point_polar.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qpainter.h>
|
||||
|
||||
static QPointF qwtIntersection(
|
||||
QPointF p11, QPointF p12, QPointF p21, QPointF p22 )
|
||||
{
|
||||
const QLineF line1( p11, p12 );
|
||||
const QLineF line2( p21, p22 );
|
||||
|
||||
QPointF pos;
|
||||
if ( line1.intersect( line2, &pos ) == QLineF::NoIntersection )
|
||||
return QPointF();
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
class QwtSimpleCompassRose::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
width( 0.2 ),
|
||||
numThorns( 8 ),
|
||||
numThornLevels( -1 ),
|
||||
shrinkFactor( 0.9 )
|
||||
{
|
||||
}
|
||||
|
||||
double width;
|
||||
int numThorns;
|
||||
int numThornLevels;
|
||||
double shrinkFactor;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\param numThorns Number of thorns
|
||||
\param numThornLevels Number of thorn levels
|
||||
*/
|
||||
QwtSimpleCompassRose::QwtSimpleCompassRose(
|
||||
int numThorns, int numThornLevels )
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
d_data->numThorns = numThorns;
|
||||
d_data->numThornLevels = numThornLevels;
|
||||
|
||||
const QColor dark( 128, 128, 255 );
|
||||
const QColor light( 192, 255, 255 );
|
||||
|
||||
QPalette palette;
|
||||
palette.setColor( QPalette::Dark, dark );
|
||||
palette.setColor( QPalette::Light, light );
|
||||
|
||||
setPalette( palette );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtSimpleCompassRose::~QwtSimpleCompassRose()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the Factor how to shrink the thorns with each level
|
||||
The default value is 0.9.
|
||||
|
||||
\param factor Shrink factor
|
||||
\sa shrinkFactor()
|
||||
*/
|
||||
void QwtSimpleCompassRose::setShrinkFactor( double factor )
|
||||
{
|
||||
d_data->shrinkFactor = factor;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Factor how to shrink the thorns with each level
|
||||
\sa setShrinkFactor()
|
||||
*/
|
||||
double QwtSimpleCompassRose::shrinkFactor() const
|
||||
{
|
||||
return d_data->shrinkFactor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the rose
|
||||
|
||||
\param painter Painter
|
||||
\param center Center point
|
||||
\param radius Radius of the rose
|
||||
\param north Position
|
||||
\param cg Color group
|
||||
*/
|
||||
void QwtSimpleCompassRose::draw( QPainter *painter, const QPointF ¢er,
|
||||
double radius, double north, QPalette::ColorGroup cg ) const
|
||||
{
|
||||
QPalette pal = palette();
|
||||
pal.setCurrentColorGroup( cg );
|
||||
|
||||
drawRose( painter, pal, center, radius, north, d_data->width,
|
||||
d_data->numThorns, d_data->numThornLevels, d_data->shrinkFactor );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the rose
|
||||
|
||||
\param painter Painter
|
||||
\param palette Palette
|
||||
\param center Center of the rose
|
||||
\param radius Radius of the rose
|
||||
\param north Position pointing to north
|
||||
\param width Width of the rose
|
||||
\param numThorns Number of thorns
|
||||
\param numThornLevels Number of thorn levels
|
||||
\param shrinkFactor Factor to shrink the thorns with each level
|
||||
*/
|
||||
void QwtSimpleCompassRose::drawRose(
|
||||
QPainter *painter,
|
||||
const QPalette &palette,
|
||||
const QPointF ¢er, double radius, double north, double width,
|
||||
int numThorns, int numThornLevels, double shrinkFactor )
|
||||
{
|
||||
if ( numThorns < 4 )
|
||||
numThorns = 4;
|
||||
|
||||
if ( numThorns % 4 )
|
||||
numThorns += 4 - numThorns % 4;
|
||||
|
||||
if ( numThornLevels <= 0 )
|
||||
numThornLevels = numThorns / 4;
|
||||
|
||||
if ( shrinkFactor >= 1.0 )
|
||||
shrinkFactor = 1.0;
|
||||
|
||||
if ( shrinkFactor <= 0.5 )
|
||||
shrinkFactor = 0.5;
|
||||
|
||||
painter->save();
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
|
||||
for ( int j = 1; j <= numThornLevels; j++ )
|
||||
{
|
||||
double step = qPow( 2.0, j ) * M_PI / numThorns;
|
||||
if ( step > M_PI_2 )
|
||||
break;
|
||||
|
||||
double r = radius;
|
||||
for ( int k = 0; k < 3; k++ )
|
||||
{
|
||||
if ( j + k < numThornLevels )
|
||||
r *= shrinkFactor;
|
||||
}
|
||||
|
||||
double leafWidth = r * width;
|
||||
if ( 2.0 * M_PI / step > 32 )
|
||||
leafWidth = 16;
|
||||
|
||||
const double origin = qwtRadians( north );
|
||||
for ( double angle = origin;
|
||||
angle < 2.0 * M_PI + origin; angle += step )
|
||||
{
|
||||
const QPointF p = qwtPolar2Pos( center, r, angle );
|
||||
const QPointF p1 = qwtPolar2Pos( center, leafWidth, angle + M_PI_2 );
|
||||
const QPointF p2 = qwtPolar2Pos( center, leafWidth, angle - M_PI_2 );
|
||||
const QPointF p3 = qwtPolar2Pos( center, r, angle + step / 2.0 );
|
||||
const QPointF p4 = qwtPolar2Pos( center, r, angle - step / 2.0 );
|
||||
|
||||
QPainterPath darkPath;
|
||||
darkPath.moveTo( center );
|
||||
darkPath.lineTo( p );
|
||||
darkPath.lineTo( qwtIntersection( center, p3, p1, p ) );
|
||||
|
||||
painter->setBrush( palette.brush( QPalette::Dark ) );
|
||||
painter->drawPath( darkPath );
|
||||
|
||||
QPainterPath lightPath;
|
||||
lightPath.moveTo( center );
|
||||
lightPath.lineTo( p );
|
||||
lightPath.lineTo( qwtIntersection( center, p4, p2, p ) );
|
||||
|
||||
painter->setBrush( palette.brush( QPalette::Light ) );
|
||||
painter->drawPath( lightPath );
|
||||
}
|
||||
}
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the width of the rose heads. Lower value make thinner heads.
|
||||
The range is limited from 0.03 to 0.4.
|
||||
|
||||
\param width Width
|
||||
*/
|
||||
void QwtSimpleCompassRose::setWidth( double width )
|
||||
{
|
||||
d_data->width = width;
|
||||
if ( d_data->width < 0.03 )
|
||||
d_data->width = 0.03;
|
||||
|
||||
if ( d_data->width > 0.4 )
|
||||
d_data->width = 0.4;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Width of the rose
|
||||
\sa setWidth()
|
||||
*/
|
||||
double QwtSimpleCompassRose::width() const
|
||||
{
|
||||
return d_data->width;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the number of thorns on one level
|
||||
The number is aligned to a multiple of 4, with a minimum of 4
|
||||
|
||||
\param numThorns Number of thorns
|
||||
\sa numThorns(), setNumThornLevels()
|
||||
*/
|
||||
void QwtSimpleCompassRose::setNumThorns( int numThorns )
|
||||
{
|
||||
if ( numThorns < 4 )
|
||||
numThorns = 4;
|
||||
|
||||
if ( numThorns % 4 )
|
||||
numThorns += 4 - numThorns % 4;
|
||||
|
||||
d_data->numThorns = numThorns;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of thorns
|
||||
\sa setNumThorns(), setNumThornLevels()
|
||||
*/
|
||||
int QwtSimpleCompassRose::numThorns() const
|
||||
{
|
||||
return d_data->numThorns;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the of thorns levels
|
||||
|
||||
\param numThornLevels Number of thorns levels
|
||||
\sa setNumThorns(), numThornLevels()
|
||||
*/
|
||||
void QwtSimpleCompassRose::setNumThornLevels( int numThornLevels )
|
||||
{
|
||||
d_data->numThornLevels = numThornLevels;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of thorn levels
|
||||
\sa setNumThorns(), setNumThornLevels()
|
||||
*/
|
||||
int QwtSimpleCompassRose::numThornLevels() const
|
||||
{
|
||||
return d_data->numThornLevels;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_COMPASS_ROSE_H
|
||||
#define QWT_COMPASS_ROSE_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpalette.h>
|
||||
|
||||
class QPainter;
|
||||
|
||||
/*!
|
||||
\brief Abstract base class for a compass rose
|
||||
*/
|
||||
class QWT_EXPORT QwtCompassRose
|
||||
{
|
||||
public:
|
||||
//! Destructor
|
||||
virtual ~QwtCompassRose() {};
|
||||
|
||||
//! Assign a palette
|
||||
virtual void setPalette( const QPalette &p )
|
||||
{
|
||||
d_palette = p;
|
||||
}
|
||||
|
||||
//! \return Current palette
|
||||
const QPalette &palette() const
|
||||
{
|
||||
return d_palette;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the rose
|
||||
|
||||
\param painter Painter
|
||||
\param center Center point
|
||||
\param radius Radius of the rose
|
||||
\param north Position
|
||||
\param colorGroup Color group
|
||||
*/
|
||||
virtual void draw( QPainter *painter,
|
||||
const QPointF ¢er, double radius, double north,
|
||||
QPalette::ColorGroup colorGroup = QPalette::Active ) const = 0;
|
||||
|
||||
private:
|
||||
QPalette d_palette;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A simple rose for QwtCompass
|
||||
*/
|
||||
class QWT_EXPORT QwtSimpleCompassRose: public QwtCompassRose
|
||||
{
|
||||
public:
|
||||
QwtSimpleCompassRose( int numThorns = 8, int numThornLevels = -1 );
|
||||
virtual ~QwtSimpleCompassRose();
|
||||
|
||||
void setWidth( double w );
|
||||
double width() const;
|
||||
|
||||
void setNumThorns( int count );
|
||||
int numThorns() const;
|
||||
|
||||
void setNumThornLevels( int count );
|
||||
int numThornLevels() const;
|
||||
|
||||
void setShrinkFactor( double factor );
|
||||
double shrinkFactor() const;
|
||||
|
||||
virtual void draw( QPainter *, const QPointF ¢er, double radius,
|
||||
double north, QPalette::ColorGroup = QPalette::Active ) const;
|
||||
|
||||
static void drawRose( QPainter *, const QPalette &,
|
||||
const QPointF ¢er, double radius, double origin, double width,
|
||||
int numThorns, int numThornLevels, double shrinkFactor );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _QWT_COMPAT_H_
|
||||
#define _QWT_COMPAT_H_
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_interval.h"
|
||||
#include "qwt_point_3d.h"
|
||||
#include <qlist.h>
|
||||
#include <qvector.h>
|
||||
#include <qpoint.h>
|
||||
#include <qsize.h>
|
||||
#include <qrect.h>
|
||||
#include <qpolygon.h>
|
||||
|
||||
// A couple of definition for Qwt5 compatibility
|
||||
|
||||
#define qwtMax qMax
|
||||
#define qwtMin qMin
|
||||
#define qwtAbs qAbs
|
||||
#define qwtRound qRound
|
||||
|
||||
#define QwtArray QVector
|
||||
|
||||
typedef QList<double> QwtValueList;
|
||||
typedef QPointF QwtDoublePoint;
|
||||
typedef QSizeF QwtDoubleSize;
|
||||
typedef QRectF QwtDoubleRect;
|
||||
|
||||
typedef QPolygon QwtPolygon;
|
||||
typedef QPolygonF QwtPolygonF;
|
||||
typedef QwtInterval QwtDoubleInterval;
|
||||
typedef QwtPoint3D QwtDoublePoint3D;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,785 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_arrow_button.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_counter.h"
|
||||
#include <qlayout.h>
|
||||
#include <qlineedit.h>
|
||||
#include <qvalidator.h>
|
||||
#include <qevent.h>
|
||||
#include <qstyle.h>
|
||||
|
||||
class QwtCounter::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
minimum( 0.0 ),
|
||||
maximum( 0.0 ),
|
||||
singleStep( 1.0 ),
|
||||
isValid( false ),
|
||||
value( 0.0 ),
|
||||
wrapping( false )
|
||||
{
|
||||
increment[Button1] = 1;
|
||||
increment[Button2] = 10;
|
||||
increment[Button3] = 100;
|
||||
}
|
||||
|
||||
QwtArrowButton *buttonDown[ButtonCnt];
|
||||
QwtArrowButton *buttonUp[ButtonCnt];
|
||||
QLineEdit *valueEdit;
|
||||
|
||||
int increment[ButtonCnt];
|
||||
int numButtons;
|
||||
|
||||
double minimum;
|
||||
double maximum;
|
||||
double singleStep;
|
||||
|
||||
bool isValid;
|
||||
double value;
|
||||
|
||||
bool wrapping;
|
||||
};
|
||||
|
||||
/*!
|
||||
The counter is initialized with a range is set to [0.0, 1.0] with
|
||||
0.01 as single step size. The value is invalid.
|
||||
|
||||
The default number of buttons is set to 2. The default increments are:
|
||||
\li Button 1: 1 step
|
||||
\li Button 2: 10 steps
|
||||
\li Button 3: 100 steps
|
||||
|
||||
\param parent
|
||||
*/
|
||||
QwtCounter::QwtCounter( QWidget *parent ):
|
||||
QWidget( parent )
|
||||
{
|
||||
initCounter();
|
||||
}
|
||||
|
||||
void QwtCounter::initCounter()
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout( this );
|
||||
layout->setSpacing( 0 );
|
||||
layout->setMargin( 0 );
|
||||
|
||||
for ( int i = ButtonCnt - 1; i >= 0; i-- )
|
||||
{
|
||||
QwtArrowButton *btn =
|
||||
new QwtArrowButton( i + 1, Qt::DownArrow, this );
|
||||
btn->setFocusPolicy( Qt::NoFocus );
|
||||
btn->installEventFilter( this );
|
||||
layout->addWidget( btn );
|
||||
|
||||
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
|
||||
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
|
||||
|
||||
d_data->buttonDown[i] = btn;
|
||||
}
|
||||
|
||||
d_data->valueEdit = new QLineEdit( this );
|
||||
d_data->valueEdit->setReadOnly( false );
|
||||
d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
|
||||
layout->addWidget( d_data->valueEdit );
|
||||
|
||||
connect( d_data->valueEdit, SIGNAL( editingFinished() ),
|
||||
SLOT( textChanged() ) );
|
||||
|
||||
layout->setStretchFactor( d_data->valueEdit, 10 );
|
||||
|
||||
for ( int i = 0; i < ButtonCnt; i++ )
|
||||
{
|
||||
QwtArrowButton *btn =
|
||||
new QwtArrowButton( i + 1, Qt::UpArrow, this );
|
||||
btn->setFocusPolicy( Qt::NoFocus );
|
||||
btn->installEventFilter( this );
|
||||
layout->addWidget( btn );
|
||||
|
||||
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
|
||||
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
|
||||
|
||||
d_data->buttonUp[i] = btn;
|
||||
}
|
||||
|
||||
setNumButtons( 2 );
|
||||
setRange( 0.0, 1.0 );
|
||||
setSingleStep( 0.001 );
|
||||
setValue( 0.0 );
|
||||
|
||||
setSizePolicy(
|
||||
QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
|
||||
|
||||
setFocusProxy( d_data->valueEdit );
|
||||
setFocusPolicy( Qt::StrongFocus );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtCounter::~QwtCounter()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the counter to be in valid/invalid state
|
||||
|
||||
When the counter is set to invalid, no numbers are displayed and
|
||||
the buttons are disabled.
|
||||
|
||||
\param on If true the counter will be set as valid
|
||||
|
||||
\sa setValue(), isValid()
|
||||
*/
|
||||
void QwtCounter::setValid( bool on )
|
||||
{
|
||||
if ( on != d_data->isValid )
|
||||
{
|
||||
d_data->isValid = on;
|
||||
|
||||
updateButtons();
|
||||
|
||||
if ( d_data->isValid )
|
||||
{
|
||||
showNumber( value() );
|
||||
Q_EMIT valueChanged( value() );
|
||||
}
|
||||
else
|
||||
{
|
||||
d_data->valueEdit->setText( QString::null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, if the value is valid
|
||||
\sa setValid(), setValue()
|
||||
*/
|
||||
bool QwtCounter::isValid() const
|
||||
{
|
||||
return d_data->isValid;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Allow/disallow the user to manually edit the value
|
||||
|
||||
\param on True disable editing
|
||||
\sa isReadOnly()
|
||||
*/
|
||||
void QwtCounter::setReadOnly( bool on )
|
||||
{
|
||||
d_data->valueEdit->setReadOnly( on );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, when the line line edit is read only. (default is no)
|
||||
\sa setReadOnly()
|
||||
*/
|
||||
bool QwtCounter::isReadOnly() const
|
||||
{
|
||||
return d_data->valueEdit->isReadOnly();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set a new value without adjusting to the step raster
|
||||
|
||||
The state of the counter is set to be valid.
|
||||
|
||||
\param value New value
|
||||
|
||||
\sa isValid(), value(), valueChanged()
|
||||
\warning The value is clipped when it lies outside the range.
|
||||
*/
|
||||
|
||||
void QwtCounter::setValue( double value )
|
||||
{
|
||||
const double vmin = qMin( d_data->minimum, d_data->maximum );
|
||||
const double vmax = qMax( d_data->minimum, d_data->maximum );
|
||||
|
||||
value = qBound( vmin, value, vmax );
|
||||
|
||||
if ( !d_data->isValid || value != d_data->value )
|
||||
{
|
||||
d_data->isValid = true;
|
||||
d_data->value = value;
|
||||
|
||||
showNumber( value );
|
||||
updateButtons();
|
||||
|
||||
Q_EMIT valueChanged( value );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Current value of the counter
|
||||
\sa setValue(), valueChanged()
|
||||
*/
|
||||
double QwtCounter::value() const
|
||||
{
|
||||
return d_data->value;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the minimum and maximum values
|
||||
|
||||
The maximum is adjusted if necessary to ensure that the range remains valid.
|
||||
The value might be modified to be inside of the range.
|
||||
|
||||
\param min Minimum value
|
||||
\param max Maximum value
|
||||
|
||||
\sa minimum(), maximum()
|
||||
*/
|
||||
void QwtCounter::setRange( double min, double max )
|
||||
{
|
||||
max = qMax( min, max );
|
||||
|
||||
if ( d_data->maximum == max && d_data->minimum == min )
|
||||
return;
|
||||
|
||||
d_data->minimum = min;
|
||||
d_data->maximum = max;
|
||||
|
||||
setSingleStep( singleStep() );
|
||||
|
||||
const double value = qBound( min, d_data->value, max );
|
||||
|
||||
if ( value != d_data->value )
|
||||
{
|
||||
d_data->value = value;
|
||||
|
||||
if ( d_data->isValid )
|
||||
{
|
||||
showNumber( value );
|
||||
Q_EMIT valueChanged( value );
|
||||
}
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the minimum value of the range
|
||||
|
||||
\param value Minimum value
|
||||
\sa setRange(), setMaximum(), minimum()
|
||||
|
||||
\note The maximum is adjusted if necessary to ensure that the range remains valid.
|
||||
*/
|
||||
void QwtCounter::setMinimum( double value )
|
||||
{
|
||||
setRange( value, maximum() );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The minimum of the range
|
||||
\sa setRange(), setMinimum(), maximum()
|
||||
*/
|
||||
double QwtCounter::minimum() const
|
||||
{
|
||||
return d_data->minimum;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the maximum value of the range
|
||||
|
||||
\param value Maximum value
|
||||
\sa setRange(), setMinimum(), maximum()
|
||||
*/
|
||||
void QwtCounter::setMaximum( double value )
|
||||
{
|
||||
setRange( minimum(), value );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The maximum of the range
|
||||
\sa setRange(), setMaximum(), minimum()
|
||||
*/
|
||||
double QwtCounter::maximum() const
|
||||
{
|
||||
return d_data->maximum;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the step size of the counter
|
||||
|
||||
A value <= 0.0 disables stepping
|
||||
|
||||
\param stepSize Single step size
|
||||
\sa singleStep()
|
||||
*/
|
||||
void QwtCounter::setSingleStep( double stepSize )
|
||||
{
|
||||
d_data->singleStep = qMax( stepSize, 0.0 );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Single step size
|
||||
\sa setSingleStep()
|
||||
*/
|
||||
double QwtCounter::singleStep() const
|
||||
{
|
||||
return d_data->singleStep;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief En/Disable wrapping
|
||||
|
||||
If wrapping is true stepping up from maximum() value will take
|
||||
you to the minimum() value and vice versa.
|
||||
|
||||
\param on En/Disable wrapping
|
||||
\sa wrapping()
|
||||
*/
|
||||
void QwtCounter::setWrapping( bool on )
|
||||
{
|
||||
d_data->wrapping = on;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, when wrapping is set
|
||||
\sa setWrapping()
|
||||
*/
|
||||
bool QwtCounter::wrapping() const
|
||||
{
|
||||
return d_data->wrapping;
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify the number of buttons on each side of the label
|
||||
|
||||
\param numButtons Number of buttons
|
||||
\sa numButtons()
|
||||
*/
|
||||
void QwtCounter::setNumButtons( int numButtons )
|
||||
{
|
||||
if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
|
||||
return;
|
||||
|
||||
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||
{
|
||||
if ( i < numButtons )
|
||||
{
|
||||
d_data->buttonDown[i]->show();
|
||||
d_data->buttonUp[i]->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
d_data->buttonDown[i]->hide();
|
||||
d_data->buttonUp[i]->hide();
|
||||
}
|
||||
}
|
||||
|
||||
d_data->numButtons = numButtons;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The number of buttons on each side of the widget.
|
||||
\sa setNumButtons()
|
||||
*/
|
||||
int QwtCounter::numButtons() const
|
||||
{
|
||||
return d_data->numButtons;
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify the number of steps by which the value
|
||||
is incremented or decremented when a specified button
|
||||
is pushed.
|
||||
|
||||
\param button Button index
|
||||
\param numSteps Number of steps
|
||||
|
||||
\sa incSteps()
|
||||
*/
|
||||
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
|
||||
{
|
||||
if ( button >= 0 && button < QwtCounter::ButtonCnt )
|
||||
d_data->increment[ button ] = numSteps;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The number of steps by which a specified button increments the value
|
||||
or 0 if the button is invalid.
|
||||
\param button Button index
|
||||
|
||||
\sa setIncSteps()
|
||||
*/
|
||||
int QwtCounter::incSteps( QwtCounter::Button button ) const
|
||||
{
|
||||
if ( button >= 0 && button < QwtCounter::ButtonCnt )
|
||||
return d_data->increment[ button ];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Set the number of increment steps for button 1
|
||||
\param nSteps Number of steps
|
||||
*/
|
||||
void QwtCounter::setStepButton1( int nSteps )
|
||||
{
|
||||
setIncSteps( QwtCounter::Button1, nSteps );
|
||||
}
|
||||
|
||||
//! returns the number of increment steps for button 1
|
||||
int QwtCounter::stepButton1() const
|
||||
{
|
||||
return incSteps( QwtCounter::Button1 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the number of increment steps for button 2
|
||||
\param nSteps Number of steps
|
||||
*/
|
||||
void QwtCounter::setStepButton2( int nSteps )
|
||||
{
|
||||
setIncSteps( QwtCounter::Button2, nSteps );
|
||||
}
|
||||
|
||||
//! returns the number of increment steps for button 2
|
||||
int QwtCounter::stepButton2() const
|
||||
{
|
||||
return incSteps( QwtCounter::Button2 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the number of increment steps for button 3
|
||||
\param nSteps Number of steps
|
||||
*/
|
||||
void QwtCounter::setStepButton3( int nSteps )
|
||||
{
|
||||
setIncSteps( QwtCounter::Button3, nSteps );
|
||||
}
|
||||
|
||||
//! returns the number of increment steps for button 3
|
||||
int QwtCounter::stepButton3() const
|
||||
{
|
||||
return incSteps( QwtCounter::Button3 );
|
||||
}
|
||||
|
||||
//! Set from lineedit
|
||||
void QwtCounter::textChanged()
|
||||
{
|
||||
bool converted = false;
|
||||
|
||||
const double value = d_data->valueEdit->text().toDouble( &converted );
|
||||
if ( converted )
|
||||
setValue( value );
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle QEvent::PolishRequest events
|
||||
\param event Event
|
||||
\return see QWidget::event()
|
||||
*/
|
||||
bool QwtCounter::event( QEvent *event )
|
||||
{
|
||||
if ( event->type() == QEvent::PolishRequest )
|
||||
{
|
||||
const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
|
||||
for ( int i = 0; i < ButtonCnt; i++ )
|
||||
{
|
||||
d_data->buttonDown[i]->setMinimumWidth( w );
|
||||
d_data->buttonUp[i]->setMinimumWidth( w );
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::event( event );
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle key events
|
||||
|
||||
- Ctrl + Qt::Key_Home\n
|
||||
Step to minimum()
|
||||
- Ctrl + Qt::Key_End\n
|
||||
Step to maximum()
|
||||
- Qt::Key_Up\n
|
||||
Increment by incSteps(QwtCounter::Button1)
|
||||
- Qt::Key_Down\n
|
||||
Decrement by incSteps(QwtCounter::Button1)
|
||||
- Qt::Key_PageUp\n
|
||||
Increment by incSteps(QwtCounter::Button2)
|
||||
- Qt::Key_PageDown\n
|
||||
Decrement by incSteps(QwtCounter::Button2)
|
||||
- Shift + Qt::Key_PageUp\n
|
||||
Increment by incSteps(QwtCounter::Button3)
|
||||
- Shift + Qt::Key_PageDown\n
|
||||
Decrement by incSteps(QwtCounter::Button3)
|
||||
|
||||
\param event Key event
|
||||
*/
|
||||
void QwtCounter::keyPressEvent ( QKeyEvent *event )
|
||||
{
|
||||
bool accepted = true;
|
||||
|
||||
switch ( event->key() )
|
||||
{
|
||||
case Qt::Key_Home:
|
||||
{
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
setValue( minimum() );
|
||||
else
|
||||
accepted = false;
|
||||
break;
|
||||
}
|
||||
case Qt::Key_End:
|
||||
{
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
setValue( maximum() );
|
||||
else
|
||||
accepted = false;
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Up:
|
||||
{
|
||||
incrementValue( d_data->increment[0] );
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
incrementValue( -d_data->increment[0] );
|
||||
break;
|
||||
}
|
||||
case Qt::Key_PageUp:
|
||||
case Qt::Key_PageDown:
|
||||
{
|
||||
int increment = d_data->increment[0];
|
||||
if ( d_data->numButtons >= 2 )
|
||||
increment = d_data->increment[1];
|
||||
if ( d_data->numButtons >= 3 )
|
||||
{
|
||||
if ( event->modifiers() & Qt::ShiftModifier )
|
||||
increment = d_data->increment[2];
|
||||
}
|
||||
if ( event->key() == Qt::Key_PageDown )
|
||||
increment = -increment;
|
||||
incrementValue( increment );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( accepted )
|
||||
{
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::keyPressEvent ( event );
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle wheel events
|
||||
\param event Wheel event
|
||||
*/
|
||||
void QwtCounter::wheelEvent( QWheelEvent *event )
|
||||
{
|
||||
event->accept();
|
||||
|
||||
if ( d_data->numButtons <= 0 )
|
||||
return;
|
||||
|
||||
int increment = d_data->increment[0];
|
||||
if ( d_data->numButtons >= 2 )
|
||||
{
|
||||
if ( event->modifiers() & Qt::ControlModifier )
|
||||
increment = d_data->increment[1];
|
||||
}
|
||||
if ( d_data->numButtons >= 3 )
|
||||
{
|
||||
if ( event->modifiers() & Qt::ShiftModifier )
|
||||
increment = d_data->increment[2];
|
||||
}
|
||||
|
||||
for ( int i = 0; i < d_data->numButtons; i++ )
|
||||
{
|
||||
if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
|
||||
d_data->buttonUp[i]->geometry().contains( event->pos() ) )
|
||||
{
|
||||
increment = d_data->increment[i];
|
||||
}
|
||||
}
|
||||
|
||||
const int wheel_delta = 120;
|
||||
|
||||
#if 1
|
||||
int delta = event->delta();
|
||||
if ( delta >= 2 * wheel_delta )
|
||||
delta /= 2; // Never saw an abs(delta) < 240
|
||||
#endif
|
||||
|
||||
incrementValue( delta / wheel_delta * increment );
|
||||
}
|
||||
|
||||
void QwtCounter::incrementValue( int numSteps )
|
||||
{
|
||||
const double min = d_data->minimum;
|
||||
const double max = d_data->maximum;
|
||||
double stepSize = d_data->singleStep;
|
||||
|
||||
if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
|
||||
return;
|
||||
|
||||
|
||||
#if 1
|
||||
stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
|
||||
#endif
|
||||
|
||||
double value = d_data->value + numSteps * stepSize;
|
||||
|
||||
if ( d_data->wrapping )
|
||||
{
|
||||
const double range = max - min;
|
||||
|
||||
if ( value < min )
|
||||
{
|
||||
value += ::ceil( ( min - value ) / range ) * range;
|
||||
}
|
||||
else if ( value > max )
|
||||
{
|
||||
value -= ::ceil( ( value - max ) / range ) * range;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
value = qBound( min, value, max );
|
||||
}
|
||||
|
||||
value = min + qRound( ( value - min ) / stepSize ) * stepSize;
|
||||
|
||||
if ( stepSize > 1e-12 )
|
||||
{
|
||||
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
|
||||
{
|
||||
// correct rounding error if value = 0
|
||||
value = 0.0;
|
||||
}
|
||||
else if ( qFuzzyCompare( value, max ) )
|
||||
{
|
||||
// correct rounding error at the border
|
||||
value = max;
|
||||
}
|
||||
}
|
||||
|
||||
if ( value != d_data->value )
|
||||
{
|
||||
d_data->value = value;
|
||||
showNumber( d_data->value );
|
||||
updateButtons();
|
||||
|
||||
Q_EMIT valueChanged( d_data->value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Update buttons according to the current value
|
||||
|
||||
When the QwtCounter under- or over-flows, the focus is set to the smallest
|
||||
up- or down-button and counting is disabled.
|
||||
|
||||
Counting is re-enabled on a button release event (mouse or space bar).
|
||||
*/
|
||||
void QwtCounter::updateButtons()
|
||||
{
|
||||
if ( d_data->isValid )
|
||||
{
|
||||
// 1. save enabled state of the smallest down- and up-button
|
||||
// 2. change enabled state on under- or over-flow
|
||||
|
||||
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||
{
|
||||
d_data->buttonDown[i]->setEnabled( value() > minimum() );
|
||||
d_data->buttonUp[i]->setEnabled( value() < maximum() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
|
||||
{
|
||||
d_data->buttonDown[i]->setEnabled( false );
|
||||
d_data->buttonUp[i]->setEnabled( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*!
|
||||
Display number string
|
||||
|
||||
\param number Number
|
||||
*/
|
||||
void QwtCounter::showNumber( double number )
|
||||
{
|
||||
QString text;
|
||||
text.setNum( number );
|
||||
|
||||
const int cursorPos = d_data->valueEdit->cursorPosition();
|
||||
d_data->valueEdit->setText( text );
|
||||
d_data->valueEdit->setCursorPosition( cursorPos );
|
||||
}
|
||||
|
||||
//! Button clicked
|
||||
void QwtCounter::btnClicked()
|
||||
{
|
||||
for ( int i = 0; i < ButtonCnt; i++ )
|
||||
{
|
||||
if ( d_data->buttonUp[i] == sender() )
|
||||
incrementValue( d_data->increment[i] );
|
||||
|
||||
if ( d_data->buttonDown[i] == sender() )
|
||||
incrementValue( -d_data->increment[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//! Button released
|
||||
void QwtCounter::btnReleased()
|
||||
{
|
||||
Q_EMIT buttonReleased( value() );
|
||||
}
|
||||
|
||||
//! A size hint
|
||||
QSize QwtCounter::sizeHint() const
|
||||
{
|
||||
QString tmp;
|
||||
|
||||
int w = tmp.setNum( minimum() ).length();
|
||||
int w1 = tmp.setNum( maximum() ).length();
|
||||
if ( w1 > w )
|
||||
w = w1;
|
||||
w1 = tmp.setNum( minimum() + singleStep() ).length();
|
||||
if ( w1 > w )
|
||||
w = w1;
|
||||
w1 = tmp.setNum( maximum() - singleStep() ).length();
|
||||
if ( w1 > w )
|
||||
w = w1;
|
||||
|
||||
tmp.fill( '9', w );
|
||||
|
||||
QFontMetrics fm( d_data->valueEdit->font() );
|
||||
w = fm.width( tmp ) + 2;
|
||||
if ( d_data->valueEdit->hasFrame() )
|
||||
w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
|
||||
|
||||
// Now we replace default sizeHint contribution of d_data->valueEdit by
|
||||
// what we really need.
|
||||
|
||||
w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
|
||||
|
||||
const int h = qMin( QWidget::sizeHint().height(),
|
||||
d_data->valueEdit->minimumSizeHint().height() );
|
||||
return QSize( w, h );
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_COUNTER_H
|
||||
#define QWT_COUNTER_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qwidget.h>
|
||||
|
||||
/*!
|
||||
\brief The Counter Widget
|
||||
|
||||
A Counter consists of a label displaying a number and
|
||||
one ore more (up to three) push buttons on each side
|
||||
of the label which can be used to increment or decrement
|
||||
the counter's value.
|
||||
|
||||
A counter has a range from a minimum value to a maximum value
|
||||
and a step size. When the wrapping property is set
|
||||
the counter is circular.
|
||||
|
||||
The number of steps by which a button increments or decrements the value
|
||||
can be specified using setIncSteps(). The number of buttons can be
|
||||
changed with setNumButtons().
|
||||
|
||||
Example:
|
||||
\code
|
||||
#include <qwt_counter.h>
|
||||
|
||||
QwtCounter *counter = new QwtCounter(parent);
|
||||
|
||||
counter->setRange(0.0, 100.0); // From 0.0 to 100
|
||||
counter->setSingleStep( 1.0 ); // Step size 1.0
|
||||
counter->setNumButtons(2); // Two buttons each side
|
||||
counter->setIncSteps(QwtCounter::Button1, 1); // Button 1 increments 1 step
|
||||
counter->setIncSteps(QwtCounter::Button2, 20); // Button 2 increments 20 steps
|
||||
|
||||
connect(counter, SIGNAL(valueChanged(double)), myClass, SLOT(newValue(double)));
|
||||
\endcode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtCounter : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( double value READ value WRITE setValue )
|
||||
Q_PROPERTY( double minimum READ minimum WRITE setMinimum )
|
||||
Q_PROPERTY( double maximum READ maximum WRITE setMaximum )
|
||||
Q_PROPERTY( double singleStep READ singleStep WRITE setSingleStep )
|
||||
|
||||
Q_PROPERTY( int numButtons READ numButtons WRITE setNumButtons )
|
||||
Q_PROPERTY( int stepButton1 READ stepButton1 WRITE setStepButton1 )
|
||||
Q_PROPERTY( int stepButton2 READ stepButton2 WRITE setStepButton2 )
|
||||
Q_PROPERTY( int stepButton3 READ stepButton3 WRITE setStepButton3 )
|
||||
|
||||
Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly )
|
||||
Q_PROPERTY( bool wrapping READ wrapping WRITE setWrapping )
|
||||
|
||||
public:
|
||||
//! Button index
|
||||
enum Button
|
||||
{
|
||||
//! Button intended for minor steps
|
||||
Button1,
|
||||
|
||||
//! Button intended for medium steps
|
||||
Button2,
|
||||
|
||||
//! Button intended for large steps
|
||||
Button3,
|
||||
|
||||
//! Number of buttons
|
||||
ButtonCnt
|
||||
};
|
||||
|
||||
explicit QwtCounter( QWidget *parent = NULL );
|
||||
virtual ~QwtCounter();
|
||||
|
||||
void setValid( bool );
|
||||
bool isValid() const;
|
||||
|
||||
void setWrapping( bool );
|
||||
bool wrapping() const;
|
||||
|
||||
bool isReadOnly() const;
|
||||
void setReadOnly( bool );
|
||||
|
||||
void setNumButtons( int n );
|
||||
int numButtons() const;
|
||||
|
||||
void setIncSteps( QwtCounter::Button btn, int nSteps );
|
||||
int incSteps( QwtCounter::Button btn ) const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
double singleStep() const;
|
||||
void setSingleStep( double s );
|
||||
|
||||
void setRange( double min, double max );
|
||||
|
||||
double minimum() const;
|
||||
void setMinimum( double min );
|
||||
|
||||
double maximum() const;
|
||||
void setMaximum( double max );
|
||||
|
||||
void setStepButton1( int nSteps );
|
||||
int stepButton1() const;
|
||||
|
||||
void setStepButton2( int nSteps );
|
||||
int stepButton2() const;
|
||||
|
||||
void setStepButton3( int nSteps );
|
||||
int stepButton3() const;
|
||||
|
||||
double value() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setValue( double );
|
||||
|
||||
|
||||
Q_SIGNALS:
|
||||
/*!
|
||||
This signal is emitted when a button has been released
|
||||
\param value The new value
|
||||
*/
|
||||
void buttonReleased ( double value );
|
||||
|
||||
/*!
|
||||
This signal is emitted when the counter's value has changed
|
||||
\param value The new value
|
||||
*/
|
||||
void valueChanged ( double value );
|
||||
|
||||
protected:
|
||||
virtual bool event( QEvent * );
|
||||
virtual void wheelEvent( QWheelEvent * );
|
||||
virtual void keyPressEvent( QKeyEvent * );
|
||||
|
||||
private Q_SLOTS:
|
||||
void btnReleased();
|
||||
void btnClicked();
|
||||
void textChanged();
|
||||
|
||||
private:
|
||||
void incrementValue( int numSteps );
|
||||
void initCounter();
|
||||
void updateButtons();
|
||||
void showNumber( double );
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,453 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_curve_fitter.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_spline.h"
|
||||
#include <qstack.h>
|
||||
#include <qvector.h>
|
||||
|
||||
#if QT_VERSION < 0x040601
|
||||
#define qFabs(x) ::fabs(x)
|
||||
#endif
|
||||
|
||||
//! Constructor
|
||||
QwtCurveFitter::QwtCurveFitter()
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtCurveFitter::~QwtCurveFitter()
|
||||
{
|
||||
}
|
||||
|
||||
class QwtSplineCurveFitter::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
fitMode( QwtSplineCurveFitter::Auto ),
|
||||
splineSize( 250 )
|
||||
{
|
||||
}
|
||||
|
||||
QwtSpline spline;
|
||||
QwtSplineCurveFitter::FitMode fitMode;
|
||||
int splineSize;
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
QwtSplineCurveFitter::QwtSplineCurveFitter()
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtSplineCurveFitter::~QwtSplineCurveFitter()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Select the algorithm used for building the spline
|
||||
|
||||
\param mode Mode representing a spline algorithm
|
||||
\sa fitMode()
|
||||
*/
|
||||
void QwtSplineCurveFitter::setFitMode( FitMode mode )
|
||||
{
|
||||
d_data->fitMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Mode representing a spline algorithm
|
||||
\sa setFitMode()
|
||||
*/
|
||||
QwtSplineCurveFitter::FitMode QwtSplineCurveFitter::fitMode() const
|
||||
{
|
||||
return d_data->fitMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a spline
|
||||
|
||||
\param spline Spline
|
||||
\sa spline()
|
||||
*/
|
||||
void QwtSplineCurveFitter::setSpline( const QwtSpline &spline )
|
||||
{
|
||||
d_data->spline = spline;
|
||||
d_data->spline.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Spline
|
||||
\sa setSpline()
|
||||
*/
|
||||
const QwtSpline &QwtSplineCurveFitter::spline() const
|
||||
{
|
||||
return d_data->spline;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Spline
|
||||
\sa setSpline()
|
||||
*/
|
||||
QwtSpline &QwtSplineCurveFitter::spline()
|
||||
{
|
||||
return d_data->spline;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a spline size ( has to be at least 10 points )
|
||||
|
||||
\param splineSize Spline size
|
||||
\sa splineSize()
|
||||
*/
|
||||
void QwtSplineCurveFitter::setSplineSize( int splineSize )
|
||||
{
|
||||
d_data->splineSize = qMax( splineSize, 10 );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Spline size
|
||||
\sa setSplineSize()
|
||||
*/
|
||||
int QwtSplineCurveFitter::splineSize() const
|
||||
{
|
||||
return d_data->splineSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find a curve which has the best fit to a series of data points
|
||||
|
||||
\param points Series of data points
|
||||
\return Curve points
|
||||
*/
|
||||
QPolygonF QwtSplineCurveFitter::fitCurve( const QPolygonF &points ) const
|
||||
{
|
||||
const int size = points.size();
|
||||
if ( size <= 2 )
|
||||
return points;
|
||||
|
||||
FitMode fitMode = d_data->fitMode;
|
||||
if ( fitMode == Auto )
|
||||
{
|
||||
fitMode = Spline;
|
||||
|
||||
const QPointF *p = points.data();
|
||||
for ( int i = 1; i < size; i++ )
|
||||
{
|
||||
if ( p[i].x() <= p[i-1].x() )
|
||||
{
|
||||
fitMode = ParametricSpline;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if ( fitMode == ParametricSpline )
|
||||
return fitParametric( points );
|
||||
else
|
||||
return fitSpline( points );
|
||||
}
|
||||
|
||||
QPolygonF QwtSplineCurveFitter::fitSpline( const QPolygonF &points ) const
|
||||
{
|
||||
d_data->spline.setPoints( points );
|
||||
if ( !d_data->spline.isValid() )
|
||||
return points;
|
||||
|
||||
QPolygonF fittedPoints( d_data->splineSize );
|
||||
|
||||
const double x1 = points[0].x();
|
||||
const double x2 = points[int( points.size() - 1 )].x();
|
||||
const double dx = x2 - x1;
|
||||
const double delta = dx / ( d_data->splineSize - 1 );
|
||||
|
||||
for ( int i = 0; i < d_data->splineSize; i++ )
|
||||
{
|
||||
QPointF &p = fittedPoints[i];
|
||||
|
||||
const double v = x1 + i * delta;
|
||||
const double sv = d_data->spline.value( v );
|
||||
|
||||
p.setX( v );
|
||||
p.setY( sv );
|
||||
}
|
||||
d_data->spline.reset();
|
||||
|
||||
return fittedPoints;
|
||||
}
|
||||
|
||||
QPolygonF QwtSplineCurveFitter::fitParametric( const QPolygonF &points ) const
|
||||
{
|
||||
int i;
|
||||
const int size = points.size();
|
||||
|
||||
QPolygonF fittedPoints( d_data->splineSize );
|
||||
QPolygonF splinePointsX( size );
|
||||
QPolygonF splinePointsY( size );
|
||||
|
||||
const QPointF *p = points.data();
|
||||
QPointF *spX = splinePointsX.data();
|
||||
QPointF *spY = splinePointsY.data();
|
||||
|
||||
double param = 0.0;
|
||||
for ( i = 0; i < size; i++ )
|
||||
{
|
||||
const double x = p[i].x();
|
||||
const double y = p[i].y();
|
||||
if ( i > 0 )
|
||||
{
|
||||
const double delta = qSqrt( qwtSqr( x - spX[i-1].y() )
|
||||
+ qwtSqr( y - spY[i-1].y() ) );
|
||||
param += qMax( delta, 1.0 );
|
||||
}
|
||||
spX[i].setX( param );
|
||||
spX[i].setY( x );
|
||||
spY[i].setX( param );
|
||||
spY[i].setY( y );
|
||||
}
|
||||
|
||||
d_data->spline.setPoints( splinePointsX );
|
||||
if ( !d_data->spline.isValid() )
|
||||
return points;
|
||||
|
||||
const double deltaX =
|
||||
splinePointsX[size - 1].x() / ( d_data->splineSize - 1 );
|
||||
for ( i = 0; i < d_data->splineSize; i++ )
|
||||
{
|
||||
const double dtmp = i * deltaX;
|
||||
fittedPoints[i].setX( d_data->spline.value( dtmp ) );
|
||||
}
|
||||
|
||||
d_data->spline.setPoints( splinePointsY );
|
||||
if ( !d_data->spline.isValid() )
|
||||
return points;
|
||||
|
||||
const double deltaY =
|
||||
splinePointsY[size - 1].x() / ( d_data->splineSize - 1 );
|
||||
for ( i = 0; i < d_data->splineSize; i++ )
|
||||
{
|
||||
const double dtmp = i * deltaY;
|
||||
fittedPoints[i].setY( d_data->spline.value( dtmp ) );
|
||||
}
|
||||
|
||||
return fittedPoints;
|
||||
}
|
||||
|
||||
class QwtWeedingCurveFitter::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
tolerance( 1.0 ),
|
||||
chunkSize( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
double tolerance;
|
||||
uint chunkSize;
|
||||
};
|
||||
|
||||
class QwtWeedingCurveFitter::Line
|
||||
{
|
||||
public:
|
||||
Line( int i1 = 0, int i2 = 0 ):
|
||||
from( i1 ),
|
||||
to( i2 )
|
||||
{
|
||||
}
|
||||
|
||||
int from;
|
||||
int to;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\param tolerance Tolerance
|
||||
\sa setTolerance(), tolerance()
|
||||
*/
|
||||
QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
setTolerance( tolerance );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtWeedingCurveFitter::~QwtWeedingCurveFitter()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the tolerance
|
||||
|
||||
The tolerance is the maximum distance, that is acceptable
|
||||
between the original curve and the smoothed curve.
|
||||
|
||||
Increasing the tolerance will reduce the number of the
|
||||
resulting points.
|
||||
|
||||
\param tolerance Tolerance
|
||||
|
||||
\sa tolerance()
|
||||
*/
|
||||
void QwtWeedingCurveFitter::setTolerance( double tolerance )
|
||||
{
|
||||
d_data->tolerance = qMax( tolerance, 0.0 );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Tolerance
|
||||
\sa setTolerance()
|
||||
*/
|
||||
double QwtWeedingCurveFitter::tolerance() const
|
||||
{
|
||||
return d_data->tolerance;
|
||||
}
|
||||
|
||||
/*!
|
||||
Limit the number of points passed to a run of the algorithm
|
||||
|
||||
The runtime of the Douglas Peucker algorithm increases non linear
|
||||
with the number of points. For a chunk size > 0 the polygon
|
||||
is split into pieces passed to the algorithm one by one.
|
||||
|
||||
\param numPoints Maximum for the number of points passed to the algorithm
|
||||
|
||||
\sa chunkSize()
|
||||
*/
|
||||
void QwtWeedingCurveFitter::setChunkSize( uint numPoints )
|
||||
{
|
||||
if ( numPoints > 0 )
|
||||
numPoints = qMax( numPoints, 3U );
|
||||
|
||||
d_data->chunkSize = numPoints;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
\return Maximum for the number of points passed to a run
|
||||
of the algorithm - or 0, when unlimited
|
||||
\sa setChunkSize()
|
||||
*/
|
||||
uint QwtWeedingCurveFitter::chunkSize() const
|
||||
{
|
||||
return d_data->chunkSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param points Series of data points
|
||||
\return Curve points
|
||||
*/
|
||||
QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const
|
||||
{
|
||||
QPolygonF fittedPoints;
|
||||
|
||||
if ( d_data->chunkSize == 0 )
|
||||
{
|
||||
fittedPoints = simplify( points );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < points.size(); i += d_data->chunkSize )
|
||||
{
|
||||
const QPolygonF p = points.mid( i, d_data->chunkSize );
|
||||
fittedPoints += simplify( p );
|
||||
}
|
||||
}
|
||||
|
||||
return fittedPoints;
|
||||
}
|
||||
|
||||
QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF &points ) const
|
||||
{
|
||||
const double toleranceSqr = d_data->tolerance * d_data->tolerance;
|
||||
|
||||
QStack<Line> stack;
|
||||
stack.reserve( 500 );
|
||||
|
||||
const QPointF *p = points.data();
|
||||
const int nPoints = points.size();
|
||||
|
||||
QVector<bool> usePoint( nPoints, false );
|
||||
|
||||
stack.push( Line( 0, nPoints - 1 ) );
|
||||
|
||||
while ( !stack.isEmpty() )
|
||||
{
|
||||
const Line r = stack.pop();
|
||||
|
||||
// initialize line segment
|
||||
const double vecX = p[r.to].x() - p[r.from].x();
|
||||
const double vecY = p[r.to].y() - p[r.from].y();
|
||||
|
||||
const double vecLength = qSqrt( vecX * vecX + vecY * vecY );
|
||||
|
||||
const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0;
|
||||
const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0;
|
||||
|
||||
double maxDistSqr = 0.0;
|
||||
int nVertexIndexMaxDistance = r.from + 1;
|
||||
for ( int i = r.from + 1; i < r.to; i++ )
|
||||
{
|
||||
//compare to anchor
|
||||
const double fromVecX = p[i].x() - p[r.from].x();
|
||||
const double fromVecY = p[i].y() - p[r.from].y();
|
||||
|
||||
double distToSegmentSqr;
|
||||
if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
|
||||
{
|
||||
distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double toVecX = p[i].x() - p[r.to].x();
|
||||
const double toVecY = p[i].y() - p[r.to].y();
|
||||
const double toVecLength = toVecX * toVecX + toVecY * toVecY;
|
||||
|
||||
const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
|
||||
if ( s < 0.0 )
|
||||
{
|
||||
distToSegmentSqr = toVecLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
distToSegmentSqr = qFabs( toVecLength - s * s );
|
||||
}
|
||||
}
|
||||
|
||||
if ( maxDistSqr < distToSegmentSqr )
|
||||
{
|
||||
maxDistSqr = distToSegmentSqr;
|
||||
nVertexIndexMaxDistance = i;
|
||||
}
|
||||
}
|
||||
if ( maxDistSqr <= toleranceSqr )
|
||||
{
|
||||
usePoint[r.from] = true;
|
||||
usePoint[r.to] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.push( Line( r.from, nVertexIndexMaxDistance ) );
|
||||
stack.push( Line( nVertexIndexMaxDistance, r.to ) );
|
||||
}
|
||||
}
|
||||
|
||||
QPolygonF stripped;
|
||||
for ( int i = 0; i < nPoints; i++ )
|
||||
{
|
||||
if ( usePoint[i] )
|
||||
stripped += p[i];
|
||||
}
|
||||
|
||||
return stripped;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_CURVE_FITTER_H
|
||||
#define QWT_CURVE_FITTER_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpolygon.h>
|
||||
#include <qrect.h>
|
||||
|
||||
class QwtSpline;
|
||||
|
||||
/*!
|
||||
\brief Abstract base class for a curve fitter
|
||||
*/
|
||||
class QWT_EXPORT QwtCurveFitter
|
||||
{
|
||||
public:
|
||||
virtual ~QwtCurveFitter();
|
||||
|
||||
/*!
|
||||
Find a curve which has the best fit to a series of data points
|
||||
|
||||
\param polygon Series of data points
|
||||
\return Curve points
|
||||
*/
|
||||
virtual QPolygonF fitCurve( const QPolygonF &polygon ) const = 0;
|
||||
|
||||
protected:
|
||||
QwtCurveFitter();
|
||||
|
||||
private:
|
||||
QwtCurveFitter( const QwtCurveFitter & );
|
||||
QwtCurveFitter &operator=( const QwtCurveFitter & );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A curve fitter using cubic splines
|
||||
*/
|
||||
class QWT_EXPORT QwtSplineCurveFitter: public QwtCurveFitter
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Spline type
|
||||
The default setting is Auto
|
||||
\sa setFitMode(), FitMode()
|
||||
*/
|
||||
enum FitMode
|
||||
{
|
||||
/*!
|
||||
Use the default spline algorithm for polygons with
|
||||
increasing x values ( p[i-1] < p[i] ), otherwise use
|
||||
a parametric spline algorithm.
|
||||
*/
|
||||
Auto,
|
||||
|
||||
//! Use a default spline algorithm
|
||||
Spline,
|
||||
|
||||
//! Use a parametric spline algorithm
|
||||
ParametricSpline
|
||||
};
|
||||
|
||||
QwtSplineCurveFitter();
|
||||
virtual ~QwtSplineCurveFitter();
|
||||
|
||||
void setFitMode( FitMode );
|
||||
FitMode fitMode() const;
|
||||
|
||||
void setSpline( const QwtSpline& );
|
||||
const QwtSpline &spline() const;
|
||||
QwtSpline &spline();
|
||||
|
||||
void setSplineSize( int size );
|
||||
int splineSize() const;
|
||||
|
||||
virtual QPolygonF fitCurve( const QPolygonF & ) const;
|
||||
|
||||
private:
|
||||
QPolygonF fitSpline( const QPolygonF & ) const;
|
||||
QPolygonF fitParametric( const QPolygonF & ) const;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A curve fitter implementing Douglas and Peucker algorithm
|
||||
|
||||
The purpose of the Douglas and Peucker algorithm is that given a 'curve'
|
||||
composed of line segments to find a curve not too dissimilar but that
|
||||
has fewer points. The algorithm defines 'too dissimilar' based on the
|
||||
maximum distance (tolerance) between the original curve and the
|
||||
smoothed curve.
|
||||
|
||||
The runtime of the algorithm increases non linear ( worst case O( n*n ) )
|
||||
and might be very slow for huge polygons. To avoid performance issues
|
||||
it might be useful to split the polygon ( setChunkSize() ) and to run the algorithm
|
||||
for these smaller parts. The disadvantage of having no interpolation
|
||||
at the borders is for most use cases irrelevant.
|
||||
|
||||
The smoothed curve consists of a subset of the points that defined the
|
||||
original curve.
|
||||
|
||||
In opposite to QwtSplineCurveFitter the Douglas and Peucker algorithm reduces
|
||||
the number of points. By adjusting the tolerance parameter according to the
|
||||
axis scales QwtSplineCurveFitter can be used to implement different
|
||||
level of details to speed up painting of curves of many points.
|
||||
*/
|
||||
class QWT_EXPORT QwtWeedingCurveFitter: public QwtCurveFitter
|
||||
{
|
||||
public:
|
||||
QwtWeedingCurveFitter( double tolerance = 1.0 );
|
||||
virtual ~QwtWeedingCurveFitter();
|
||||
|
||||
void setTolerance( double );
|
||||
double tolerance() const;
|
||||
|
||||
void setChunkSize( uint );
|
||||
uint chunkSize() const;
|
||||
|
||||
virtual QPolygonF fitCurve( const QPolygonF & ) const;
|
||||
|
||||
private:
|
||||
virtual QPolygonF simplify( const QPolygonF & ) const;
|
||||
|
||||
class Line;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,760 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_date.h"
|
||||
#include <qdebug.h>
|
||||
#include <qlocale.h>
|
||||
#include <math.h>
|
||||
#include <limits>
|
||||
#include <limits.h>
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
|
||||
typedef qint64 QwtJulianDay;
|
||||
static const QwtJulianDay minJulianDayD = Q_INT64_C( -784350574879 );
|
||||
static const QwtJulianDay maxJulianDayD = Q_INT64_C( 784354017364 );
|
||||
|
||||
#else
|
||||
|
||||
// QDate stores the Julian day as unsigned int, but
|
||||
// but it is QDate::fromJulianDay( int ). That's why
|
||||
// we have the range [ 1, INT_MAX ]
|
||||
typedef int QwtJulianDay;
|
||||
static const QwtJulianDay minJulianDayD = 1;
|
||||
static const QwtJulianDay maxJulianDayD = std::numeric_limits<int>::max();
|
||||
|
||||
#endif
|
||||
|
||||
static QString qwtExpandedFormat( const QString & format,
|
||||
const QDateTime &dateTime, QwtDate::Week0Type week0Type )
|
||||
{
|
||||
const int week = QwtDate::weekNumber( dateTime.date(), week0Type );
|
||||
|
||||
QString weekNo;
|
||||
weekNo.setNum( week );
|
||||
|
||||
QString weekNoWW;
|
||||
if ( weekNo.length() == 1 )
|
||||
weekNoWW += "0";
|
||||
|
||||
weekNoWW += weekNo;
|
||||
|
||||
QString fmt = format;
|
||||
fmt.replace( "ww", weekNoWW );
|
||||
fmt.replace( "w", weekNo );
|
||||
|
||||
if ( week == 1 && dateTime.date().month() != 1 )
|
||||
{
|
||||
// in case of week 1, we might need to increment the year
|
||||
|
||||
static QString s_yyyy = "yyyy";
|
||||
static QString s_yy = "yy";
|
||||
|
||||
// week 1 might start in the previous year
|
||||
|
||||
bool doReplaceYear = fmt.contains( s_yy );
|
||||
|
||||
if ( doReplaceYear )
|
||||
{
|
||||
if ( fmt.contains( 'M' ) )
|
||||
{
|
||||
// in case of also having 'M' we have a conflict about
|
||||
// which year to show
|
||||
|
||||
doReplaceYear = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// in case of also having 'd' or 'dd' we have a conflict about
|
||||
// which year to show
|
||||
|
||||
int numD = 0;
|
||||
|
||||
for ( int i = 0; i < fmt.size(); i++ )
|
||||
{
|
||||
if ( fmt[i] == 'd' )
|
||||
{
|
||||
numD++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( numD > 0 && numD <= 2 )
|
||||
break;
|
||||
|
||||
numD = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( numD > 0 && numD <= 2 )
|
||||
doReplaceYear = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( doReplaceYear )
|
||||
{
|
||||
const QDate dt( dateTime.date().year() + 1, 1, 1 );
|
||||
|
||||
if ( fmt.contains( s_yyyy ) )
|
||||
{
|
||||
fmt.replace( s_yyyy, dt.toString( s_yyyy ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt.replace( s_yy, dt.toString( s_yyyy ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt;
|
||||
}
|
||||
|
||||
static inline Qt::DayOfWeek qwtFirstDayOfWeek()
|
||||
{
|
||||
#if QT_VERSION >= 0x040800
|
||||
return QLocale().firstDayOfWeek();
|
||||
#else
|
||||
|
||||
switch( QLocale().country() )
|
||||
{
|
||||
case QLocale::Maldives:
|
||||
return Qt::Friday;
|
||||
|
||||
case QLocale::Afghanistan:
|
||||
case QLocale::Algeria:
|
||||
case QLocale::Bahrain:
|
||||
case QLocale::Djibouti:
|
||||
case QLocale::Egypt:
|
||||
case QLocale::Eritrea:
|
||||
case QLocale::Ethiopia:
|
||||
case QLocale::Iran:
|
||||
case QLocale::Iraq:
|
||||
case QLocale::Jordan:
|
||||
case QLocale::Kenya:
|
||||
case QLocale::Kuwait:
|
||||
case QLocale::LibyanArabJamahiriya:
|
||||
case QLocale::Morocco:
|
||||
case QLocale::Oman:
|
||||
case QLocale::Qatar:
|
||||
case QLocale::SaudiArabia:
|
||||
case QLocale::Somalia:
|
||||
case QLocale::Sudan:
|
||||
case QLocale::Tunisia:
|
||||
case QLocale::Yemen:
|
||||
return Qt::Saturday;
|
||||
|
||||
case QLocale::AmericanSamoa:
|
||||
case QLocale::Argentina:
|
||||
case QLocale::Azerbaijan:
|
||||
case QLocale::Botswana:
|
||||
case QLocale::Canada:
|
||||
case QLocale::China:
|
||||
case QLocale::FaroeIslands:
|
||||
case QLocale::Georgia:
|
||||
case QLocale::Greenland:
|
||||
case QLocale::Guam:
|
||||
case QLocale::HongKong:
|
||||
case QLocale::Iceland:
|
||||
case QLocale::India:
|
||||
case QLocale::Ireland:
|
||||
case QLocale::Israel:
|
||||
case QLocale::Jamaica:
|
||||
case QLocale::Japan:
|
||||
case QLocale::Kyrgyzstan:
|
||||
case QLocale::Lao:
|
||||
case QLocale::Malta:
|
||||
case QLocale::MarshallIslands:
|
||||
case QLocale::Macau:
|
||||
case QLocale::Mongolia:
|
||||
case QLocale::NewZealand:
|
||||
case QLocale::NorthernMarianaIslands:
|
||||
case QLocale::Pakistan:
|
||||
case QLocale::Philippines:
|
||||
case QLocale::RepublicOfKorea:
|
||||
case QLocale::Singapore:
|
||||
case QLocale::SyrianArabRepublic:
|
||||
case QLocale::Taiwan:
|
||||
case QLocale::Thailand:
|
||||
case QLocale::TrinidadAndTobago:
|
||||
case QLocale::UnitedStates:
|
||||
case QLocale::UnitedStatesMinorOutlyingIslands:
|
||||
case QLocale::USVirginIslands:
|
||||
case QLocale::Uzbekistan:
|
||||
case QLocale::Zimbabwe:
|
||||
return Qt::Sunday;
|
||||
|
||||
default:
|
||||
return Qt::Monday;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void qwtFloorTime(
|
||||
QwtDate::IntervalType intervalType, QDateTime &dt )
|
||||
{
|
||||
// when dt is inside the special hour where DST is ending
|
||||
// an hour is no unique. Therefore we have to
|
||||
// use UTC time.
|
||||
|
||||
const Qt::TimeSpec timeSpec = dt.timeSpec();
|
||||
|
||||
if ( timeSpec == Qt::LocalTime )
|
||||
dt = dt.toTimeSpec( Qt::UTC );
|
||||
|
||||
const QTime t = dt.time();
|
||||
switch( intervalType )
|
||||
{
|
||||
case QwtDate::Second:
|
||||
{
|
||||
dt.setTime( QTime( t.hour(), t.minute(), t.second() ) );
|
||||
break;
|
||||
}
|
||||
case QwtDate::Minute:
|
||||
{
|
||||
dt.setTime( QTime( t.hour(), t.minute(), 0 ) );
|
||||
break;
|
||||
}
|
||||
case QwtDate::Hour:
|
||||
{
|
||||
dt.setTime( QTime( t.hour(), 0, 0 ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( timeSpec == Qt::LocalTime )
|
||||
dt = dt.toTimeSpec( Qt::LocalTime );
|
||||
}
|
||||
|
||||
static inline QDateTime qwtToTimeSpec(
|
||||
const QDateTime &dt, Qt::TimeSpec spec )
|
||||
{
|
||||
if ( dt.timeSpec() == spec )
|
||||
return dt;
|
||||
|
||||
const qint64 jd = dt.date().toJulianDay();
|
||||
if ( jd < 0 || jd >= INT_MAX )
|
||||
{
|
||||
// the conversion between local time and UTC
|
||||
// is internally limited. To avoid
|
||||
// overflows we simply ignore the difference
|
||||
// for those dates
|
||||
|
||||
QDateTime dt2 = dt;
|
||||
dt2.setTimeSpec( spec );
|
||||
return dt2;
|
||||
}
|
||||
|
||||
return dt.toTimeSpec( spec );
|
||||
}
|
||||
|
||||
static inline double qwtToJulianDay( int year, int month, int day )
|
||||
{
|
||||
// code from QDate but using doubles to avoid overflows
|
||||
// for large values
|
||||
|
||||
const int m1 = ( month - 14 ) / 12;
|
||||
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
|
||||
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
|
||||
|
||||
return ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
|
||||
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
|
||||
}
|
||||
|
||||
static inline qint64 qwtFloorDiv64( qint64 a, int b )
|
||||
{
|
||||
if ( a < 0 )
|
||||
a -= b - 1;
|
||||
|
||||
return a / b;
|
||||
}
|
||||
|
||||
static inline qint64 qwtFloorDiv( int a, int b )
|
||||
{
|
||||
if ( a < 0 )
|
||||
a -= b - 1;
|
||||
|
||||
return a / b;
|
||||
}
|
||||
|
||||
static inline QDate qwtToDate( int year, int month = 1, int day = 1 )
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return QDate( year, month, day );
|
||||
#else
|
||||
if ( year > 100000 )
|
||||
{
|
||||
// code from QDate but using doubles to avoid overflows
|
||||
// for large values
|
||||
|
||||
const int m1 = ( month - 14 ) / 12;
|
||||
const int m2 = ( 367 * ( month - 2 - 12 * m1 ) ) / 12;
|
||||
const double y1 = ::floor( ( 4900.0 + year + m1 ) / 100 );
|
||||
|
||||
const double jd = ::floor( ( 1461.0 * ( year + 4800 + m1 ) ) / 4 ) + m2
|
||||
- ::floor( ( 3 * y1 ) / 4 ) + day - 32075;
|
||||
|
||||
if ( jd > maxJulianDayD )
|
||||
{
|
||||
qWarning() << "qwtToDate: overflow";
|
||||
return QDate();
|
||||
}
|
||||
|
||||
return QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return QDate( year, month, day );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
Translate from double to QDateTime
|
||||
|
||||
\param value Number of milliseconds since the epoch,
|
||||
1970-01-01T00:00:00 UTC
|
||||
\param timeSpec Time specification
|
||||
\return Datetime value
|
||||
|
||||
\sa toDouble(), QDateTime::setMSecsSinceEpoch()
|
||||
\note The return datetime for Qt::OffsetFromUTC will be Qt::UTC
|
||||
*/
|
||||
QDateTime QwtDate::toDateTime( double value, Qt::TimeSpec timeSpec )
|
||||
{
|
||||
const int msecsPerDay = 86400000;
|
||||
|
||||
const double days = static_cast<qint64>( ::floor( value / msecsPerDay ) );
|
||||
|
||||
const double jd = QwtDate::JulianDayForEpoch + days;
|
||||
if ( ( jd > maxJulianDayD ) || ( jd < minJulianDayD ) )
|
||||
{
|
||||
qWarning() << "QwtDate::toDateTime: overflow";
|
||||
return QDateTime();
|
||||
}
|
||||
|
||||
const QDate d = QDate::fromJulianDay( static_cast<QwtJulianDay>( jd ) );
|
||||
|
||||
const int msecs = static_cast<int>( value - days * msecsPerDay );
|
||||
|
||||
static const QTime timeNull( 0, 0, 0, 0 );
|
||||
|
||||
QDateTime dt( d, timeNull.addMSecs( msecs ), Qt::UTC );
|
||||
|
||||
if ( timeSpec == Qt::LocalTime )
|
||||
dt = qwtToTimeSpec( dt, timeSpec );
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/*!
|
||||
Translate from QDateTime to double
|
||||
|
||||
\param dateTime Datetime value
|
||||
\return Number of milliseconds since 1970-01-01T00:00:00 UTC has passed.
|
||||
|
||||
\sa toDateTime(), QDateTime::toMSecsSinceEpoch()
|
||||
\warning For values very far below or above 1970-01-01 UTC rounding errors
|
||||
will happen due to the limited significance of a double.
|
||||
*/
|
||||
double QwtDate::toDouble( const QDateTime &dateTime )
|
||||
{
|
||||
const int msecsPerDay = 86400000;
|
||||
|
||||
const QDateTime dt = qwtToTimeSpec( dateTime, Qt::UTC );
|
||||
|
||||
const double days = dt.date().toJulianDay() - QwtDate::JulianDayForEpoch;
|
||||
|
||||
const QTime time = dt.time();
|
||||
const double secs = 3600.0 * time.hour() +
|
||||
60.0 * time.minute() + time.second();
|
||||
|
||||
return days * msecsPerDay + time.msec() + 1000.0 * secs;
|
||||
}
|
||||
|
||||
/*!
|
||||
Ceil a datetime according the interval type
|
||||
|
||||
\param dateTime Datetime value
|
||||
\param intervalType Interval type, how to ceil.
|
||||
F.e. when intervalType = QwtDate::Months, the result
|
||||
will be ceiled to the next beginning of a month
|
||||
\return Ceiled datetime
|
||||
\sa floor()
|
||||
*/
|
||||
QDateTime QwtDate::ceil( const QDateTime &dateTime, IntervalType intervalType )
|
||||
{
|
||||
if ( dateTime.date() >= QwtDate::maxDate() )
|
||||
return dateTime;
|
||||
|
||||
QDateTime dt = dateTime;
|
||||
|
||||
switch ( intervalType )
|
||||
{
|
||||
case QwtDate::Millisecond:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case QwtDate::Second:
|
||||
{
|
||||
qwtFloorTime( QwtDate::Second, dt );
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addSecs( 1 );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Minute:
|
||||
{
|
||||
qwtFloorTime( QwtDate::Minute, dt );
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addSecs( 60 );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Hour:
|
||||
{
|
||||
qwtFloorTime( QwtDate::Hour, dt );
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addSecs( 3600 );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Day:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addDays( 1 );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Week:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addDays( 1 );
|
||||
|
||||
int days = qwtFirstDayOfWeek() - dt.date().dayOfWeek();
|
||||
if ( days < 0 )
|
||||
days += 7;
|
||||
|
||||
dt = dt.addDays( days );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Month:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
dt.setDate( qwtToDate( dateTime.date().year(),
|
||||
dateTime.date().month() ) );
|
||||
|
||||
if ( dt < dateTime )
|
||||
dt = dt.addMonths( 1 );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Year:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
|
||||
const QDate d = dateTime.date();
|
||||
|
||||
int year = d.year();
|
||||
if ( d.month() > 1 || d.day() > 1 || !dateTime.time().isNull() )
|
||||
year++;
|
||||
|
||||
if ( year == 0 )
|
||||
year++; // there is no year 0
|
||||
|
||||
dt.setDate( qwtToDate( year ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/*!
|
||||
Floor a datetime according the interval type
|
||||
|
||||
\param dateTime Datetime value
|
||||
\param intervalType Interval type, how to ceil.
|
||||
F.e. when intervalType = QwtDate::Months,
|
||||
the result will be ceiled to the next
|
||||
beginning of a month
|
||||
\return Floored datetime
|
||||
\sa floor()
|
||||
*/
|
||||
QDateTime QwtDate::floor( const QDateTime &dateTime,
|
||||
IntervalType intervalType )
|
||||
{
|
||||
if ( dateTime.date() <= QwtDate::minDate() )
|
||||
return dateTime;
|
||||
|
||||
QDateTime dt = dateTime;
|
||||
|
||||
switch ( intervalType )
|
||||
{
|
||||
case QwtDate::Millisecond:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case QwtDate::Second:
|
||||
case QwtDate::Minute:
|
||||
case QwtDate::Hour:
|
||||
{
|
||||
qwtFloorTime( intervalType, dt );
|
||||
break;
|
||||
}
|
||||
case QwtDate::Day:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
break;
|
||||
}
|
||||
case QwtDate::Week:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
|
||||
int days = dt.date().dayOfWeek() - qwtFirstDayOfWeek();
|
||||
if ( days < 0 )
|
||||
days += 7;
|
||||
|
||||
dt = dt.addDays( -days );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Month:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
|
||||
const QDate date = qwtToDate( dt.date().year(),
|
||||
dt.date().month() );
|
||||
dt.setDate( date );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtDate::Year:
|
||||
{
|
||||
dt.setTime( QTime( 0, 0 ) );
|
||||
|
||||
const QDate date = qwtToDate( dt.date().year() );
|
||||
dt.setDate( date );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
|
||||
/*!
|
||||
Minimum for the supported date range
|
||||
|
||||
The range of valid dates depends on how QDate stores the
|
||||
Julian day internally.
|
||||
|
||||
- For Qt4 it is "Tue Jan 2 -4713"
|
||||
- For Qt5 it is "Thu Jan 1 -2147483648"
|
||||
|
||||
\return minimum of the date range
|
||||
\sa maxDate()
|
||||
*/
|
||||
QDate QwtDate::minDate()
|
||||
{
|
||||
static QDate date;
|
||||
if ( !date.isValid() )
|
||||
date = QDate::fromJulianDay( minJulianDayD );
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
/*!
|
||||
Maximum for the supported date range
|
||||
|
||||
The range of valid dates depends on how QDate stores the
|
||||
Julian day internally.
|
||||
|
||||
- For Qt4 it is "Tue Jun 3 5874898"
|
||||
- For Qt5 it is "Tue Dec 31 2147483647"
|
||||
|
||||
\return maximum of the date range
|
||||
\sa minDate()
|
||||
\note The maximum differs between Qt4 and Qt5
|
||||
*/
|
||||
QDate QwtDate::maxDate()
|
||||
{
|
||||
static QDate date;
|
||||
if ( !date.isValid() )
|
||||
date = QDate::fromJulianDay( maxJulianDayD );
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Date of the first day of the first week for a year
|
||||
|
||||
The first day of a week depends on the current locale
|
||||
( QLocale::firstDayOfWeek() ).
|
||||
|
||||
\param year Year
|
||||
\param type Option how to identify the first week
|
||||
\return First day of week 0
|
||||
|
||||
\sa QLocale::firstDayOfWeek(), weekNumber()
|
||||
*/
|
||||
QDate QwtDate::dateOfWeek0( int year, Week0Type type )
|
||||
{
|
||||
const Qt::DayOfWeek firstDayOfWeek = qwtFirstDayOfWeek();
|
||||
|
||||
QDate dt0( year, 1, 1 );
|
||||
|
||||
// floor to the first day of the week
|
||||
int days = dt0.dayOfWeek() - firstDayOfWeek;
|
||||
if ( days < 0 )
|
||||
days += 7;
|
||||
|
||||
dt0 = dt0.addDays( -days );
|
||||
|
||||
if ( type == QwtDate::FirstThursday )
|
||||
{
|
||||
// according to ISO 8601 the first week is defined
|
||||
// by the first thursday.
|
||||
|
||||
int d = Qt::Thursday - firstDayOfWeek;
|
||||
if ( d < 0 )
|
||||
d += 7;
|
||||
|
||||
if ( dt0.addDays( d ).year() < year )
|
||||
dt0 = dt0.addDays( 7 );
|
||||
}
|
||||
|
||||
return dt0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the week number of a date
|
||||
|
||||
- QwtDate::FirstThursday\n
|
||||
Corresponding to ISO 8601 ( see QDate::weekNumber() ).
|
||||
|
||||
- QwtDate::FirstDay\n
|
||||
Number of weeks that have begun since dateOfWeek0().
|
||||
|
||||
\param date Date
|
||||
\param type Option how to identify the first week
|
||||
|
||||
\return Week number, starting with 1
|
||||
*/
|
||||
int QwtDate::weekNumber( const QDate &date, Week0Type type )
|
||||
{
|
||||
int weekNo;
|
||||
|
||||
if ( type == QwtDate::FirstDay )
|
||||
{
|
||||
QDate day0;
|
||||
|
||||
if ( date.month() == 12 && date.day() >= 24 )
|
||||
{
|
||||
// week 1 usually starts in the previous years.
|
||||
// and we have to check if we are already there
|
||||
|
||||
day0 = dateOfWeek0( date.year() + 1, type );
|
||||
if ( day0.daysTo( date ) < 0 )
|
||||
day0 = dateOfWeek0( date.year(), type );
|
||||
}
|
||||
else
|
||||
{
|
||||
day0 = dateOfWeek0( date.year(), type );
|
||||
}
|
||||
|
||||
weekNo = day0.daysTo( date ) / 7 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
weekNo = date.weekNumber();
|
||||
}
|
||||
|
||||
return weekNo;
|
||||
}
|
||||
|
||||
/*!
|
||||
Offset in seconds from Coordinated Universal Time
|
||||
|
||||
The offset depends on the time specification of dateTime:
|
||||
|
||||
- Qt::UTC
|
||||
0, dateTime has no offset
|
||||
- Qt::OffsetFromUTC
|
||||
returns dateTime.utcOffset()
|
||||
- Qt::LocalTime:
|
||||
number of seconds from the UTC
|
||||
|
||||
For Qt::LocalTime the offset depends on the timezone and
|
||||
daylight savings.
|
||||
|
||||
\param dateTime Datetime value
|
||||
\return Offset in seconds
|
||||
*/
|
||||
int QwtDate::utcOffset( const QDateTime &dateTime )
|
||||
{
|
||||
int seconds = 0;
|
||||
|
||||
switch( dateTime.timeSpec() )
|
||||
{
|
||||
case Qt::UTC:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Qt::OffsetFromUTC:
|
||||
{
|
||||
seconds = dateTime.utcOffset();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
const QDateTime dt1( dateTime.date(), dateTime.time(), Qt::UTC );
|
||||
seconds = dateTime.secsTo( dt1 );
|
||||
}
|
||||
}
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/*!
|
||||
Translate a datetime into a string
|
||||
|
||||
Beside the format expressions documented in QDateTime::toString()
|
||||
the following expressions are supported:
|
||||
|
||||
- w\n
|
||||
week number: ( 1 - 53 )
|
||||
- ww\n
|
||||
week number with a leading zero ( 01 - 53 )
|
||||
|
||||
As week 1 usually starts in the previous year a special rule
|
||||
is applied for formats, where the year is expected to match the
|
||||
week number - even if the date belongs to the previous year.
|
||||
|
||||
\param dateTime Datetime value
|
||||
\param format Format string
|
||||
\param week0Type Specification of week 0
|
||||
|
||||
\return Datetime string
|
||||
\sa QDateTime::toString(), weekNumber(), QwtDateScaleDraw
|
||||
*/
|
||||
QString QwtDate::toString( const QDateTime &dateTime,
|
||||
const QString & format, Week0Type week0Type )
|
||||
{
|
||||
QString fmt = format;
|
||||
if ( fmt.contains( 'w' ) )
|
||||
{
|
||||
fmt = qwtExpandedFormat( fmt, dateTime, week0Type );
|
||||
}
|
||||
|
||||
return dateTime.toString( fmt );
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _QWT_DATE_H_
|
||||
#define _QWT_DATE_H_
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qdatetime.h>
|
||||
|
||||
/*!
|
||||
\brief A collection of methods around date/time values
|
||||
|
||||
Qt offers convenient classes for dealing with date/time values,
|
||||
but Qwt uses coordinate systems that are based on doubles.
|
||||
QwtDate offers methods to translate from QDateTime to double and v.v.
|
||||
|
||||
A double is interpreted as the number of milliseconds since
|
||||
1970-01-01T00:00:00 Universal Coordinated Time - also known
|
||||
as "The Epoch".
|
||||
|
||||
While the range of the Julian day in Qt4 is limited to [0, MAX_INT],
|
||||
Qt5 stores it as qint64 offering a huge range of valid dates.
|
||||
As the significance of a double is below this ( assuming a
|
||||
fraction of 52 bits ) the translation is not
|
||||
bijective with rounding errors for dates very far from Epoch.
|
||||
For a resolution of 1 ms those start to happen for dates above the
|
||||
year 144683.
|
||||
|
||||
An axis for a date/time interval is expected to be aligned
|
||||
and divided in time/date units like seconds, minutes, ...
|
||||
QwtDate offers several algorithms that are needed to
|
||||
calculate these axes.
|
||||
|
||||
\sa QwtDateScaleEngine, QwtDateScaleDraw, QDate, QTime
|
||||
*/
|
||||
class QWT_EXPORT QwtDate
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
How to identify the first week of year differs between
|
||||
countries.
|
||||
*/
|
||||
enum Week0Type
|
||||
{
|
||||
/*!
|
||||
According to ISO 8601 the first week of a year is defined
|
||||
as "the week with the year's first Thursday in it".
|
||||
|
||||
FirstThursday corresponds to the numbering that is
|
||||
implemented in QDate::weekNumber().
|
||||
*/
|
||||
FirstThursday,
|
||||
|
||||
/*!
|
||||
"The week with January 1.1 in it."
|
||||
|
||||
In the U.S. this definition is more common than
|
||||
FirstThursday.
|
||||
*/
|
||||
FirstDay
|
||||
};
|
||||
|
||||
/*!
|
||||
Classification of an time interval
|
||||
|
||||
Time intervals needs to be classified to decide how to
|
||||
align and divide it.
|
||||
*/
|
||||
enum IntervalType
|
||||
{
|
||||
//! The interval is related to milliseconds
|
||||
Millisecond,
|
||||
|
||||
//! The interval is related to seconds
|
||||
Second,
|
||||
|
||||
//! The interval is related to minutes
|
||||
Minute,
|
||||
|
||||
//! The interval is related to hours
|
||||
Hour,
|
||||
|
||||
//! The interval is related to days
|
||||
Day,
|
||||
|
||||
//! The interval is related to weeks
|
||||
Week,
|
||||
|
||||
//! The interval is related to months
|
||||
Month,
|
||||
|
||||
//! The interval is related to years
|
||||
Year
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
//! The Julian day of "The Epoch"
|
||||
JulianDayForEpoch = 2440588
|
||||
};
|
||||
|
||||
static QDate minDate();
|
||||
static QDate maxDate();
|
||||
|
||||
static QDateTime toDateTime( double value,
|
||||
Qt::TimeSpec = Qt::UTC );
|
||||
|
||||
static double toDouble( const QDateTime & );
|
||||
|
||||
static QDateTime ceil( const QDateTime &, IntervalType );
|
||||
static QDateTime floor( const QDateTime &, IntervalType );
|
||||
|
||||
static QDate dateOfWeek0( int year, Week0Type );
|
||||
static int weekNumber( const QDate &, Week0Type );
|
||||
|
||||
static int utcOffset( const QDateTime & );
|
||||
|
||||
static QString toString( const QDateTime &,
|
||||
const QString & format, Week0Type );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,278 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_date_scale_draw.h"
|
||||
|
||||
class QwtDateScaleDraw::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData( Qt::TimeSpec spec ):
|
||||
timeSpec( spec ),
|
||||
utcOffset( 0 ),
|
||||
week0Type( QwtDate::FirstThursday )
|
||||
{
|
||||
dateFormats[ QwtDate::Millisecond ] = "hh:mm:ss:zzz\nddd dd MMM yyyy";
|
||||
dateFormats[ QwtDate::Second ] = "hh:mm:ss\nddd dd MMM yyyy";
|
||||
dateFormats[ QwtDate::Minute ] = "hh:mm\nddd dd MMM yyyy";
|
||||
dateFormats[ QwtDate::Hour ] = "hh:mm\nddd dd MMM yyyy";
|
||||
dateFormats[ QwtDate::Day ] = "ddd dd MMM yyyy";
|
||||
dateFormats[ QwtDate::Week ] = "Www yyyy";
|
||||
dateFormats[ QwtDate::Month ] = "MMM yyyy";
|
||||
dateFormats[ QwtDate::Year ] = "yyyy";
|
||||
}
|
||||
|
||||
Qt::TimeSpec timeSpec;
|
||||
int utcOffset;
|
||||
QwtDate::Week0Type week0Type;
|
||||
QString dateFormats[ QwtDate::Year + 1 ];
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Constructor
|
||||
|
||||
The default setting is to display tick labels for the
|
||||
given time specification. The first week of a year is defined like
|
||||
for QwtDate::FirstThursday.
|
||||
|
||||
\param timeSpec Time specification
|
||||
|
||||
\sa setTimeSpec(), setWeek0Type()
|
||||
*/
|
||||
QwtDateScaleDraw::QwtDateScaleDraw( Qt::TimeSpec timeSpec )
|
||||
{
|
||||
d_data = new PrivateData( timeSpec );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtDateScaleDraw::~QwtDateScaleDraw()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the time specification used for the tick labels
|
||||
|
||||
\param timeSpec Time specification
|
||||
\sa timeSpec(), setUtcOffset(), toDateTime()
|
||||
*/
|
||||
void QwtDateScaleDraw::setTimeSpec( Qt::TimeSpec timeSpec )
|
||||
{
|
||||
d_data->timeSpec = timeSpec;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Time specification used for the tick labels
|
||||
\sa setTimeSpec(), utcOffset(), toDateTime()
|
||||
*/
|
||||
Qt::TimeSpec QwtDateScaleDraw::timeSpec() const
|
||||
{
|
||||
return d_data->timeSpec;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the offset in seconds from Coordinated Universal Time
|
||||
|
||||
\param seconds Offset in seconds
|
||||
|
||||
\note The offset has no effect beside for the time specification
|
||||
Qt::OffsetFromUTC.
|
||||
|
||||
\sa QDate::utcOffset(), setTimeSpec(), toDateTime()
|
||||
*/
|
||||
void QwtDateScaleDraw::setUtcOffset( int seconds )
|
||||
{
|
||||
d_data->utcOffset = seconds;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Offset in seconds from Coordinated Universal Time
|
||||
\note The offset has no effect beside for the time specification
|
||||
Qt::OffsetFromUTC.
|
||||
|
||||
\sa QDate::setUtcOffset(), setTimeSpec(), toDateTime()
|
||||
*/
|
||||
int QwtDateScaleDraw::utcOffset() const
|
||||
{
|
||||
return d_data->utcOffset;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets how to identify the first week of a year.
|
||||
|
||||
\param week0Type Mode how to identify the first week of a year
|
||||
|
||||
\sa week0Type().
|
||||
\note week0Type has no effect beside for intervals classified as
|
||||
QwtDate::Week.
|
||||
*/
|
||||
void QwtDateScaleDraw::setWeek0Type( QwtDate::Week0Type week0Type )
|
||||
{
|
||||
d_data->week0Type = week0Type;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Setting how to identify the first week of a year.
|
||||
\sa setWeek0Type()
|
||||
*/
|
||||
QwtDate::Week0Type QwtDateScaleDraw::week0Type() const
|
||||
{
|
||||
return d_data->week0Type;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the default format string for an datetime interval type
|
||||
|
||||
\param intervalType Interval type
|
||||
\param format Default format string
|
||||
|
||||
\sa dateFormat(), dateFormatOfDate(), QwtDate::toString()
|
||||
*/
|
||||
void QwtDateScaleDraw::setDateFormat(
|
||||
QwtDate::IntervalType intervalType, const QString &format )
|
||||
{
|
||||
if ( intervalType >= QwtDate::Millisecond &&
|
||||
intervalType <= QwtDate::Year )
|
||||
{
|
||||
d_data->dateFormats[ intervalType ] = format;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\param intervalType Interval type
|
||||
\return Default format string for an datetime interval type
|
||||
\sa setDateFormat(), dateFormatOfDate()
|
||||
*/
|
||||
QString QwtDateScaleDraw::dateFormat(
|
||||
QwtDate::IntervalType intervalType ) const
|
||||
{
|
||||
if ( intervalType >= QwtDate::Millisecond &&
|
||||
intervalType <= QwtDate::Year )
|
||||
{
|
||||
return d_data->dateFormats[ intervalType ];
|
||||
}
|
||||
|
||||
return QString::null;
|
||||
}
|
||||
|
||||
/*!
|
||||
Format string for the representation of a datetime
|
||||
|
||||
dateFormatOfDate() is intended to be overloaded for
|
||||
situations, where formats are individual for specific
|
||||
datetime values.
|
||||
|
||||
The default setting ignores dateTime and return
|
||||
the default format for the interval type.
|
||||
|
||||
\param dateTime Datetime value
|
||||
\param intervalType Interval type
|
||||
\return Format string
|
||||
|
||||
\sa setDateFormat(), QwtDate::toString()
|
||||
*/
|
||||
QString QwtDateScaleDraw::dateFormatOfDate( const QDateTime &dateTime,
|
||||
QwtDate::IntervalType intervalType ) const
|
||||
{
|
||||
Q_UNUSED( dateTime )
|
||||
|
||||
if ( intervalType >= QwtDate::Millisecond &&
|
||||
intervalType <= QwtDate::Year )
|
||||
{
|
||||
return d_data->dateFormats[ intervalType ];
|
||||
}
|
||||
|
||||
return d_data->dateFormats[ QwtDate::Second ];
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Convert a value into its representing label
|
||||
|
||||
The value is converted to a datetime value using toDateTime()
|
||||
and converted to a plain text using QwtDate::toString().
|
||||
|
||||
\param value Value
|
||||
\return Label string.
|
||||
|
||||
\sa dateFormatOfDate()
|
||||
*/
|
||||
QwtText QwtDateScaleDraw::label( double value ) const
|
||||
{
|
||||
const QDateTime dt = toDateTime( value );
|
||||
const QString fmt = dateFormatOfDate(
|
||||
dt, intervalType( scaleDiv() ) );
|
||||
|
||||
return QwtDate::toString( dt, fmt, d_data->week0Type );
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the less detailed datetime unit, where no rounding
|
||||
errors happen.
|
||||
|
||||
\param scaleDiv Scale division
|
||||
\return Interval type
|
||||
|
||||
\sa dateFormatOfDate()
|
||||
*/
|
||||
QwtDate::IntervalType QwtDateScaleDraw::intervalType(
|
||||
const QwtScaleDiv &scaleDiv ) const
|
||||
{
|
||||
int intvType = QwtDate::Year;
|
||||
|
||||
bool alignedToWeeks = true;
|
||||
|
||||
const QList<double> ticks = scaleDiv.ticks( QwtScaleDiv::MajorTick );
|
||||
for ( int i = 0; i < ticks.size(); i++ )
|
||||
{
|
||||
const QDateTime dt = toDateTime( ticks[i] );
|
||||
for ( int j = QwtDate::Second; j <= intvType; j++ )
|
||||
{
|
||||
const QDateTime dt0 = QwtDate::floor( dt,
|
||||
static_cast<QwtDate::IntervalType>( j ) );
|
||||
|
||||
if ( dt0 != dt )
|
||||
{
|
||||
if ( j == QwtDate::Week )
|
||||
{
|
||||
alignedToWeeks = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
intvType = j - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( intvType == QwtDate::Millisecond )
|
||||
break;
|
||||
}
|
||||
|
||||
if ( intvType == QwtDate::Week && !alignedToWeeks )
|
||||
intvType = QwtDate::Day;
|
||||
|
||||
return static_cast<QwtDate::IntervalType>( intvType );
|
||||
}
|
||||
|
||||
/*!
|
||||
Translate a double value into a QDateTime object.
|
||||
|
||||
\return QDateTime object initialized with timeSpec() and utcOffset().
|
||||
\sa timeSpec(), utcOffset(), QwtDate::toDateTime()
|
||||
*/
|
||||
QDateTime QwtDateScaleDraw::toDateTime( double value ) const
|
||||
{
|
||||
QDateTime dt = QwtDate::toDateTime( value, d_data->timeSpec );
|
||||
if ( d_data->timeSpec == Qt::OffsetFromUTC )
|
||||
{
|
||||
dt = dt.addSecs( d_data->utcOffset );
|
||||
dt.setUtcOffset( d_data->utcOffset );
|
||||
}
|
||||
|
||||
return dt;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _QWT_DATE_SCALE_DRAW_H_
|
||||
#define _QWT_DATE_SCALE_DRAW_H_ 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_scale_draw.h"
|
||||
#include "qwt_date.h"
|
||||
|
||||
/*!
|
||||
\brief A class for drawing datetime scales
|
||||
|
||||
QwtDateScaleDraw displays values as datetime labels.
|
||||
The format of the labels depends on the alignment of
|
||||
the major tick labels.
|
||||
|
||||
The default format strings are:
|
||||
|
||||
- Millisecond\n
|
||||
"hh:mm:ss:zzz\nddd dd MMM yyyy"
|
||||
- Second\n
|
||||
"hh:mm:ss\nddd dd MMM yyyy"
|
||||
- Minute\n
|
||||
"hh:mm\nddd dd MMM yyyy"
|
||||
- Hour\n
|
||||
"hh:mm\nddd dd MMM yyyy"
|
||||
- Day\n
|
||||
"ddd dd MMM yyyy"
|
||||
- Week\n
|
||||
"Www yyyy"
|
||||
- Month\n
|
||||
"MMM yyyy"
|
||||
- Year\n
|
||||
"yyyy"
|
||||
|
||||
The format strings can be modified using setDateFormat()
|
||||
or individually for each tick label by overloading dateFormatOfDate(),
|
||||
|
||||
Usually QwtDateScaleDraw is used in combination with
|
||||
QwtDateScaleEngine, that calculates scales for datetime
|
||||
intervals.
|
||||
|
||||
\sa QwtDateScaleEngine, QwtPlot::setAxisScaleDraw()
|
||||
*/
|
||||
class QWT_EXPORT QwtDateScaleDraw: public QwtScaleDraw
|
||||
{
|
||||
public:
|
||||
QwtDateScaleDraw( Qt::TimeSpec = Qt::LocalTime );
|
||||
virtual ~QwtDateScaleDraw();
|
||||
|
||||
void setDateFormat( QwtDate::IntervalType, const QString & );
|
||||
QString dateFormat( QwtDate::IntervalType ) const;
|
||||
|
||||
void setTimeSpec( Qt::TimeSpec );
|
||||
Qt::TimeSpec timeSpec() const;
|
||||
|
||||
void setUtcOffset( int seconds );
|
||||
int utcOffset() const;
|
||||
|
||||
void setWeek0Type( QwtDate::Week0Type );
|
||||
QwtDate::Week0Type week0Type() const;
|
||||
|
||||
virtual QwtText label( double ) const;
|
||||
|
||||
QDateTime toDateTime( double ) const;
|
||||
|
||||
protected:
|
||||
virtual QwtDate::IntervalType
|
||||
intervalType( const QwtScaleDiv & ) const;
|
||||
|
||||
virtual QString dateFormatOfDate( const QDateTime &,
|
||||
QwtDate::IntervalType ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,86 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _QWT_DATE_SCALE_ENGINE_H_
|
||||
#define _QWT_DATE_SCALE_ENGINE_H_ 1
|
||||
|
||||
#include "qwt_date.h"
|
||||
#include "qwt_scale_engine.h"
|
||||
|
||||
/*!
|
||||
\brief A scale engine for date/time values
|
||||
|
||||
QwtDateScaleEngine builds scales from a time intervals.
|
||||
Together with QwtDateScaleDraw it can be used for
|
||||
axes according to date/time values.
|
||||
|
||||
Years, months, weeks, days, hours and minutes are organized
|
||||
in steps with non constant intervals. QwtDateScaleEngine
|
||||
classifies intervals and aligns the boundaries and tick positions
|
||||
according to this classification.
|
||||
|
||||
QwtDateScaleEngine supports representations depending
|
||||
on Qt::TimeSpec specifications. The valid range for scales
|
||||
is limited by the range of QDateTime, that differs
|
||||
between Qt4 and Qt5.
|
||||
|
||||
Datetime values are expected as the number of milliseconds since
|
||||
1970-01-01T00:00:00 Universal Coordinated Time - also known
|
||||
as "The Epoch", that can be converted to QDateTime using
|
||||
QwtDate::toDateTime().
|
||||
|
||||
\sa QwtDate, QwtPlot::setAxisScaleEngine(),
|
||||
QwtAbstractScale::setScaleEngine()
|
||||
*/
|
||||
class QWT_EXPORT QwtDateScaleEngine: public QwtLinearScaleEngine
|
||||
{
|
||||
public:
|
||||
QwtDateScaleEngine( Qt::TimeSpec = Qt::LocalTime );
|
||||
virtual ~QwtDateScaleEngine();
|
||||
|
||||
void setTimeSpec( Qt::TimeSpec );
|
||||
Qt::TimeSpec timeSpec() const;
|
||||
|
||||
void setUtcOffset( int seconds );
|
||||
int utcOffset() const;
|
||||
|
||||
void setWeek0Type( QwtDate::Week0Type );
|
||||
QwtDate::Week0Type week0Type() const;
|
||||
|
||||
void setMaxWeeks( int );
|
||||
int maxWeeks() const;
|
||||
|
||||
virtual void autoScale( int maxNumSteps,
|
||||
double &x1, double &x2, double &stepSize ) const;
|
||||
|
||||
virtual QwtScaleDiv divideScale(
|
||||
double x1, double x2,
|
||||
int maxMajorSteps, int maxMinorSteps,
|
||||
double stepSize = 0.0 ) const;
|
||||
|
||||
virtual QwtDate::IntervalType intervalType(
|
||||
const QDateTime &, const QDateTime &, int maxSteps ) const;
|
||||
|
||||
QDateTime toDateTime( double ) const;
|
||||
|
||||
protected:
|
||||
virtual QDateTime alignDate( const QDateTime &, double stepSize,
|
||||
QwtDate::IntervalType, bool up ) const;
|
||||
|
||||
private:
|
||||
QwtScaleDiv buildScaleDiv( const QDateTime &, const QDateTime &,
|
||||
int maxMajorSteps, int maxMinorSteps,
|
||||
QwtDate::IntervalType ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,871 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_dial.h"
|
||||
#include "qwt_dial_needle.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_scale_engine.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_round_scale_draw.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qpainter.h>
|
||||
#include <qpalette.h>
|
||||
#include <qpixmap.h>
|
||||
#include <qevent.h>
|
||||
#include <qalgorithms.h>
|
||||
#include <qmath.h>
|
||||
#include <qstyle.h>
|
||||
#include <qstyleoption.h>
|
||||
#include <qapplication.h>
|
||||
|
||||
static inline double qwtAngleDist( double a1, double a2 )
|
||||
{
|
||||
double dist = qAbs( a2 - a1 );
|
||||
if ( dist > 360.0 )
|
||||
dist -= 360.0;
|
||||
|
||||
return dist;
|
||||
}
|
||||
|
||||
static inline bool qwtIsOnArc( double angle, double min, double max )
|
||||
{
|
||||
if ( min < max )
|
||||
{
|
||||
return ( angle >= min ) && ( angle <= max );
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( angle >= min ) || ( angle <= max );
|
||||
}
|
||||
}
|
||||
|
||||
static inline double qwtBoundedAngle( double min, double angle, double max )
|
||||
{
|
||||
double from = qwtNormalizeDegrees( min );
|
||||
double to = qwtNormalizeDegrees( max );
|
||||
|
||||
double a;
|
||||
|
||||
if ( qwtIsOnArc( angle, from, to ) )
|
||||
{
|
||||
a = angle;
|
||||
if ( a < min )
|
||||
a += 360.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qwtAngleDist( angle, from ) <
|
||||
qwtAngleDist( angle, to ) )
|
||||
{
|
||||
a = min;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = max;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
class QwtDial::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
frameShadow( Sunken ),
|
||||
lineWidth( 0 ),
|
||||
mode( RotateNeedle ),
|
||||
origin( 90.0 ),
|
||||
minScaleArc( 0.0 ),
|
||||
maxScaleArc( 0.0 ),
|
||||
needle( NULL ),
|
||||
arcOffset( 0.0 ),
|
||||
mouseOffset( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
delete needle;
|
||||
}
|
||||
Shadow frameShadow;
|
||||
int lineWidth;
|
||||
|
||||
QwtDial::Mode mode;
|
||||
|
||||
double origin;
|
||||
double minScaleArc;
|
||||
double maxScaleArc;
|
||||
|
||||
QwtDialNeedle *needle;
|
||||
|
||||
double arcOffset;
|
||||
double mouseOffset;
|
||||
|
||||
QPixmap pixmapCache;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Constructor
|
||||
\param parent Parent widget
|
||||
|
||||
Create a dial widget with no needle. The scale is initialized
|
||||
to [ 0.0, 360.0 ] and 360 steps ( QwtAbstractSlider::setTotalSteps() ).
|
||||
The origin of the scale is at 90°,
|
||||
|
||||
The value is set to 0.0.
|
||||
|
||||
The default mode is QwtDial::RotateNeedle.
|
||||
*/
|
||||
QwtDial::QwtDial( QWidget* parent ):
|
||||
QwtAbstractSlider( parent )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
setFocusPolicy( Qt::TabFocus );
|
||||
|
||||
QPalette p = palette();
|
||||
for ( int i = 0; i < QPalette::NColorGroups; i++ )
|
||||
{
|
||||
const QPalette::ColorGroup colorGroup =
|
||||
static_cast<QPalette::ColorGroup>( i );
|
||||
|
||||
// Base: background color of the circle inside the frame.
|
||||
// WindowText: background color of the circle inside the scale
|
||||
|
||||
p.setColor( colorGroup, QPalette::WindowText,
|
||||
p.color( colorGroup, QPalette::Base ) );
|
||||
}
|
||||
setPalette( p );
|
||||
|
||||
QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
|
||||
scaleDraw->setRadius( 0 );
|
||||
|
||||
setScaleDraw( scaleDraw );
|
||||
|
||||
setScaleArc( 0.0, 360.0 ); // scale as a full circle
|
||||
|
||||
setScaleMaxMajor( 10 );
|
||||
setScaleMaxMinor( 5 );
|
||||
|
||||
setValue( 0.0 );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtDial::~QwtDial()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the frame shadow value from the frame style.
|
||||
|
||||
\param shadow Frame shadow
|
||||
\sa setLineWidth(), QFrame::setFrameShadow()
|
||||
*/
|
||||
void QwtDial::setFrameShadow( Shadow shadow )
|
||||
{
|
||||
if ( shadow != d_data->frameShadow )
|
||||
{
|
||||
invalidateCache();
|
||||
|
||||
d_data->frameShadow = shadow;
|
||||
if ( lineWidth() > 0 )
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Frame shadow
|
||||
/sa setFrameShadow(), lineWidth(), QFrame::frameShadow()
|
||||
*/
|
||||
QwtDial::Shadow QwtDial::frameShadow() const
|
||||
{
|
||||
return d_data->frameShadow;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the line width of the frame
|
||||
|
||||
\param lineWidth Line width
|
||||
\sa setFrameShadow()
|
||||
*/
|
||||
void QwtDial::setLineWidth( int lineWidth )
|
||||
{
|
||||
if ( lineWidth < 0 )
|
||||
lineWidth = 0;
|
||||
|
||||
if ( d_data->lineWidth != lineWidth )
|
||||
{
|
||||
invalidateCache();
|
||||
|
||||
d_data->lineWidth = lineWidth;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Line width of the frame
|
||||
\sa setLineWidth(), frameShadow(), lineWidth()
|
||||
*/
|
||||
int QwtDial::lineWidth() const
|
||||
{
|
||||
return d_data->lineWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return bounding rectangle of the circle inside the frame
|
||||
\sa setLineWidth(), scaleInnerRect(), boundingRect()
|
||||
*/
|
||||
QRect QwtDial::innerRect() const
|
||||
{
|
||||
const int lw = lineWidth();
|
||||
return boundingRect().adjusted( lw, lw, -lw, -lw );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return bounding rectangle of the dial including the frame
|
||||
\sa setLineWidth(), scaleInnerRect(), innerRect()
|
||||
*/
|
||||
QRect QwtDial::boundingRect() const
|
||||
{
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
const double dim = qMin( cr.width(), cr.height() );
|
||||
|
||||
QRect inner( 0, 0, dim, dim );
|
||||
inner.moveCenter( cr.center() );
|
||||
|
||||
return inner;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return rectangle inside the scale
|
||||
\sa setLineWidth(), boundingRect(), innerRect()
|
||||
*/
|
||||
QRect QwtDial::scaleInnerRect() const
|
||||
{
|
||||
QRect rect = innerRect();
|
||||
|
||||
const QwtAbstractScaleDraw *sd = scaleDraw();
|
||||
if ( sd )
|
||||
{
|
||||
int scaleDist = qCeil( sd->extent( font() ) );
|
||||
scaleDist++; // margin
|
||||
|
||||
rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the mode of the dial.
|
||||
\param mode New mode
|
||||
|
||||
In case of QwtDial::RotateNeedle the needle is rotating, in case of
|
||||
QwtDial::RotateScale, the needle points to origin()
|
||||
and the scale is rotating.
|
||||
|
||||
The default mode is QwtDial::RotateNeedle.
|
||||
|
||||
\sa mode(), setValue(), setOrigin()
|
||||
*/
|
||||
void QwtDial::setMode( Mode mode )
|
||||
{
|
||||
if ( mode != d_data->mode )
|
||||
{
|
||||
invalidateCache();
|
||||
|
||||
d_data->mode = mode;
|
||||
sliderChange();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Mode of the dial.
|
||||
\sa setMode(), origin(), setScaleArc(), value()
|
||||
*/
|
||||
QwtDial::Mode QwtDial::mode() const
|
||||
{
|
||||
return d_data->mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Invalidate the internal caches used to speed up repainting
|
||||
*/
|
||||
void QwtDial::invalidateCache()
|
||||
{
|
||||
d_data->pixmapCache = QPixmap();
|
||||
}
|
||||
|
||||
/*!
|
||||
Paint the dial
|
||||
\param event Paint event
|
||||
*/
|
||||
void QwtDial::paintEvent( QPaintEvent *event )
|
||||
{
|
||||
QPainter painter( this );
|
||||
painter.setClipRegion( event->region() );
|
||||
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||
|
||||
if ( d_data->mode == QwtDial::RotateScale )
|
||||
{
|
||||
painter.save();
|
||||
painter.setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
drawContents( &painter );
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
const QRect r = contentsRect();
|
||||
if ( r.size() != d_data->pixmapCache.size() )
|
||||
{
|
||||
d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
|
||||
d_data->pixmapCache.fill( Qt::transparent );
|
||||
|
||||
QPainter p( &d_data->pixmapCache );
|
||||
p.setRenderHint( QPainter::Antialiasing, true );
|
||||
p.translate( -r.topLeft() );
|
||||
|
||||
if ( d_data->mode != QwtDial::RotateScale )
|
||||
drawContents( &p );
|
||||
|
||||
if ( lineWidth() > 0 )
|
||||
drawFrame( &p );
|
||||
|
||||
if ( d_data->mode != QwtDial::RotateNeedle )
|
||||
drawNeedle( &p );
|
||||
}
|
||||
|
||||
painter.drawPixmap( r.topLeft(), d_data->pixmapCache );
|
||||
|
||||
if ( d_data->mode == QwtDial::RotateNeedle )
|
||||
drawNeedle( &painter );
|
||||
|
||||
if ( hasFocus() )
|
||||
drawFocusIndicator( &painter );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the focus indicator
|
||||
\param painter Painter
|
||||
*/
|
||||
void QwtDial::drawFocusIndicator( QPainter *painter ) const
|
||||
{
|
||||
QwtPainter::drawFocusRect( painter, this, boundingRect() );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the frame around the dial
|
||||
|
||||
\param painter Painter
|
||||
\sa lineWidth(), frameShadow()
|
||||
*/
|
||||
void QwtDial::drawFrame( QPainter *painter )
|
||||
{
|
||||
QwtPainter::drawRoundFrame( painter, boundingRect(),
|
||||
palette(), lineWidth(), d_data->frameShadow );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Draw the contents inside the frame
|
||||
|
||||
QPalette::Window is the background color outside of the frame.
|
||||
QPalette::Base is the background color inside the frame.
|
||||
QPalette::WindowText is the background color inside the scale.
|
||||
|
||||
\param painter Painter
|
||||
|
||||
\sa boundingRect(), innerRect(),
|
||||
scaleInnerRect(), QWidget::setPalette()
|
||||
*/
|
||||
void QwtDial::drawContents( QPainter *painter ) const
|
||||
{
|
||||
if ( testAttribute( Qt::WA_NoSystemBackground ) ||
|
||||
palette().brush( QPalette::Base ) !=
|
||||
palette().brush( QPalette::Window ) )
|
||||
{
|
||||
const QRectF br = boundingRect();
|
||||
|
||||
painter->save();
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( palette().brush( QPalette::Base ) );
|
||||
painter->drawEllipse( br );
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
const QRectF insideScaleRect = scaleInnerRect();
|
||||
if ( palette().brush( QPalette::WindowText ) !=
|
||||
palette().brush( QPalette::Base ) )
|
||||
{
|
||||
painter->save();
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( palette().brush( QPalette::WindowText ) );
|
||||
painter->drawEllipse( insideScaleRect );
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
const QPointF center = insideScaleRect.center();
|
||||
const double radius = 0.5 * insideScaleRect.width();
|
||||
|
||||
painter->save();
|
||||
drawScale( painter, center, radius );
|
||||
painter->restore();
|
||||
|
||||
painter->save();
|
||||
drawScaleContents( painter, center, radius );
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the needle
|
||||
|
||||
\param painter Painter
|
||||
\param center Center of the dial
|
||||
\param radius Length for the needle
|
||||
\param direction Direction of the needle in degrees, counter clockwise
|
||||
\param colorGroup ColorGroup
|
||||
*/
|
||||
void QwtDial::drawNeedle( QPainter *painter, const QPointF ¢er,
|
||||
double radius, double direction, QPalette::ColorGroup colorGroup ) const
|
||||
{
|
||||
if ( d_data->needle )
|
||||
{
|
||||
direction = 360.0 - direction; // counter clockwise
|
||||
d_data->needle->draw( painter, center, radius, direction, colorGroup );
|
||||
}
|
||||
}
|
||||
|
||||
void QwtDial::drawNeedle( QPainter *painter ) const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return;
|
||||
|
||||
QPalette::ColorGroup colorGroup;
|
||||
if ( isEnabled() )
|
||||
colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
|
||||
else
|
||||
colorGroup = QPalette::Disabled;
|
||||
|
||||
const QRectF sr = scaleInnerRect();
|
||||
|
||||
painter->save();
|
||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||
drawNeedle( painter, sr.center(), 0.5 * sr.width(),
|
||||
scaleMap().transform( value() ) + 270.0, colorGroup );
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the scale
|
||||
|
||||
\param painter Painter
|
||||
\param center Center of the dial
|
||||
\param radius Radius of the scale
|
||||
*/
|
||||
void QwtDial::drawScale( QPainter *painter,
|
||||
const QPointF ¢er, double radius ) const
|
||||
{
|
||||
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
|
||||
if ( sd == NULL )
|
||||
return;
|
||||
|
||||
sd->setRadius( radius );
|
||||
sd->moveCenter( center );
|
||||
|
||||
QPalette pal = palette();
|
||||
|
||||
const QColor textColor = pal.color( QPalette::Text );
|
||||
pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
|
||||
|
||||
painter->setFont( font() );
|
||||
painter->setPen( QPen( textColor, sd->penWidth() ) );
|
||||
|
||||
painter->setBrush( Qt::red );
|
||||
sd->draw( painter, pal );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the contents inside the scale
|
||||
|
||||
Paints nothing.
|
||||
|
||||
\param painter Painter
|
||||
\param center Center of the contents circle
|
||||
\param radius Radius of the contents circle
|
||||
*/
|
||||
void QwtDial::drawScaleContents( QPainter *painter,
|
||||
const QPointF ¢er, double radius ) const
|
||||
{
|
||||
Q_UNUSED(painter);
|
||||
Q_UNUSED(center);
|
||||
Q_UNUSED(radius);
|
||||
}
|
||||
|
||||
/*!
|
||||
Set a needle for the dial
|
||||
|
||||
\param needle Needle
|
||||
|
||||
\warning The needle will be deleted, when a different needle is
|
||||
set or in ~QwtDial()
|
||||
*/
|
||||
void QwtDial::setNeedle( QwtDialNeedle *needle )
|
||||
{
|
||||
if ( needle != d_data->needle )
|
||||
{
|
||||
if ( d_data->needle )
|
||||
delete d_data->needle;
|
||||
|
||||
d_data->needle = needle;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return needle
|
||||
\sa setNeedle()
|
||||
*/
|
||||
const QwtDialNeedle *QwtDial::needle() const
|
||||
{
|
||||
return d_data->needle;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return needle
|
||||
\sa setNeedle()
|
||||
*/
|
||||
QwtDialNeedle *QwtDial::needle()
|
||||
{
|
||||
return d_data->needle;
|
||||
}
|
||||
|
||||
//! \return the scale draw
|
||||
QwtRoundScaleDraw *QwtDial::scaleDraw()
|
||||
{
|
||||
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||
}
|
||||
|
||||
//! \return the scale draw
|
||||
const QwtRoundScaleDraw *QwtDial::scaleDraw() const
|
||||
{
|
||||
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set an individual scale draw
|
||||
|
||||
The motivation for setting a scale draw is often
|
||||
to overload QwtRoundScaleDraw::label() to return
|
||||
individual tick labels.
|
||||
|
||||
\param scaleDraw Scale draw
|
||||
\warning The previous scale draw is deleted
|
||||
*/
|
||||
void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
|
||||
{
|
||||
setAbstractScaleDraw( scaleDraw );
|
||||
sliderChange();
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the arc of the scale
|
||||
|
||||
\param minArc Lower limit
|
||||
\param maxArc Upper limit
|
||||
|
||||
\sa minScaleArc(), maxScaleArc()
|
||||
*/
|
||||
void QwtDial::setScaleArc( double minArc, double maxArc )
|
||||
{
|
||||
if ( minArc != 360.0 && minArc != -360.0 )
|
||||
minArc = ::fmod( minArc, 360.0 );
|
||||
if ( maxArc != 360.0 && maxArc != -360.0 )
|
||||
maxArc = ::fmod( maxArc, 360.0 );
|
||||
|
||||
double minScaleArc = qMin( minArc, maxArc );
|
||||
double maxScaleArc = qMax( minArc, maxArc );
|
||||
|
||||
if ( maxScaleArc - minScaleArc > 360.0 )
|
||||
maxScaleArc = minScaleArc + 360.0;
|
||||
|
||||
if ( ( minScaleArc != d_data->minScaleArc ) ||
|
||||
( maxScaleArc != d_data->maxScaleArc ) )
|
||||
{
|
||||
d_data->minScaleArc = minScaleArc;
|
||||
d_data->maxScaleArc = maxScaleArc;
|
||||
|
||||
invalidateCache();
|
||||
sliderChange();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the lower limit for the scale arc
|
||||
|
||||
\param min Lower limit of the scale arc
|
||||
\sa setScaleArc(), setMaxScaleArc()
|
||||
*/
|
||||
void QwtDial::setMinScaleArc( double min )
|
||||
{
|
||||
setScaleArc( min, d_data->maxScaleArc );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Lower limit of the scale arc
|
||||
\sa setScaleArc()
|
||||
*/
|
||||
double QwtDial::minScaleArc() const
|
||||
{
|
||||
return d_data->minScaleArc;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the upper limit for the scale arc
|
||||
|
||||
\param max Upper limit of the scale arc
|
||||
\sa setScaleArc(), setMinScaleArc()
|
||||
*/
|
||||
void QwtDial::setMaxScaleArc( double max )
|
||||
{
|
||||
setScaleArc( d_data->minScaleArc, max );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Upper limit of the scale arc
|
||||
\sa setScaleArc()
|
||||
*/
|
||||
double QwtDial::maxScaleArc() const
|
||||
{
|
||||
return d_data->maxScaleArc;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the origin
|
||||
|
||||
The origin is the angle where scale and needle is relative to.
|
||||
|
||||
\param origin New origin
|
||||
\sa origin()
|
||||
*/
|
||||
void QwtDial::setOrigin( double origin )
|
||||
{
|
||||
invalidateCache();
|
||||
|
||||
d_data->origin = origin;
|
||||
sliderChange();
|
||||
}
|
||||
|
||||
/*!
|
||||
The origin is the angle where scale and needle is relative to.
|
||||
|
||||
\return Origin of the dial
|
||||
\sa setOrigin()
|
||||
*/
|
||||
double QwtDial::origin() const
|
||||
{
|
||||
return d_data->origin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Size hint
|
||||
\sa minimumSizeHint()
|
||||
*/
|
||||
QSize QwtDial::sizeHint() const
|
||||
{
|
||||
int sh = 0;
|
||||
if ( scaleDraw() )
|
||||
sh = qCeil( scaleDraw()->extent( font() ) );
|
||||
|
||||
const int d = 6 * sh + 2 * lineWidth();
|
||||
|
||||
QSize hint( d, d );
|
||||
if ( !isReadOnly() )
|
||||
hint = hint.expandedTo( QApplication::globalStrut() );
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Minimum size hint
|
||||
\sa sizeHint()
|
||||
*/
|
||||
QSize QwtDial::minimumSizeHint() const
|
||||
{
|
||||
int sh = 0;
|
||||
if ( scaleDraw() )
|
||||
sh = qCeil( scaleDraw()->extent( font() ) );
|
||||
|
||||
const int d = 3 * sh + 2 * lineWidth();
|
||||
|
||||
return QSize( d, d );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Determine what to do when the user presses a mouse button.
|
||||
|
||||
\param pos Mouse position
|
||||
|
||||
\retval True, when the inner circle contains pos
|
||||
\sa scrolledTo()
|
||||
*/
|
||||
bool QwtDial::isScrollPosition( const QPoint &pos ) const
|
||||
{
|
||||
const QRegion region( innerRect(), QRegion::Ellipse );
|
||||
if ( region.contains( pos ) && ( pos != innerRect().center() ) )
|
||||
{
|
||||
double angle = QLineF( rect().center(), pos ).angle();
|
||||
if ( d_data->mode == QwtDial::RotateScale )
|
||||
angle = 360.0 - angle;
|
||||
|
||||
double valueAngle =
|
||||
qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
|
||||
|
||||
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
|
||||
d_data->arcOffset = scaleMap().p1();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Determine the value for a new position of the
|
||||
slider handle.
|
||||
|
||||
\param pos Mouse position
|
||||
|
||||
\return Value for the mouse position
|
||||
\sa isScrollPosition()
|
||||
*/
|
||||
double QwtDial::scrolledTo( const QPoint &pos ) const
|
||||
{
|
||||
double angle = QLineF( rect().center(), pos ).angle();
|
||||
if ( d_data->mode == QwtDial::RotateScale )
|
||||
{
|
||||
angle += scaleMap().p1() - d_data->arcOffset;
|
||||
angle = 360.0 - angle;
|
||||
}
|
||||
|
||||
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
|
||||
angle = qwtNormalizeDegrees( 90.0 - angle );
|
||||
|
||||
if ( scaleMap().pDist() >= 360.0 )
|
||||
{
|
||||
if ( angle < scaleMap().p1() )
|
||||
angle += 360.0;
|
||||
|
||||
if ( !wrapping() )
|
||||
{
|
||||
double boundedAngle = angle;
|
||||
|
||||
const double arc = angle - scaleMap().transform( value() );
|
||||
if ( qAbs( arc ) > 180.0 )
|
||||
{
|
||||
boundedAngle = ( arc > 0 )
|
||||
? scaleMap().p1() : scaleMap().p2();
|
||||
}
|
||||
|
||||
d_data->mouseOffset += ( boundedAngle - angle );
|
||||
|
||||
angle = boundedAngle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const double boundedAngle =
|
||||
qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
|
||||
|
||||
if ( !wrapping() )
|
||||
d_data->mouseOffset += ( boundedAngle - angle );
|
||||
|
||||
angle = boundedAngle;
|
||||
}
|
||||
|
||||
return scaleMap().invTransform( angle );
|
||||
}
|
||||
|
||||
/*!
|
||||
Change Event handler
|
||||
\param event Change event
|
||||
|
||||
Invalidates internal paint caches if necessary
|
||||
*/
|
||||
void QwtDial::changeEvent( QEvent *event )
|
||||
{
|
||||
switch( event->type() )
|
||||
{
|
||||
case QEvent::EnabledChange:
|
||||
case QEvent::FontChange:
|
||||
case QEvent::StyleChange:
|
||||
case QEvent::PaletteChange:
|
||||
case QEvent::LanguageChange:
|
||||
case QEvent::LocaleChange:
|
||||
{
|
||||
invalidateCache();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QwtAbstractSlider::changeEvent( event );
|
||||
}
|
||||
|
||||
/*!
|
||||
Wheel Event handler
|
||||
\param event Wheel event
|
||||
*/
|
||||
void QwtDial::wheelEvent( QWheelEvent *event )
|
||||
{
|
||||
const QRegion region( innerRect(), QRegion::Ellipse );
|
||||
if ( region.contains( event->pos() ) )
|
||||
QwtAbstractSlider::wheelEvent( event );
|
||||
}
|
||||
|
||||
void QwtDial::setAngleRange( double angle, double span )
|
||||
{
|
||||
QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
|
||||
if ( sd )
|
||||
{
|
||||
angle = qwtNormalizeDegrees( angle - 270.0 );
|
||||
sd->setAngleRange( angle, angle + span );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Invalidate the internal caches and call
|
||||
QwtAbstractSlider::scaleChange()
|
||||
*/
|
||||
void QwtDial::scaleChange()
|
||||
{
|
||||
invalidateCache();
|
||||
QwtAbstractSlider::scaleChange();
|
||||
}
|
||||
|
||||
void QwtDial::sliderChange()
|
||||
{
|
||||
setAngleRange( d_data->origin + d_data->minScaleArc,
|
||||
d_data->maxScaleArc - d_data->minScaleArc );
|
||||
|
||||
if ( mode() == RotateScale )
|
||||
{
|
||||
const double arc = scaleMap().transform( value() ) - scaleMap().p1();
|
||||
setAngleRange( d_data->origin - arc,
|
||||
d_data->maxScaleArc - d_data->minScaleArc );
|
||||
}
|
||||
|
||||
QwtAbstractSlider::sliderChange();
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_DIAL_H
|
||||
#define QWT_DIAL_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_abstract_slider.h"
|
||||
#include "qwt_abstract_scale_draw.h"
|
||||
#include <qframe.h>
|
||||
#include <qpalette.h>
|
||||
|
||||
class QwtDialNeedle;
|
||||
class QwtRoundScaleDraw;
|
||||
|
||||
/*!
|
||||
\brief QwtDial class provides a rounded range control.
|
||||
|
||||
QwtDial is intended as base class for dial widgets like
|
||||
speedometers, compass widgets, clocks ...
|
||||
|
||||
\image html dials2.png
|
||||
|
||||
A dial contains a scale and a needle indicating the current value
|
||||
of the dial. Depending on Mode one of them is fixed and the
|
||||
other is rotating. If not isReadOnly() the
|
||||
dial can be rotated by dragging the mouse or using keyboard inputs
|
||||
(see QwtAbstractSlider::keyPressEvent()). A dial might be wrapping, what means
|
||||
a rotation below/above one limit continues on the other limit (f.e compass).
|
||||
The scale might cover any arc of the dial, its values are related to
|
||||
the origin() of the dial.
|
||||
|
||||
Often dials have to be updated very often according to values from external
|
||||
devices. For these high refresh rates QwtDial caches as much as possible.
|
||||
For derived classes it might be necessary to clear these caches manually
|
||||
according to attribute changes using invalidateCache().
|
||||
|
||||
\sa QwtCompass, QwtAnalogClock, QwtDialNeedle
|
||||
\note The controls and dials examples shows different types of dials.
|
||||
\note QDial is more similar to QwtKnob than to QwtDial
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtDial: public QwtAbstractSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS( Shadow Mode Direction )
|
||||
|
||||
Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth )
|
||||
Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
|
||||
Q_PROPERTY( Mode mode READ mode WRITE setMode )
|
||||
Q_PROPERTY( double origin READ origin WRITE setOrigin )
|
||||
Q_PROPERTY( double minScaleArc READ minScaleArc WRITE setMinScaleArc )
|
||||
Q_PROPERTY( double maxScaleArc READ maxScaleArc WRITE setMaxScaleArc )
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
\brief Frame shadow
|
||||
|
||||
Unfortunately it is not possible to use QFrame::Shadow
|
||||
as a property of a widget that is not derived from QFrame.
|
||||
The following enum is made for the designer only. It is safe
|
||||
to use QFrame::Shadow instead.
|
||||
*/
|
||||
enum Shadow
|
||||
{
|
||||
//! QFrame::Plain
|
||||
Plain = QFrame::Plain,
|
||||
|
||||
//! QFrame::Raised
|
||||
Raised = QFrame::Raised,
|
||||
|
||||
//! QFrame::Sunken
|
||||
Sunken = QFrame::Sunken
|
||||
};
|
||||
|
||||
//! Mode controlling whether the needle or the scale is rotating
|
||||
enum Mode
|
||||
{
|
||||
//! The needle is rotating
|
||||
RotateNeedle,
|
||||
|
||||
//! The needle is fixed, the scales are rotating
|
||||
RotateScale
|
||||
};
|
||||
|
||||
explicit QwtDial( QWidget *parent = NULL );
|
||||
virtual ~QwtDial();
|
||||
|
||||
void setFrameShadow( Shadow );
|
||||
Shadow frameShadow() const;
|
||||
|
||||
void setLineWidth( int );
|
||||
int lineWidth() const;
|
||||
|
||||
void setMode( Mode );
|
||||
Mode mode() const;
|
||||
|
||||
void setScaleArc( double min, double max );
|
||||
|
||||
void setMinScaleArc( double min );
|
||||
double minScaleArc() const;
|
||||
|
||||
void setMaxScaleArc( double min );
|
||||
double maxScaleArc() const;
|
||||
|
||||
virtual void setOrigin( double );
|
||||
double origin() const;
|
||||
|
||||
void setNeedle( QwtDialNeedle * );
|
||||
const QwtDialNeedle *needle() const;
|
||||
QwtDialNeedle *needle();
|
||||
|
||||
QRect boundingRect() const;
|
||||
QRect innerRect() const;
|
||||
|
||||
virtual QRect scaleInnerRect() const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
|
||||
void setScaleDraw( QwtRoundScaleDraw * );
|
||||
|
||||
QwtRoundScaleDraw *scaleDraw();
|
||||
const QwtRoundScaleDraw *scaleDraw() const;
|
||||
|
||||
protected:
|
||||
virtual void wheelEvent( QWheelEvent * );
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
virtual void changeEvent( QEvent * );
|
||||
|
||||
virtual void drawFrame( QPainter *p );
|
||||
virtual void drawContents( QPainter * ) const;
|
||||
virtual void drawFocusIndicator( QPainter * ) const;
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
virtual void drawScale( QPainter *,
|
||||
const QPointF ¢er, double radius ) const;
|
||||
|
||||
virtual void drawScaleContents( QPainter *painter,
|
||||
const QPointF ¢er, double radius ) const;
|
||||
|
||||
virtual void drawNeedle( QPainter *, const QPointF &,
|
||||
double radius, double direction, QPalette::ColorGroup ) const;
|
||||
|
||||
virtual double scrolledTo( const QPoint & ) const;
|
||||
virtual bool isScrollPosition( const QPoint & ) const;
|
||||
|
||||
virtual void sliderChange();
|
||||
virtual void scaleChange();
|
||||
|
||||
private:
|
||||
void setAngleRange( double angle, double span );
|
||||
void drawNeedle( QPainter * ) const;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,440 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_dial_needle.h"
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qapplication.h>
|
||||
#include <qpainter.h>
|
||||
|
||||
#if QT_VERSION < 0x040601
|
||||
#define qFastSin(x) qSin(x)
|
||||
#define qFastCos(x) qCos(x)
|
||||
#endif
|
||||
|
||||
static void qwtDrawStyle1Needle( QPainter *painter,
|
||||
const QPalette &palette, QPalette::ColorGroup colorGroup,
|
||||
double length )
|
||||
{
|
||||
const double r[] = { 0.4, 0.3, 1, 0.8, 1, 0.3, 0.4 };
|
||||
const double a[] = { -45, -20, -15, 0, 15, 20, 45 };
|
||||
|
||||
QPainterPath path;
|
||||
for ( int i = 0; i < 7; i++ )
|
||||
{
|
||||
const double angle = a[i] / 180.0 * M_PI;
|
||||
const double radius = r[i] * length;
|
||||
|
||||
const double x = radius * qFastCos( angle );
|
||||
const double y = radius * qFastSin( angle );
|
||||
|
||||
path.lineTo( x, -y );
|
||||
}
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
|
||||
painter->drawPath( path );
|
||||
}
|
||||
|
||||
static void qwtDrawStyle2Needle( QPainter *painter,
|
||||
const QPalette &palette, QPalette::ColorGroup colorGroup, double length )
|
||||
{
|
||||
const double ratioX = 0.7;
|
||||
const double ratioY = 0.3;
|
||||
|
||||
QPainterPath path1;
|
||||
path1.lineTo( ratioX * length, 0.0 );
|
||||
path1.lineTo( length, ratioY * length );
|
||||
|
||||
QPainterPath path2;
|
||||
path2.lineTo( ratioX * length, 0.0 );
|
||||
path2.lineTo( length, -ratioY * length );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
|
||||
painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
|
||||
painter->drawPath( path1 );
|
||||
|
||||
painter->setBrush( palette.brush( colorGroup, QPalette::Dark ) );
|
||||
painter->drawPath( path2 );
|
||||
}
|
||||
|
||||
static void qwtDrawShadedPointer( QPainter *painter,
|
||||
const QColor &lightColor, const QColor &darkColor,
|
||||
double length, double width )
|
||||
{
|
||||
const double peak = qMax( length / 10.0, 5.0 );
|
||||
|
||||
const double knobWidth = width + 8;
|
||||
QRectF knobRect( 0, 0, knobWidth, knobWidth );
|
||||
knobRect.moveCenter( QPointF(0, 0) );
|
||||
|
||||
QPainterPath path1;
|
||||
path1.lineTo( 0.0, 0.5 * width );
|
||||
path1.lineTo( length - peak, 0.5 * width );
|
||||
path1.lineTo( length, 0.0 );
|
||||
path1.lineTo( 0.0, 0.0 );
|
||||
|
||||
QPainterPath arcPath1;
|
||||
arcPath1.arcTo( knobRect, 0.0, -90.0 );
|
||||
|
||||
path1 = path1.united( arcPath1 );
|
||||
|
||||
QPainterPath path2;
|
||||
path2.lineTo( 0.0, -0.5 * width );
|
||||
path2.lineTo( length - peak, -0.5 * width );
|
||||
path2.lineTo( length, 0.0 );
|
||||
path2.lineTo( 0.0, 0.0 );
|
||||
|
||||
QPainterPath arcPath2;
|
||||
arcPath2.arcTo( knobRect, 0.0, 90.0 );
|
||||
|
||||
path2 = path2.united( arcPath2 );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
|
||||
painter->setBrush( lightColor );
|
||||
painter->drawPath( path1 );
|
||||
|
||||
painter->setBrush( darkColor );
|
||||
painter->drawPath( path2 );
|
||||
}
|
||||
|
||||
static void qwtDrawArrowNeedle( QPainter *painter,
|
||||
const QPalette &palette, QPalette::ColorGroup colorGroup,
|
||||
double length, double width )
|
||||
{
|
||||
if ( width <= 0 )
|
||||
width = qMax( length * 0.06, 9.0 );
|
||||
|
||||
const double peak = qMax( 2.0, 0.4 * width );
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo( 0.0, 0.5 * width );
|
||||
path.lineTo( length - peak, 0.3 * width );
|
||||
path.lineTo( length, 0.0 );
|
||||
path.lineTo( length - peak, -0.3 * width );
|
||||
path.lineTo( 0.0, -0.5 * width );
|
||||
|
||||
QRectF br = path.boundingRect();
|
||||
|
||||
QPalette pal( palette.color( QPalette::Mid ) );
|
||||
QColor c1 = pal.color( QPalette::Light );
|
||||
QColor c2 = pal.color( QPalette::Dark );
|
||||
|
||||
QLinearGradient gradient( br.topLeft(), br.bottomLeft() );
|
||||
gradient.setColorAt( 0.0, c1 );
|
||||
gradient.setColorAt( 0.5, c1 );
|
||||
gradient.setColorAt( 0.5001, c2 );
|
||||
gradient.setColorAt( 1.0, c2 );
|
||||
|
||||
QPen pen( gradient, 1 );
|
||||
pen.setJoinStyle( Qt::MiterJoin );
|
||||
|
||||
painter->setPen( pen );
|
||||
painter->setBrush( palette.brush( colorGroup, QPalette::Mid ) );
|
||||
|
||||
painter->drawPath( path );
|
||||
}
|
||||
|
||||
static void qwtDrawTriangleNeedle( QPainter *painter,
|
||||
const QPalette &palette, QPalette::ColorGroup colorGroup,
|
||||
double length )
|
||||
{
|
||||
const double width = qRound( length / 3.0 );
|
||||
|
||||
QPainterPath path[4];
|
||||
|
||||
path[0].lineTo( length, 0.0 );
|
||||
path[0].lineTo( 0.0, width / 2 );
|
||||
|
||||
path[1].lineTo( length, 0.0 );
|
||||
path[1].lineTo( 0.0, -width / 2 );
|
||||
|
||||
path[2].lineTo( -length, 0.0 );
|
||||
path[2].lineTo( 0.0, width / 2 );
|
||||
|
||||
path[3].lineTo( -length, 0.0 );
|
||||
path[3].lineTo( 0.0, -width / 2 );
|
||||
|
||||
|
||||
const int colorOffset = 10;
|
||||
const QColor darkColor = palette.color( colorGroup, QPalette::Dark );
|
||||
const QColor lightColor = palette.color( colorGroup, QPalette::Light );
|
||||
|
||||
QColor color[4];
|
||||
color[0] = darkColor.light( 100 + colorOffset );
|
||||
color[1] = darkColor.dark( 100 + colorOffset );
|
||||
color[2] = lightColor.light( 100 + colorOffset );
|
||||
color[3] = lightColor.dark( 100 + colorOffset );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
painter->setBrush( color[i] );
|
||||
painter->drawPath( path[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtDialNeedle::QwtDialNeedle():
|
||||
d_palette( QApplication::palette() )
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtDialNeedle::~QwtDialNeedle()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the palette for the needle.
|
||||
|
||||
\param palette New Palette
|
||||
*/
|
||||
void QwtDialNeedle::setPalette( const QPalette &palette )
|
||||
{
|
||||
d_palette = palette;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the palette of the needle.
|
||||
*/
|
||||
const QPalette &QwtDialNeedle::palette() const
|
||||
{
|
||||
return d_palette;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the needle
|
||||
|
||||
\param painter Painter
|
||||
\param center Center of the dial, start position for the needle
|
||||
\param length Length of the needle
|
||||
\param direction Direction of the needle, in degrees counter clockwise
|
||||
\param colorGroup Color group, used for painting
|
||||
*/
|
||||
void QwtDialNeedle::draw( QPainter *painter,
|
||||
const QPointF ¢er, double length, double direction,
|
||||
QPalette::ColorGroup colorGroup ) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
painter->translate( center );
|
||||
painter->rotate( -direction );
|
||||
|
||||
drawNeedle( painter, length, colorGroup );
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
//! Draw the knob
|
||||
void QwtDialNeedle::drawKnob( QPainter *painter,
|
||||
double width, const QBrush &brush, bool sunken ) const
|
||||
{
|
||||
QPalette palette( brush.color() );
|
||||
|
||||
QColor c1 = palette.color( QPalette::Light );
|
||||
QColor c2 = palette.color( QPalette::Dark );
|
||||
|
||||
if ( sunken )
|
||||
qSwap( c1, c2 );
|
||||
|
||||
QRectF rect( 0.0, 0.0, width, width );
|
||||
rect.moveCenter( painter->combinedTransform().map( QPointF() ) );
|
||||
|
||||
QLinearGradient gradient( rect.topLeft(), rect.bottomRight() );
|
||||
gradient.setColorAt( 0.0, c1 );
|
||||
gradient.setColorAt( 0.3, c1 );
|
||||
gradient.setColorAt( 0.7, c2 );
|
||||
gradient.setColorAt( 1.0, c2 );
|
||||
|
||||
painter->save();
|
||||
|
||||
painter->resetTransform();
|
||||
|
||||
painter->setPen( QPen( gradient, 1 ) );
|
||||
painter->setBrush( brush );
|
||||
painter->drawEllipse( rect );
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\param style Style
|
||||
\param hasKnob With/Without knob
|
||||
\param mid Middle color
|
||||
\param base Base color
|
||||
*/
|
||||
QwtDialSimpleNeedle::QwtDialSimpleNeedle( Style style, bool hasKnob,
|
||||
const QColor &mid, const QColor &base ):
|
||||
d_style( style ),
|
||||
d_hasKnob( hasKnob ),
|
||||
d_width( -1 )
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor( QPalette::Mid, mid );
|
||||
palette.setColor( QPalette::Base, base );
|
||||
|
||||
setPalette( palette );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the width of the needle
|
||||
\param width Width
|
||||
\sa width()
|
||||
*/
|
||||
void QwtDialSimpleNeedle::setWidth( double width )
|
||||
{
|
||||
d_width = width;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the width of the needle
|
||||
\sa setWidth()
|
||||
*/
|
||||
double QwtDialSimpleNeedle::width() const
|
||||
{
|
||||
return d_width;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the needle
|
||||
|
||||
\param painter Painter
|
||||
\param length Length of the needle
|
||||
\param colorGroup Color group, used for painting
|
||||
*/
|
||||
void QwtDialSimpleNeedle::drawNeedle( QPainter *painter,
|
||||
double length, QPalette::ColorGroup colorGroup ) const
|
||||
{
|
||||
double knobWidth = 0.0;
|
||||
double width = d_width;
|
||||
|
||||
if ( d_style == Arrow )
|
||||
{
|
||||
if ( width <= 0.0 )
|
||||
width = qMax(length * 0.06, 6.0);
|
||||
|
||||
qwtDrawArrowNeedle( painter,
|
||||
palette(), colorGroup, length, width );
|
||||
|
||||
knobWidth = qMin( width * 2.0, 0.2 * length );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( width <= 0.0 )
|
||||
width = 5.0;
|
||||
|
||||
QPen pen ( palette().brush( colorGroup, QPalette::Mid ), width );
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
painter->setPen( pen );
|
||||
painter->drawLine( QPointF( 0.0, 0.0 ), QPointF( length, 0.0 ) );
|
||||
|
||||
knobWidth = qMax( width * 3.0, 5.0 );
|
||||
}
|
||||
|
||||
if ( d_hasKnob && knobWidth > 0.0 )
|
||||
{
|
||||
drawKnob( painter, knobWidth,
|
||||
palette().brush( colorGroup, QPalette::Base ), false );
|
||||
}
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtCompassMagnetNeedle::QwtCompassMagnetNeedle( Style style,
|
||||
const QColor &light, const QColor &dark ):
|
||||
d_style( style )
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor( QPalette::Light, light );
|
||||
palette.setColor( QPalette::Dark, dark );
|
||||
palette.setColor( QPalette::Base, Qt::gray );
|
||||
|
||||
setPalette( palette );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the needle
|
||||
|
||||
\param painter Painter
|
||||
\param length Length of the needle
|
||||
\param colorGroup Color group, used for painting
|
||||
*/
|
||||
void QwtCompassMagnetNeedle::drawNeedle( QPainter *painter,
|
||||
double length, QPalette::ColorGroup colorGroup ) const
|
||||
{
|
||||
if ( d_style == ThinStyle )
|
||||
{
|
||||
const double width = qMax( length / 6.0, 3.0 );
|
||||
|
||||
const int colorOffset = 10;
|
||||
|
||||
const QColor light = palette().color( colorGroup, QPalette::Light );
|
||||
const QColor dark = palette().color( colorGroup, QPalette::Dark );
|
||||
|
||||
qwtDrawShadedPointer( painter,
|
||||
dark.light( 100 + colorOffset ),
|
||||
dark.dark( 100 + colorOffset ),
|
||||
length, width );
|
||||
|
||||
painter->rotate( 180.0 );
|
||||
|
||||
qwtDrawShadedPointer( painter,
|
||||
light.light( 100 + colorOffset ),
|
||||
light.dark( 100 + colorOffset ),
|
||||
length, width );
|
||||
|
||||
const QBrush baseBrush = palette().brush( colorGroup, QPalette::Base );
|
||||
drawKnob( painter, width, baseBrush, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
qwtDrawTriangleNeedle( painter, palette(), colorGroup, length );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\param style Arrow style
|
||||
\param light Light color
|
||||
\param dark Dark color
|
||||
*/
|
||||
QwtCompassWindArrow::QwtCompassWindArrow( Style style,
|
||||
const QColor &light, const QColor &dark ):
|
||||
d_style( style )
|
||||
{
|
||||
QPalette palette;
|
||||
palette.setColor( QPalette::Light, light );
|
||||
palette.setColor( QPalette::Dark, dark );
|
||||
|
||||
setPalette( palette );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the needle
|
||||
|
||||
\param painter Painter
|
||||
\param length Length of the needle
|
||||
\param colorGroup Color group, used for painting
|
||||
*/
|
||||
void QwtCompassWindArrow::drawNeedle( QPainter *painter,
|
||||
double length, QPalette::ColorGroup colorGroup ) const
|
||||
{
|
||||
if ( d_style == Style1 )
|
||||
qwtDrawStyle1Needle( painter, palette(), colorGroup, length );
|
||||
else
|
||||
qwtDrawStyle2Needle( painter, palette(), colorGroup, length );
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_DIAL_NEEDLE_H
|
||||
#define QWT_DIAL_NEEDLE_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpalette.h>
|
||||
|
||||
class QPainter;
|
||||
class QPoint;
|
||||
|
||||
/*!
|
||||
\brief Base class for needles that can be used in a QwtDial.
|
||||
|
||||
QwtDialNeedle is a pointer that indicates a value by pointing
|
||||
to a specific direction.
|
||||
|
||||
\sa QwtDial, QwtCompass
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtDialNeedle
|
||||
{
|
||||
public:
|
||||
QwtDialNeedle();
|
||||
virtual ~QwtDialNeedle();
|
||||
|
||||
virtual void setPalette( const QPalette & );
|
||||
const QPalette &palette() const;
|
||||
|
||||
virtual void draw( QPainter *painter, const QPointF ¢er,
|
||||
double length, double direction,
|
||||
QPalette::ColorGroup = QPalette::Active ) const;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
\brief Draw the needle
|
||||
|
||||
The origin of the needle is at position (0.0, 0.0 )
|
||||
pointing in direction 0.0 ( = east ).
|
||||
|
||||
The painter is already initialized with translation and
|
||||
rotation.
|
||||
|
||||
\param painter Painter
|
||||
\param length Length of the needle
|
||||
\param colorGroup Color group, used for painting
|
||||
|
||||
\sa setPalette(), palette()
|
||||
*/
|
||||
virtual void drawNeedle( QPainter *painter,
|
||||
double length, QPalette::ColorGroup colorGroup ) const = 0;
|
||||
|
||||
virtual void drawKnob( QPainter *, double width,
|
||||
const QBrush &, bool sunken ) const;
|
||||
|
||||
private:
|
||||
QPalette d_palette;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A needle for dial widgets
|
||||
|
||||
The following colors are used:
|
||||
|
||||
- QPalette::Mid\n
|
||||
Pointer
|
||||
- QPalette::Base\n
|
||||
Knob
|
||||
|
||||
\sa QwtDial, QwtCompass
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtDialSimpleNeedle: public QwtDialNeedle
|
||||
{
|
||||
public:
|
||||
//! Style of the needle
|
||||
enum Style
|
||||
{
|
||||
//! Arrow
|
||||
Arrow,
|
||||
|
||||
//! A straight line from the center
|
||||
Ray
|
||||
};
|
||||
|
||||
QwtDialSimpleNeedle( Style, bool hasKnob = true,
|
||||
const QColor &mid = Qt::gray, const QColor &base = Qt::darkGray );
|
||||
|
||||
void setWidth( double width );
|
||||
double width() const;
|
||||
|
||||
protected:
|
||||
virtual void drawNeedle( QPainter *, double length,
|
||||
QPalette::ColorGroup ) const;
|
||||
|
||||
private:
|
||||
Style d_style;
|
||||
bool d_hasKnob;
|
||||
double d_width;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A magnet needle for compass widgets
|
||||
|
||||
A magnet needle points to two opposite directions indicating
|
||||
north and south.
|
||||
|
||||
The following colors are used:
|
||||
- QPalette::Light\n
|
||||
Used for pointing south
|
||||
- QPalette::Dark\n
|
||||
Used for pointing north
|
||||
- QPalette::Base\n
|
||||
Knob (ThinStyle only)
|
||||
|
||||
\sa QwtDial, QwtCompass
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtCompassMagnetNeedle: public QwtDialNeedle
|
||||
{
|
||||
public:
|
||||
//! Style of the needle
|
||||
enum Style
|
||||
{
|
||||
//! A needle with a triangular shape
|
||||
TriangleStyle,
|
||||
|
||||
//! A thin needle
|
||||
ThinStyle
|
||||
};
|
||||
|
||||
QwtCompassMagnetNeedle( Style = TriangleStyle,
|
||||
const QColor &light = Qt::white, const QColor &dark = Qt::red );
|
||||
|
||||
protected:
|
||||
virtual void drawNeedle( QPainter *,
|
||||
double length, QPalette::ColorGroup ) const;
|
||||
|
||||
private:
|
||||
Style d_style;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief An indicator for the wind direction
|
||||
|
||||
QwtCompassWindArrow shows the direction where the wind comes from.
|
||||
|
||||
- QPalette::Light\n
|
||||
Used for Style1, or the light half of Style2
|
||||
- QPalette::Dark\n
|
||||
Used for the dark half of Style2
|
||||
|
||||
\sa QwtDial, QwtCompass
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtCompassWindArrow: public QwtDialNeedle
|
||||
{
|
||||
public:
|
||||
//! Style of the arrow
|
||||
enum Style
|
||||
{
|
||||
//! A needle pointing to the center
|
||||
Style1,
|
||||
|
||||
//! A needle pointing to the center
|
||||
Style2
|
||||
};
|
||||
|
||||
QwtCompassWindArrow( Style, const QColor &light = Qt::white,
|
||||
const QColor &dark = Qt::gray );
|
||||
|
||||
protected:
|
||||
virtual void drawNeedle( QPainter *,
|
||||
double length, QPalette::ColorGroup ) const;
|
||||
|
||||
private:
|
||||
Style d_style;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,591 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_dyngrid_layout.h"
|
||||
#include "qwt_math.h"
|
||||
#include <qvector.h>
|
||||
#include <qlist.h>
|
||||
|
||||
class QwtDynGridLayout::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
isDirty( true )
|
||||
{
|
||||
}
|
||||
|
||||
void updateLayoutCache();
|
||||
|
||||
mutable QList<QLayoutItem*> itemList;
|
||||
|
||||
uint maxColumns;
|
||||
uint numRows;
|
||||
uint numColumns;
|
||||
|
||||
Qt::Orientations expanding;
|
||||
|
||||
bool isDirty;
|
||||
QVector<QSize> itemSizeHints;
|
||||
};
|
||||
|
||||
void QwtDynGridLayout::PrivateData::updateLayoutCache()
|
||||
{
|
||||
itemSizeHints.resize( itemList.count() );
|
||||
|
||||
int index = 0;
|
||||
|
||||
for ( QList<QLayoutItem*>::iterator it = itemList.begin();
|
||||
it != itemList.end(); ++it, index++ )
|
||||
{
|
||||
itemSizeHints[ index ] = ( *it )->sizeHint();
|
||||
}
|
||||
|
||||
isDirty = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param parent Parent widget
|
||||
\param margin Margin
|
||||
\param spacing Spacing
|
||||
*/
|
||||
|
||||
QwtDynGridLayout::QwtDynGridLayout( QWidget *parent,
|
||||
int margin, int spacing ):
|
||||
QLayout( parent )
|
||||
{
|
||||
init();
|
||||
|
||||
setSpacing( spacing );
|
||||
setMargin( margin );
|
||||
}
|
||||
|
||||
/*!
|
||||
\param spacing Spacing
|
||||
*/
|
||||
|
||||
QwtDynGridLayout::QwtDynGridLayout( int spacing )
|
||||
{
|
||||
init();
|
||||
setSpacing( spacing );
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize the layout with default values.
|
||||
*/
|
||||
void QwtDynGridLayout::init()
|
||||
{
|
||||
d_data = new QwtDynGridLayout::PrivateData;
|
||||
d_data->maxColumns = d_data->numRows = d_data->numColumns = 0;
|
||||
d_data->expanding = 0;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
|
||||
QwtDynGridLayout::~QwtDynGridLayout()
|
||||
{
|
||||
for ( int i = 0; i < d_data->itemList.size(); i++ )
|
||||
delete d_data->itemList[i];
|
||||
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
//! Invalidate all internal caches
|
||||
void QwtDynGridLayout::invalidate()
|
||||
{
|
||||
d_data->isDirty = true;
|
||||
QLayout::invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
Limit the number of columns.
|
||||
\param maxColumns upper limit, 0 means unlimited
|
||||
\sa maxColumns()
|
||||
*/
|
||||
void QwtDynGridLayout::setMaxColumns( uint maxColumns )
|
||||
{
|
||||
d_data->maxColumns = maxColumns;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the upper limit for the number of columns.
|
||||
|
||||
0 means unlimited, what is the default.
|
||||
|
||||
\return Upper limit for the number of columns
|
||||
\sa setMaxColumns()
|
||||
*/
|
||||
uint QwtDynGridLayout::maxColumns() const
|
||||
{
|
||||
return d_data->maxColumns;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Add an item to the next free position.
|
||||
\param item Layout item
|
||||
*/
|
||||
void QwtDynGridLayout::addItem( QLayoutItem *item )
|
||||
{
|
||||
d_data->itemList.append( item );
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if this layout is empty.
|
||||
*/
|
||||
bool QwtDynGridLayout::isEmpty() const
|
||||
{
|
||||
return d_data->itemList.isEmpty();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return number of layout items
|
||||
*/
|
||||
uint QwtDynGridLayout::itemCount() const
|
||||
{
|
||||
return d_data->itemList.count();
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the item at a specific index
|
||||
|
||||
\param index Index
|
||||
\return Item at a specific index
|
||||
\sa takeAt()
|
||||
*/
|
||||
QLayoutItem *QwtDynGridLayout::itemAt( int index ) const
|
||||
{
|
||||
if ( index < 0 || index >= d_data->itemList.count() )
|
||||
return NULL;
|
||||
|
||||
return d_data->itemList.at( index );
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the item at a specific index and remove it from the layout
|
||||
|
||||
\param index Index
|
||||
\return Layout item, removed from the layout
|
||||
\sa itemAt()
|
||||
*/
|
||||
QLayoutItem *QwtDynGridLayout::takeAt( int index )
|
||||
{
|
||||
if ( index < 0 || index >= d_data->itemList.count() )
|
||||
return NULL;
|
||||
|
||||
d_data->isDirty = true;
|
||||
return d_data->itemList.takeAt( index );
|
||||
}
|
||||
|
||||
//! \return Number of items in the layout
|
||||
int QwtDynGridLayout::count() const
|
||||
{
|
||||
return d_data->itemList.count();
|
||||
}
|
||||
|
||||
/*!
|
||||
Set whether this layout can make use of more space than sizeHint().
|
||||
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
|
||||
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
|
||||
to grow in both dimensions. The default value is 0.
|
||||
|
||||
\param expanding Or'd orientations
|
||||
\sa expandingDirections()
|
||||
*/
|
||||
void QwtDynGridLayout::setExpandingDirections( Qt::Orientations expanding )
|
||||
{
|
||||
d_data->expanding = expanding;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns whether this layout can make use of more space than sizeHint().
|
||||
|
||||
A value of Qt::Vertical or Qt::Horizontal means that it wants to grow in only
|
||||
one dimension, while Qt::Vertical | Qt::Horizontal means that it wants
|
||||
to grow in both dimensions.
|
||||
|
||||
\return Orientations, where the layout expands
|
||||
\sa setExpandingDirections()
|
||||
*/
|
||||
Qt::Orientations QwtDynGridLayout::expandingDirections() const
|
||||
{
|
||||
return d_data->expanding;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reorganizes columns and rows and resizes managed items within
|
||||
a rectangle.
|
||||
|
||||
\param rect Layout geometry
|
||||
*/
|
||||
void QwtDynGridLayout::setGeometry( const QRect &rect )
|
||||
{
|
||||
QLayout::setGeometry( rect );
|
||||
|
||||
if ( isEmpty() )
|
||||
return;
|
||||
|
||||
d_data->numColumns = columnsForWidth( rect.width() );
|
||||
d_data->numRows = itemCount() / d_data->numColumns;
|
||||
if ( itemCount() % d_data->numColumns )
|
||||
d_data->numRows++;
|
||||
|
||||
QList<QRect> itemGeometries = layoutItems( rect, d_data->numColumns );
|
||||
|
||||
int index = 0;
|
||||
for ( QList<QLayoutItem*>::iterator it = d_data->itemList.begin();
|
||||
it != d_data->itemList.end(); ++it )
|
||||
{
|
||||
( *it )->setGeometry( itemGeometries[index] );
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Calculate the number of columns for a given width.
|
||||
|
||||
The calculation tries to use as many columns as possible
|
||||
( limited by maxColumns() )
|
||||
|
||||
\param width Available width for all columns
|
||||
\return Number of columns for a given width
|
||||
|
||||
\sa maxColumns(), setMaxColumns()
|
||||
*/
|
||||
uint QwtDynGridLayout::columnsForWidth( int width ) const
|
||||
{
|
||||
if ( isEmpty() )
|
||||
return 0;
|
||||
|
||||
uint maxColumns = itemCount();
|
||||
if ( d_data->maxColumns > 0 )
|
||||
maxColumns = qMin( d_data->maxColumns, maxColumns );
|
||||
|
||||
if ( maxRowWidth( maxColumns ) <= width )
|
||||
return maxColumns;
|
||||
|
||||
for ( uint numColumns = 2; numColumns <= maxColumns; numColumns++ )
|
||||
{
|
||||
const int rowWidth = maxRowWidth( numColumns );
|
||||
if ( rowWidth > width )
|
||||
return numColumns - 1;
|
||||
}
|
||||
|
||||
return 1; // At least 1 column
|
||||
}
|
||||
|
||||
/*!
|
||||
Calculate the width of a layout for a given number of
|
||||
columns.
|
||||
|
||||
\param numColumns Given number of columns
|
||||
\param itemWidth Array of the width hints for all items
|
||||
*/
|
||||
int QwtDynGridLayout::maxRowWidth( int numColumns ) const
|
||||
{
|
||||
int col;
|
||||
|
||||
QVector<int> colWidth( numColumns );
|
||||
for ( col = 0; col < numColumns; col++ )
|
||||
colWidth[col] = 0;
|
||||
|
||||
if ( d_data->isDirty )
|
||||
d_data->updateLayoutCache();
|
||||
|
||||
for ( int index = 0;
|
||||
index < d_data->itemSizeHints.count(); index++ )
|
||||
{
|
||||
col = index % numColumns;
|
||||
colWidth[col] = qMax( colWidth[col],
|
||||
d_data->itemSizeHints[int( index )].width() );
|
||||
}
|
||||
|
||||
int rowWidth = 2 * margin() + ( numColumns - 1 ) * spacing();
|
||||
for ( col = 0; col < numColumns; col++ )
|
||||
rowWidth += colWidth[col];
|
||||
|
||||
return rowWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the maximum width of all layout items
|
||||
*/
|
||||
int QwtDynGridLayout::maxItemWidth() const
|
||||
{
|
||||
if ( isEmpty() )
|
||||
return 0;
|
||||
|
||||
if ( d_data->isDirty )
|
||||
d_data->updateLayoutCache();
|
||||
|
||||
int w = 0;
|
||||
for ( int i = 0; i < d_data->itemSizeHints.count(); i++ )
|
||||
{
|
||||
const int itemW = d_data->itemSizeHints[i].width();
|
||||
if ( itemW > w )
|
||||
w = itemW;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*!
|
||||
Calculate the geometries of the layout items for a layout
|
||||
with numColumns columns and a given rectangle.
|
||||
|
||||
\param rect Rect where to place the items
|
||||
\param numColumns Number of columns
|
||||
\return item geometries
|
||||
*/
|
||||
|
||||
QList<QRect> QwtDynGridLayout::layoutItems( const QRect &rect,
|
||||
uint numColumns ) const
|
||||
{
|
||||
QList<QRect> itemGeometries;
|
||||
if ( numColumns == 0 || isEmpty() )
|
||||
return itemGeometries;
|
||||
|
||||
uint numRows = itemCount() / numColumns;
|
||||
if ( numColumns % itemCount() )
|
||||
numRows++;
|
||||
|
||||
if ( numRows == 0 )
|
||||
return itemGeometries;
|
||||
|
||||
QVector<int> rowHeight( numRows );
|
||||
QVector<int> colWidth( numColumns );
|
||||
|
||||
layoutGrid( numColumns, rowHeight, colWidth );
|
||||
|
||||
bool expandH, expandV;
|
||||
expandH = expandingDirections() & Qt::Horizontal;
|
||||
expandV = expandingDirections() & Qt::Vertical;
|
||||
|
||||
if ( expandH || expandV )
|
||||
stretchGrid( rect, numColumns, rowHeight, colWidth );
|
||||
|
||||
const int maxColumns = d_data->maxColumns;
|
||||
d_data->maxColumns = numColumns;
|
||||
const QRect alignedRect = alignmentRect( rect );
|
||||
d_data->maxColumns = maxColumns;
|
||||
|
||||
const int xOffset = expandH ? 0 : alignedRect.x();
|
||||
const int yOffset = expandV ? 0 : alignedRect.y();
|
||||
|
||||
QVector<int> colX( numColumns );
|
||||
QVector<int> rowY( numRows );
|
||||
|
||||
const int xySpace = spacing();
|
||||
|
||||
rowY[0] = yOffset + margin();
|
||||
for ( uint r = 1; r < numRows; r++ )
|
||||
rowY[r] = rowY[r-1] + rowHeight[r-1] + xySpace;
|
||||
|
||||
colX[0] = xOffset + margin();
|
||||
for ( uint c = 1; c < numColumns; c++ )
|
||||
colX[c] = colX[c-1] + colWidth[c-1] + xySpace;
|
||||
|
||||
const int itemCount = d_data->itemList.size();
|
||||
for ( int i = 0; i < itemCount; i++ )
|
||||
{
|
||||
const int row = i / numColumns;
|
||||
const int col = i % numColumns;
|
||||
|
||||
QRect itemGeometry( colX[col], rowY[row],
|
||||
colWidth[col], rowHeight[row] );
|
||||
itemGeometries.append( itemGeometry );
|
||||
}
|
||||
|
||||
return itemGeometries;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Calculate the dimensions for the columns and rows for a grid
|
||||
of numColumns columns.
|
||||
|
||||
\param numColumns Number of columns.
|
||||
\param rowHeight Array where to fill in the calculated row heights.
|
||||
\param colWidth Array where to fill in the calculated column widths.
|
||||
*/
|
||||
|
||||
void QwtDynGridLayout::layoutGrid( uint numColumns,
|
||||
QVector<int>& rowHeight, QVector<int>& colWidth ) const
|
||||
{
|
||||
if ( numColumns <= 0 )
|
||||
return;
|
||||
|
||||
if ( d_data->isDirty )
|
||||
d_data->updateLayoutCache();
|
||||
|
||||
for ( int index = 0; index < d_data->itemSizeHints.count(); index++ )
|
||||
{
|
||||
const int row = index / numColumns;
|
||||
const int col = index % numColumns;
|
||||
|
||||
const QSize &size = d_data->itemSizeHints[int( index )];
|
||||
|
||||
rowHeight[row] = ( col == 0 )
|
||||
? size.height() : qMax( rowHeight[row], size.height() );
|
||||
colWidth[col] = ( row == 0 )
|
||||
? size.width() : qMax( colWidth[col], size.width() );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true: QwtDynGridLayout implements heightForWidth().
|
||||
\sa heightForWidth()
|
||||
*/
|
||||
bool QwtDynGridLayout::hasHeightForWidth() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The preferred height for this layout, given a width.
|
||||
\sa hasHeightForWidth()
|
||||
*/
|
||||
int QwtDynGridLayout::heightForWidth( int width ) const
|
||||
{
|
||||
if ( isEmpty() )
|
||||
return 0;
|
||||
|
||||
const uint numColumns = columnsForWidth( width );
|
||||
uint numRows = itemCount() / numColumns;
|
||||
if ( itemCount() % numColumns )
|
||||
numRows++;
|
||||
|
||||
QVector<int> rowHeight( numRows );
|
||||
QVector<int> colWidth( numColumns );
|
||||
|
||||
layoutGrid( numColumns, rowHeight, colWidth );
|
||||
|
||||
int h = 2 * margin() + ( numRows - 1 ) * spacing();
|
||||
for ( uint row = 0; row < numRows; row++ )
|
||||
h += rowHeight[row];
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/*!
|
||||
Stretch columns in case of expanding() & QSizePolicy::Horizontal and
|
||||
rows in case of expanding() & QSizePolicy::Vertical to fill the entire
|
||||
rect. Rows and columns are stretched with the same factor.
|
||||
|
||||
\param rect Bounding rectangle
|
||||
\param numColumns Number of columns
|
||||
\param rowHeight Array to be filled with the calculated row heights
|
||||
\param colWidth Array to be filled with the calculated column widths
|
||||
|
||||
\sa setExpanding(), expanding()
|
||||
*/
|
||||
void QwtDynGridLayout::stretchGrid( const QRect &rect,
|
||||
uint numColumns, QVector<int>& rowHeight, QVector<int>& colWidth ) const
|
||||
{
|
||||
if ( numColumns == 0 || isEmpty() )
|
||||
return;
|
||||
|
||||
bool expandH, expandV;
|
||||
expandH = expandingDirections() & Qt::Horizontal;
|
||||
expandV = expandingDirections() & Qt::Vertical;
|
||||
|
||||
if ( expandH )
|
||||
{
|
||||
int xDelta = rect.width() - 2 * margin() - ( numColumns - 1 ) * spacing();
|
||||
for ( uint col = 0; col < numColumns; col++ )
|
||||
xDelta -= colWidth[col];
|
||||
|
||||
if ( xDelta > 0 )
|
||||
{
|
||||
for ( uint col = 0; col < numColumns; col++ )
|
||||
{
|
||||
const int space = xDelta / ( numColumns - col );
|
||||
colWidth[col] += space;
|
||||
xDelta -= space;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( expandV )
|
||||
{
|
||||
uint numRows = itemCount() / numColumns;
|
||||
if ( itemCount() % numColumns )
|
||||
numRows++;
|
||||
|
||||
int yDelta = rect.height() - 2 * margin() - ( numRows - 1 ) * spacing();
|
||||
for ( uint row = 0; row < numRows; row++ )
|
||||
yDelta -= rowHeight[row];
|
||||
|
||||
if ( yDelta > 0 )
|
||||
{
|
||||
for ( uint row = 0; row < numRows; row++ )
|
||||
{
|
||||
const int space = yDelta / ( numRows - row );
|
||||
rowHeight[row] += space;
|
||||
yDelta -= space;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the size hint. If maxColumns() > 0 it is the size for
|
||||
a grid with maxColumns() columns, otherwise it is the size for
|
||||
a grid with only one row.
|
||||
|
||||
\return Size hint
|
||||
\sa maxColumns(), setMaxColumns()
|
||||
*/
|
||||
QSize QwtDynGridLayout::sizeHint() const
|
||||
{
|
||||
if ( isEmpty() )
|
||||
return QSize();
|
||||
|
||||
uint numColumns = itemCount();
|
||||
if ( d_data->maxColumns > 0 )
|
||||
numColumns = qMin( d_data->maxColumns, numColumns );
|
||||
|
||||
uint numRows = itemCount() / numColumns;
|
||||
if ( itemCount() % numColumns )
|
||||
numRows++;
|
||||
|
||||
QVector<int> rowHeight( numRows );
|
||||
QVector<int> colWidth( numColumns );
|
||||
|
||||
layoutGrid( numColumns, rowHeight, colWidth );
|
||||
|
||||
int h = 2 * margin() + ( numRows - 1 ) * spacing();
|
||||
for ( uint row = 0; row < numRows; row++ )
|
||||
h += rowHeight[row];
|
||||
|
||||
int w = 2 * margin() + ( numColumns - 1 ) * spacing();
|
||||
for ( uint col = 0; col < numColumns; col++ )
|
||||
w += colWidth[col];
|
||||
|
||||
return QSize( w, h );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of rows of the current layout.
|
||||
\sa numColumns()
|
||||
\warning The number of rows might change whenever the geometry changes
|
||||
*/
|
||||
uint QwtDynGridLayout::numRows() const
|
||||
{
|
||||
return d_data->numRows;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of columns of the current layout.
|
||||
\sa numRows()
|
||||
\warning The number of columns might change whenever the geometry changes
|
||||
*/
|
||||
uint QwtDynGridLayout::numColumns() const
|
||||
{
|
||||
return d_data->numColumns;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_DYNGRID_LAYOUT_H
|
||||
#define QWT_DYNGRID_LAYOUT_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qlayout.h>
|
||||
#include <qsize.h>
|
||||
#include <qlist.h>
|
||||
|
||||
/*!
|
||||
\brief The QwtDynGridLayout class lays out widgets in a grid,
|
||||
adjusting the number of columns and rows to the current size.
|
||||
|
||||
QwtDynGridLayout takes the space it gets, divides it up into rows and
|
||||
columns, and puts each of the widgets it manages into the correct cell(s).
|
||||
It lays out as many number of columns as possible (limited by maxColumns()).
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtDynGridLayout : public QLayout
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QwtDynGridLayout( QWidget *, int margin = 0, int space = -1 );
|
||||
explicit QwtDynGridLayout( int space = -1 );
|
||||
|
||||
virtual ~QwtDynGridLayout();
|
||||
|
||||
virtual void invalidate();
|
||||
|
||||
void setMaxColumns( uint maxCols );
|
||||
uint maxColumns() const;
|
||||
|
||||
uint numRows () const;
|
||||
uint numColumns () const;
|
||||
|
||||
virtual void addItem( QLayoutItem * );
|
||||
|
||||
virtual QLayoutItem *itemAt( int index ) const;
|
||||
virtual QLayoutItem *takeAt( int index );
|
||||
virtual int count() const;
|
||||
|
||||
void setExpandingDirections( Qt::Orientations );
|
||||
virtual Qt::Orientations expandingDirections() const;
|
||||
QList<QRect> layoutItems( const QRect &, uint numCols ) const;
|
||||
|
||||
virtual int maxItemWidth() const;
|
||||
|
||||
virtual void setGeometry( const QRect &rect );
|
||||
|
||||
virtual bool hasHeightForWidth() const;
|
||||
virtual int heightForWidth( int ) const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
uint itemCount() const;
|
||||
|
||||
virtual uint columnsForWidth( int width ) const;
|
||||
|
||||
protected:
|
||||
|
||||
void layoutGrid( uint numCols,
|
||||
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
|
||||
void stretchGrid( const QRect &rect, uint numCols,
|
||||
QVector<int>& rowHeight, QVector<int>& colWidth ) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
int maxRowWidth( int numCols ) const;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,265 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_event_pattern.h"
|
||||
#include <qevent.h>
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\sa MousePatternCode, KeyPatternCode
|
||||
*/
|
||||
|
||||
QwtEventPattern::QwtEventPattern():
|
||||
d_mousePattern( MousePatternCount ),
|
||||
d_keyPattern( KeyPatternCount )
|
||||
{
|
||||
initKeyPattern();
|
||||
initMousePattern( 3 );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtEventPattern::~QwtEventPattern()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Set default mouse patterns, depending on the number of mouse buttons
|
||||
|
||||
\param numButtons Number of mouse buttons ( <= 3 )
|
||||
\sa MousePatternCode
|
||||
*/
|
||||
void QwtEventPattern::initMousePattern( int numButtons )
|
||||
{
|
||||
d_mousePattern.resize( MousePatternCount );
|
||||
|
||||
switch ( numButtons )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||
setMousePattern( MouseSelect2, Qt::LeftButton, Qt::ControlModifier );
|
||||
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||
setMousePattern( MouseSelect2, Qt::RightButton );
|
||||
setMousePattern( MouseSelect3, Qt::LeftButton, Qt::AltModifier );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
setMousePattern( MouseSelect1, Qt::LeftButton );
|
||||
setMousePattern( MouseSelect2, Qt::RightButton );
|
||||
setMousePattern( MouseSelect3, Qt::MidButton );
|
||||
}
|
||||
}
|
||||
|
||||
setMousePattern( MouseSelect4, d_mousePattern[MouseSelect1].button,
|
||||
d_mousePattern[MouseSelect1].modifiers | Qt::ShiftModifier );
|
||||
|
||||
setMousePattern( MouseSelect5, d_mousePattern[MouseSelect2].button,
|
||||
d_mousePattern[MouseSelect2].modifiers | Qt::ShiftModifier );
|
||||
|
||||
setMousePattern( MouseSelect6, d_mousePattern[MouseSelect3].button,
|
||||
d_mousePattern[MouseSelect3].modifiers | Qt::ShiftModifier );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set default mouse patterns.
|
||||
|
||||
\sa KeyPatternCode
|
||||
*/
|
||||
void QwtEventPattern::initKeyPattern()
|
||||
{
|
||||
d_keyPattern.resize( KeyPatternCount );
|
||||
|
||||
setKeyPattern( KeySelect1, Qt::Key_Return );
|
||||
setKeyPattern( KeySelect2, Qt::Key_Space );
|
||||
setKeyPattern( KeyAbort, Qt::Key_Escape );
|
||||
|
||||
setKeyPattern( KeyLeft, Qt::Key_Left );
|
||||
setKeyPattern( KeyRight, Qt::Key_Right );
|
||||
setKeyPattern( KeyUp, Qt::Key_Up );
|
||||
setKeyPattern( KeyDown, Qt::Key_Down );
|
||||
|
||||
setKeyPattern( KeyRedo, Qt::Key_Plus );
|
||||
setKeyPattern( KeyUndo, Qt::Key_Minus );
|
||||
setKeyPattern( KeyHome, Qt::Key_Escape );
|
||||
}
|
||||
|
||||
/*!
|
||||
Change one mouse pattern
|
||||
|
||||
\param pattern Index of the pattern
|
||||
\param button Button
|
||||
\param modifiers Keyboard modifiers
|
||||
|
||||
\sa QMouseEvent
|
||||
*/
|
||||
void QwtEventPattern::setMousePattern( MousePatternCode pattern,
|
||||
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
if ( pattern >= 0 && pattern < MousePatternCount )
|
||||
{
|
||||
d_mousePattern[ pattern ].button = button;
|
||||
d_mousePattern[ pattern ].modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Change one key pattern
|
||||
|
||||
\param pattern Index of the pattern
|
||||
\param key Key
|
||||
\param modifiers Keyboard modifiers
|
||||
|
||||
\sa QKeyEvent
|
||||
*/
|
||||
void QwtEventPattern::setKeyPattern( KeyPatternCode pattern,
|
||||
int key, Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
if ( pattern >= 0 && pattern < KeyPatternCount )
|
||||
{
|
||||
d_keyPattern[ pattern ].key = key;
|
||||
d_keyPattern[ pattern ].modifiers = modifiers;
|
||||
}
|
||||
}
|
||||
|
||||
//! Change the mouse event patterns
|
||||
void QwtEventPattern::setMousePattern( const QVector<MousePattern> &pattern )
|
||||
{
|
||||
d_mousePattern = pattern;
|
||||
}
|
||||
|
||||
//! Change the key event patterns
|
||||
void QwtEventPattern::setKeyPattern( const QVector<KeyPattern> &pattern )
|
||||
{
|
||||
d_keyPattern = pattern;
|
||||
}
|
||||
|
||||
//! \return Mouse pattern
|
||||
const QVector<QwtEventPattern::MousePattern> &
|
||||
QwtEventPattern::mousePattern() const
|
||||
{
|
||||
return d_mousePattern;
|
||||
}
|
||||
|
||||
//! \return Key pattern
|
||||
const QVector<QwtEventPattern::KeyPattern> &
|
||||
QwtEventPattern::keyPattern() const
|
||||
{
|
||||
return d_keyPattern;
|
||||
}
|
||||
|
||||
//! \return Mouse pattern
|
||||
QVector<QwtEventPattern::MousePattern> &QwtEventPattern::mousePattern()
|
||||
{
|
||||
return d_mousePattern;
|
||||
}
|
||||
|
||||
//! \return Key pattern
|
||||
QVector<QwtEventPattern::KeyPattern> &QwtEventPattern::keyPattern()
|
||||
{
|
||||
return d_keyPattern;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Compare a mouse event with an event pattern.
|
||||
|
||||
A mouse event matches the pattern when both have the same button
|
||||
value and in the state value the same key flags(Qt::KeyButtonMask)
|
||||
are set.
|
||||
|
||||
\param code Index of the event pattern
|
||||
\param event Mouse event
|
||||
\return true if matches
|
||||
|
||||
\sa keyMatch()
|
||||
*/
|
||||
bool QwtEventPattern::mouseMatch( MousePatternCode code,
|
||||
const QMouseEvent *event ) const
|
||||
{
|
||||
if ( code >= 0 && code < MousePatternCount )
|
||||
return mouseMatch( d_mousePattern[ code ], event );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Compare a mouse event with an event pattern.
|
||||
|
||||
A mouse event matches the pattern when both have the same button
|
||||
value and in the state value the same key flags(Qt::KeyButtonMask)
|
||||
are set.
|
||||
|
||||
\param pattern Mouse event pattern
|
||||
\param event Mouse event
|
||||
\return true if matches
|
||||
|
||||
\sa keyMatch()
|
||||
*/
|
||||
|
||||
bool QwtEventPattern::mouseMatch( const MousePattern &pattern,
|
||||
const QMouseEvent *event ) const
|
||||
{
|
||||
if ( event == NULL )
|
||||
return false;
|
||||
|
||||
const MousePattern mousePattern( event->button(), event->modifiers() );
|
||||
return mousePattern == pattern;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Compare a key event with an event pattern.
|
||||
|
||||
A key event matches the pattern when both have the same key
|
||||
value and in the state value the same key flags (Qt::KeyButtonMask)
|
||||
are set.
|
||||
|
||||
\param code Index of the event pattern
|
||||
\param event Key event
|
||||
\return true if matches
|
||||
|
||||
\sa mouseMatch()
|
||||
*/
|
||||
bool QwtEventPattern::keyMatch( KeyPatternCode code,
|
||||
const QKeyEvent *event ) const
|
||||
{
|
||||
if ( code >= 0 && code < KeyPatternCount )
|
||||
return keyMatch( d_keyPattern[ code ], event );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Compare a key event with an event pattern.
|
||||
|
||||
A key event matches the pattern when both have the same key
|
||||
value and in the state value the same key flags (Qt::KeyButtonMask)
|
||||
are set.
|
||||
|
||||
\param pattern Key event pattern
|
||||
\param event Key event
|
||||
\return true if matches
|
||||
|
||||
\sa mouseMatch()
|
||||
*/
|
||||
|
||||
bool QwtEventPattern::keyMatch(
|
||||
const KeyPattern &pattern, const QKeyEvent *event ) const
|
||||
{
|
||||
if ( event == NULL )
|
||||
return false;
|
||||
|
||||
const KeyPattern keyPattern( event->key(), event->modifiers() );
|
||||
return keyPattern == pattern;
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_EVENT_PATTERN
|
||||
#define QWT_EVENT_PATTERN 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qnamespace.h>
|
||||
#include <qvector.h>
|
||||
|
||||
class QMouseEvent;
|
||||
class QKeyEvent;
|
||||
|
||||
/*!
|
||||
\brief A collection of event patterns
|
||||
|
||||
QwtEventPattern introduces an level of indirection for mouse and
|
||||
keyboard inputs. Those are represented by symbolic names, so
|
||||
the application code can be configured by individual mappings.
|
||||
|
||||
\sa QwtPicker, QwtPickerMachine, QwtPlotZoomer
|
||||
*/
|
||||
class QWT_EXPORT QwtEventPattern
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Symbolic mouse input codes
|
||||
|
||||
QwtEventPattern implements 3 different settings for
|
||||
mice with 1, 2, or 3 buttons that can be activated
|
||||
using initMousePattern(). The default setting is for
|
||||
3 button mice.
|
||||
|
||||
Individual settings can be configured using setMousePattern().
|
||||
|
||||
\sa initMousePattern(), setMousePattern(), setKeyPattern()
|
||||
*/
|
||||
enum MousePatternCode
|
||||
{
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton
|
||||
- Qt::LeftButton
|
||||
- Qt::LeftButton
|
||||
*/
|
||||
MouseSelect1,
|
||||
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton + Qt::ControlModifier
|
||||
- Qt::RightButton
|
||||
- Qt::RightButton
|
||||
*/
|
||||
MouseSelect2,
|
||||
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton + Qt::AltModifier
|
||||
- Qt::LeftButton + Qt::AltModifier
|
||||
- Qt::MidButton
|
||||
*/
|
||||
MouseSelect3,
|
||||
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton + Qt::ShiftModifier
|
||||
- Qt::LeftButton + Qt::ShiftModifier
|
||||
- Qt::LeftButton + Qt::ShiftModifier
|
||||
*/
|
||||
MouseSelect4,
|
||||
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton + Qt::ControlButton | Qt::ShiftModifier
|
||||
- Qt::RightButton + Qt::ShiftModifier
|
||||
- Qt::RightButton + Qt::ShiftModifier
|
||||
*/
|
||||
MouseSelect5,
|
||||
|
||||
/*!
|
||||
The default setting for 1, 2 and 3 button mice is:
|
||||
|
||||
- Qt::LeftButton + Qt::AltModifier + Qt::ShiftModifier
|
||||
- Qt::LeftButton + Qt::AltModifier | Qt::ShiftModifier
|
||||
- Qt::MidButton + Qt::ShiftModifier
|
||||
*/
|
||||
MouseSelect6,
|
||||
|
||||
//! Number of mouse patterns
|
||||
MousePatternCount
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Symbolic keyboard input codes
|
||||
|
||||
Individual settings can be configured using setKeyPattern()
|
||||
|
||||
\sa setKeyPattern(), setMousePattern()
|
||||
*/
|
||||
enum KeyPatternCode
|
||||
{
|
||||
//! Qt::Key_Return
|
||||
KeySelect1,
|
||||
|
||||
//! Qt::Key_Space
|
||||
KeySelect2,
|
||||
|
||||
//! Qt::Key_Escape
|
||||
KeyAbort,
|
||||
|
||||
//! Qt::Key_Left
|
||||
KeyLeft,
|
||||
|
||||
//! Qt::Key_Right
|
||||
KeyRight,
|
||||
|
||||
//! Qt::Key_Up
|
||||
KeyUp,
|
||||
|
||||
//! Qt::Key_Down
|
||||
KeyDown,
|
||||
|
||||
//! Qt::Key_Plus
|
||||
KeyRedo,
|
||||
|
||||
//! Qt::Key_Minus
|
||||
KeyUndo,
|
||||
|
||||
//! Qt::Key_Escape
|
||||
KeyHome,
|
||||
|
||||
//! Number of key patterns
|
||||
KeyPatternCount
|
||||
};
|
||||
|
||||
//! A pattern for mouse events
|
||||
class MousePattern
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
MousePattern( Qt::MouseButton btn = Qt::NoButton,
|
||||
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
|
||||
button( btn ),
|
||||
modifiers( modifierCodes )
|
||||
{
|
||||
}
|
||||
|
||||
//! Button
|
||||
Qt::MouseButton button;
|
||||
|
||||
//! Keyboard modifier
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
};
|
||||
|
||||
//! A pattern for key events
|
||||
class KeyPattern
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
KeyPattern( int keyCode = Qt::Key_unknown,
|
||||
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier ):
|
||||
key( keyCode ),
|
||||
modifiers( modifierCodes )
|
||||
{
|
||||
}
|
||||
|
||||
//! Key code
|
||||
int key;
|
||||
|
||||
//! Modifiers
|
||||
Qt::KeyboardModifiers modifiers;
|
||||
};
|
||||
|
||||
QwtEventPattern();
|
||||
virtual ~QwtEventPattern();
|
||||
|
||||
void initMousePattern( int numButtons );
|
||||
void initKeyPattern();
|
||||
|
||||
void setMousePattern( MousePatternCode, Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
|
||||
void setKeyPattern( KeyPatternCode, int keyCode,
|
||||
Qt::KeyboardModifiers modifierCodes = Qt::NoModifier );
|
||||
|
||||
void setMousePattern( const QVector<MousePattern> & );
|
||||
void setKeyPattern( const QVector<KeyPattern> & );
|
||||
|
||||
const QVector<MousePattern> &mousePattern() const;
|
||||
const QVector<KeyPattern> &keyPattern() const;
|
||||
|
||||
QVector<MousePattern> &mousePattern();
|
||||
QVector<KeyPattern> &keyPattern();
|
||||
|
||||
bool mouseMatch( MousePatternCode, const QMouseEvent * ) const;
|
||||
bool keyMatch( KeyPatternCode, const QKeyEvent * ) const;
|
||||
|
||||
protected:
|
||||
virtual bool mouseMatch( const MousePattern &, const QMouseEvent * ) const;
|
||||
virtual bool keyMatch( const KeyPattern &, const QKeyEvent * ) const;
|
||||
|
||||
private:
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4251)
|
||||
#endif
|
||||
QVector<MousePattern> d_mousePattern;
|
||||
QVector<KeyPattern> d_keyPattern;
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
};
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator==( QwtEventPattern::MousePattern b1,
|
||||
QwtEventPattern::MousePattern b2 )
|
||||
{
|
||||
return b1.button == b2.button && b1.modifiers == b2.modifiers;
|
||||
}
|
||||
|
||||
//! Compare operator
|
||||
inline bool operator==( QwtEventPattern::KeyPattern b1,
|
||||
QwtEventPattern::KeyPattern b2 )
|
||||
{
|
||||
return b1.key == b2.key && b1.modifiers == b2.modifiers;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_GLOBAL_H
|
||||
#define QWT_GLOBAL_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
// QWT_VERSION is (major << 16) + (minor << 8) + patch.
|
||||
|
||||
#define QWT_VERSION 0x060103
|
||||
#define QWT_VERSION_STR "6.1.3"
|
||||
|
||||
#if defined(_MSC_VER) /* MSVC Compiler */
|
||||
/* template-class specialization 'identifier' is already instantiated */
|
||||
#pragma warning(disable: 4660)
|
||||
/* inherits via dominance */
|
||||
#pragma warning(disable: 4250)
|
||||
#endif // _MSC_VER
|
||||
|
||||
#ifdef QWT_DLL
|
||||
|
||||
#if defined(QWT_MAKEDLL) // create a Qwt DLL library
|
||||
#define QWT_EXPORT Q_DECL_EXPORT
|
||||
#else // use a Qwt DLL library
|
||||
#define QWT_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // QWT_DLL
|
||||
|
||||
#ifndef QWT_EXPORT
|
||||
#define QWT_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,176 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_GRAPHIC_H
|
||||
#define QWT_GRAPHIC_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_null_paintdevice.h"
|
||||
#include <qmetatype.h>
|
||||
#include <qimage.h>
|
||||
#include <qpixmap.h>
|
||||
|
||||
class QwtPainterCommand;
|
||||
|
||||
/*!
|
||||
\brief A paint device for scalable graphics
|
||||
|
||||
QwtGraphic is the representation of a graphic that is tailored for
|
||||
scalability. Like QPicture it will be initialized by QPainter
|
||||
operations and can be replayed later to any target paint device.
|
||||
|
||||
While the usual image representations QImage and QPixmap are not
|
||||
scalable Qt offers two paint devices, that might be candidates
|
||||
for representing a vector graphic:
|
||||
|
||||
- QPicture\n
|
||||
Unfortunately QPicture had been forgotten, when Qt4
|
||||
introduced floating point based render engines. Its API
|
||||
is still on integers, what make it unusable for proper scaling.
|
||||
|
||||
- QSvgRenderer/QSvgGenerator\n
|
||||
Unfortunately QSvgRenderer hides to much information about
|
||||
its nodes in internal APIs, that are necessary for proper
|
||||
layout calculations. Also it is derived from QObject and
|
||||
can't be copied like QImage/QPixmap.
|
||||
|
||||
QwtGraphic maps all scalable drawing primitives to a QPainterPath
|
||||
and stores them together with the painter state changes
|
||||
( pen, brush, transformation ... ) in a list of QwtPaintCommands.
|
||||
For being a complete QPaintDevice it also stores pixmaps or images,
|
||||
what is somehow against the idea of the class, because these objects
|
||||
can't be scaled without a loss in quality.
|
||||
|
||||
The main issue about scaling a QwtGraphic object are the pens used for
|
||||
drawing the outlines of the painter paths. While non cosmetic pens
|
||||
( QPen::isCosmetic() ) are scaled with the same ratio as the path,
|
||||
cosmetic pens have a fixed width. A graphic might have paths with
|
||||
different pens - cosmetic and non-cosmetic.
|
||||
|
||||
QwtGraphic caches 2 different rectangles:
|
||||
|
||||
- control point rectangle\n
|
||||
The control point rectangle is the bounding rectangle of all
|
||||
control point rectangles of the painter paths, or the target
|
||||
rectangle of the pixmaps/images.
|
||||
|
||||
- bounding rectangle\n
|
||||
The bounding rectangle extends the control point rectangle by
|
||||
what is needed for rendering the outline with an unscaled pen.
|
||||
|
||||
Because the offset for drawing the outline depends on the shape
|
||||
of the painter path ( the peak of a triangle is different than the flat side )
|
||||
scaling with a fixed aspect ratio always needs to be calculated from the
|
||||
control point rectangle.
|
||||
|
||||
\sa QwtPainterCommand
|
||||
*/
|
||||
class QWT_EXPORT QwtGraphic: public QwtNullPaintDevice
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Hint how to render a graphic
|
||||
\sa setRenderHint(), testRenderHint()
|
||||
*/
|
||||
enum RenderHint
|
||||
{
|
||||
/*!
|
||||
When rendering a QwtGraphic a specific scaling between
|
||||
the controlPointRect() and the coordinates of the target rectangle
|
||||
is set up internally in render().
|
||||
|
||||
When RenderPensUnscaled is set this specific scaling is applied
|
||||
for the control points only, but not for the pens.
|
||||
All other painter transformations ( set up by application code )
|
||||
are supposed to work like usual.
|
||||
|
||||
\sa render();
|
||||
*/
|
||||
RenderPensUnscaled = 0x1
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Render hints
|
||||
|
||||
The default setting is to disable all hints
|
||||
*/
|
||||
typedef QFlags<RenderHint> RenderHints;
|
||||
|
||||
QwtGraphic();
|
||||
QwtGraphic( const QwtGraphic & );
|
||||
|
||||
virtual ~QwtGraphic();
|
||||
|
||||
QwtGraphic& operator=( const QwtGraphic & );
|
||||
|
||||
void reset();
|
||||
|
||||
bool isNull() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
void render( QPainter * ) const;
|
||||
|
||||
void render( QPainter *, const QSizeF &,
|
||||
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||
|
||||
void render( QPainter *, const QRectF &,
|
||||
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||
|
||||
void render( QPainter *, const QPointF &,
|
||||
Qt::Alignment = Qt::AlignTop | Qt::AlignLeft ) const;
|
||||
|
||||
QPixmap toPixmap() const;
|
||||
QPixmap toPixmap( const QSize &,
|
||||
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||
|
||||
QImage toImage() const;
|
||||
QImage toImage( const QSize &,
|
||||
Qt::AspectRatioMode = Qt::IgnoreAspectRatio ) const;
|
||||
|
||||
QRectF scaledBoundingRect( double sx, double sy ) const;
|
||||
|
||||
QRectF boundingRect() const;
|
||||
QRectF controlPointRect() const;
|
||||
|
||||
const QVector< QwtPainterCommand > &commands() const;
|
||||
void setCommands( QVector< QwtPainterCommand > & );
|
||||
|
||||
void setDefaultSize( const QSizeF & );
|
||||
QSizeF defaultSize() const;
|
||||
|
||||
void setRenderHint( RenderHint, bool on = true );
|
||||
bool testRenderHint( RenderHint ) const;
|
||||
|
||||
protected:
|
||||
virtual QSize sizeMetrics() const;
|
||||
|
||||
virtual void drawPath( const QPainterPath & );
|
||||
|
||||
virtual void drawPixmap( const QRectF &,
|
||||
const QPixmap &, const QRectF & );
|
||||
|
||||
virtual void drawImage( const QRectF &,
|
||||
const QImage &, const QRectF &, Qt::ImageConversionFlags );
|
||||
|
||||
virtual void updateState( const QPaintEngineState &state );
|
||||
|
||||
private:
|
||||
void updateBoundingRect( const QRectF & );
|
||||
void updateControlPointRect( const QRectF & );
|
||||
|
||||
class PathInfo;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtGraphic::RenderHints )
|
||||
Q_DECLARE_METATYPE( QwtGraphic )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,354 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_interval.h"
|
||||
#include "qwt_math.h"
|
||||
#include <qalgorithms.h>
|
||||
|
||||
/*!
|
||||
\brief Normalize the limits of the interval
|
||||
|
||||
If maxValue() < minValue() the limits will be inverted.
|
||||
\return Normalized interval
|
||||
|
||||
\sa isValid(), inverted()
|
||||
*/
|
||||
QwtInterval QwtInterval::normalized() const
|
||||
{
|
||||
if ( d_minValue > d_maxValue )
|
||||
{
|
||||
return inverted();
|
||||
}
|
||||
if ( d_minValue == d_maxValue && d_borderFlags == ExcludeMinimum )
|
||||
{
|
||||
return inverted();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
Invert the limits of the interval
|
||||
\return Inverted interval
|
||||
\sa normalized()
|
||||
*/
|
||||
QwtInterval QwtInterval::inverted() const
|
||||
{
|
||||
BorderFlags borderFlags = IncludeBorders;
|
||||
if ( d_borderFlags & ExcludeMinimum )
|
||||
borderFlags |= ExcludeMaximum;
|
||||
if ( d_borderFlags & ExcludeMaximum )
|
||||
borderFlags |= ExcludeMinimum;
|
||||
|
||||
return QwtInterval( d_maxValue, d_minValue, borderFlags );
|
||||
}
|
||||
|
||||
/*!
|
||||
Test if a value is inside an interval
|
||||
|
||||
\param value Value
|
||||
\return true, if value >= minValue() && value <= maxValue()
|
||||
*/
|
||||
bool QwtInterval::contains( double value ) const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return false;
|
||||
|
||||
if ( value < d_minValue || value > d_maxValue )
|
||||
return false;
|
||||
|
||||
if ( value == d_minValue && d_borderFlags & ExcludeMinimum )
|
||||
return false;
|
||||
|
||||
if ( value == d_maxValue && d_borderFlags & ExcludeMaximum )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Unite 2 intervals
|
||||
QwtInterval QwtInterval::unite( const QwtInterval &other ) const
|
||||
{
|
||||
/*
|
||||
If one of the intervals is invalid return the other one.
|
||||
If both are invalid return an invalid default interval
|
||||
*/
|
||||
if ( !isValid() )
|
||||
{
|
||||
if ( !other.isValid() )
|
||||
return QwtInterval();
|
||||
else
|
||||
return other;
|
||||
}
|
||||
if ( !other.isValid() )
|
||||
return *this;
|
||||
|
||||
QwtInterval united;
|
||||
BorderFlags flags = IncludeBorders;
|
||||
|
||||
// minimum
|
||||
if ( d_minValue < other.minValue() )
|
||||
{
|
||||
united.setMinValue( d_minValue );
|
||||
flags &= d_borderFlags & ExcludeMinimum;
|
||||
}
|
||||
else if ( other.minValue() < d_minValue )
|
||||
{
|
||||
united.setMinValue( other.minValue() );
|
||||
flags &= other.borderFlags() & ExcludeMinimum;
|
||||
}
|
||||
else // d_minValue == other.minValue()
|
||||
{
|
||||
united.setMinValue( d_minValue );
|
||||
flags &= ( d_borderFlags & other.borderFlags() ) & ExcludeMinimum;
|
||||
}
|
||||
|
||||
// maximum
|
||||
if ( d_maxValue > other.maxValue() )
|
||||
{
|
||||
united.setMaxValue( d_maxValue );
|
||||
flags &= d_borderFlags & ExcludeMaximum;
|
||||
}
|
||||
else if ( other.maxValue() > d_maxValue )
|
||||
{
|
||||
united.setMaxValue( other.maxValue() );
|
||||
flags &= other.borderFlags() & ExcludeMaximum;
|
||||
}
|
||||
else // d_maxValue == other.maxValue() )
|
||||
{
|
||||
united.setMaxValue( d_maxValue );
|
||||
flags &= d_borderFlags & other.borderFlags() & ExcludeMaximum;
|
||||
}
|
||||
|
||||
united.setBorderFlags( flags );
|
||||
return united;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Intersect 2 intervals
|
||||
|
||||
\param other Interval to be intersect with
|
||||
\return Intersection
|
||||
*/
|
||||
QwtInterval QwtInterval::intersect( const QwtInterval &other ) const
|
||||
{
|
||||
if ( !other.isValid() || !isValid() )
|
||||
return QwtInterval();
|
||||
|
||||
QwtInterval i1 = *this;
|
||||
QwtInterval i2 = other;
|
||||
|
||||
// swap i1/i2, so that the minimum of i1
|
||||
// is smaller then the minimum of i2
|
||||
|
||||
if ( i1.minValue() > i2.minValue() )
|
||||
{
|
||||
qSwap( i1, i2 );
|
||||
}
|
||||
else if ( i1.minValue() == i2.minValue() )
|
||||
{
|
||||
if ( i1.borderFlags() & ExcludeMinimum )
|
||||
qSwap( i1, i2 );
|
||||
}
|
||||
|
||||
if ( i1.maxValue() < i2.minValue() )
|
||||
{
|
||||
return QwtInterval();
|
||||
}
|
||||
|
||||
if ( i1.maxValue() == i2.minValue() )
|
||||
{
|
||||
if ( i1.borderFlags() & ExcludeMaximum ||
|
||||
i2.borderFlags() & ExcludeMinimum )
|
||||
{
|
||||
return QwtInterval();
|
||||
}
|
||||
}
|
||||
|
||||
QwtInterval intersected;
|
||||
BorderFlags flags = IncludeBorders;
|
||||
|
||||
intersected.setMinValue( i2.minValue() );
|
||||
flags |= i2.borderFlags() & ExcludeMinimum;
|
||||
|
||||
if ( i1.maxValue() < i2.maxValue() )
|
||||
{
|
||||
intersected.setMaxValue( i1.maxValue() );
|
||||
flags |= i1.borderFlags() & ExcludeMaximum;
|
||||
}
|
||||
else if ( i2.maxValue() < i1.maxValue() )
|
||||
{
|
||||
intersected.setMaxValue( i2.maxValue() );
|
||||
flags |= i2.borderFlags() & ExcludeMaximum;
|
||||
}
|
||||
else // i1.maxValue() == i2.maxValue()
|
||||
{
|
||||
intersected.setMaxValue( i1.maxValue() );
|
||||
flags |= i1.borderFlags() & i2.borderFlags() & ExcludeMaximum;
|
||||
}
|
||||
|
||||
intersected.setBorderFlags( flags );
|
||||
return intersected;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Unite this interval with the given interval.
|
||||
|
||||
\param other Interval to be united with
|
||||
\return This interval
|
||||
*/
|
||||
QwtInterval& QwtInterval::operator|=( const QwtInterval &other )
|
||||
{
|
||||
*this = *this | other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Intersect this interval with the given interval.
|
||||
|
||||
\param other Interval to be intersected with
|
||||
\return This interval
|
||||
*/
|
||||
QwtInterval& QwtInterval::operator&=( const QwtInterval &other )
|
||||
{
|
||||
*this = *this & other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Test if two intervals overlap
|
||||
|
||||
\param other Interval
|
||||
\return True, when the intervals are intersecting
|
||||
*/
|
||||
bool QwtInterval::intersects( const QwtInterval &other ) const
|
||||
{
|
||||
if ( !isValid() || !other.isValid() )
|
||||
return false;
|
||||
|
||||
QwtInterval i1 = *this;
|
||||
QwtInterval i2 = other;
|
||||
|
||||
// swap i1/i2, so that the minimum of i1
|
||||
// is smaller then the minimum of i2
|
||||
|
||||
if ( i1.minValue() > i2.minValue() )
|
||||
{
|
||||
qSwap( i1, i2 );
|
||||
}
|
||||
else if ( i1.minValue() == i2.minValue() &&
|
||||
i1.borderFlags() & ExcludeMinimum )
|
||||
{
|
||||
qSwap( i1, i2 );
|
||||
}
|
||||
|
||||
if ( i1.maxValue() > i2.minValue() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( i1.maxValue() == i2.minValue() )
|
||||
{
|
||||
return !( ( i1.borderFlags() & ExcludeMaximum ) ||
|
||||
( i2.borderFlags() & ExcludeMinimum ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Adjust the limit that is closer to value, so that value becomes
|
||||
the center of the interval.
|
||||
|
||||
\param value Center
|
||||
\return Interval with value as center
|
||||
*/
|
||||
QwtInterval QwtInterval::symmetrize( double value ) const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return *this;
|
||||
|
||||
const double delta =
|
||||
qMax( qAbs( value - d_maxValue ), qAbs( value - d_minValue ) );
|
||||
|
||||
return QwtInterval( value - delta, value + delta );
|
||||
}
|
||||
|
||||
/*!
|
||||
Limit the interval, keeping the border modes
|
||||
|
||||
\param lowerBound Lower limit
|
||||
\param upperBound Upper limit
|
||||
|
||||
\return Limited interval
|
||||
*/
|
||||
QwtInterval QwtInterval::limited( double lowerBound, double upperBound ) const
|
||||
{
|
||||
if ( !isValid() || lowerBound > upperBound )
|
||||
return QwtInterval();
|
||||
|
||||
double minValue = qMax( d_minValue, lowerBound );
|
||||
minValue = qMin( minValue, upperBound );
|
||||
|
||||
double maxValue = qMax( d_maxValue, lowerBound );
|
||||
maxValue = qMin( maxValue, upperBound );
|
||||
|
||||
return QwtInterval( minValue, maxValue, d_borderFlags );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Extend the interval
|
||||
|
||||
If value is below minValue(), value becomes the lower limit.
|
||||
If value is above maxValue(), value becomes the upper limit.
|
||||
|
||||
extend() has no effect for invalid intervals
|
||||
|
||||
\param value Value
|
||||
\return extended interval
|
||||
|
||||
\sa isValid()
|
||||
*/
|
||||
QwtInterval QwtInterval::extend( double value ) const
|
||||
{
|
||||
if ( !isValid() )
|
||||
return *this;
|
||||
|
||||
return QwtInterval( qMin( value, d_minValue ),
|
||||
qMax( value, d_maxValue ), d_borderFlags );
|
||||
}
|
||||
|
||||
/*!
|
||||
Extend an interval
|
||||
|
||||
\param value Value
|
||||
\return Reference of the extended interval
|
||||
|
||||
\sa extend()
|
||||
*/
|
||||
QwtInterval& QwtInterval::operator|=( double value )
|
||||
{
|
||||
*this = *this | value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
QDebug operator<<( QDebug debug, const QwtInterval &interval )
|
||||
{
|
||||
const int flags = interval.borderFlags();
|
||||
|
||||
debug.nospace() << "QwtInterval("
|
||||
<< ( ( flags & QwtInterval::ExcludeMinimum ) ? "]" : "[" )
|
||||
<< interval.minValue() << "," << interval.maxValue()
|
||||
<< ( ( flags & QwtInterval::ExcludeMaximum ) ? "[" : "]" )
|
||||
<< ")";
|
||||
|
||||
return debug.space();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,320 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_INTERVAL_H
|
||||
#define QWT_INTERVAL_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qmetatype.h>
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
#include <qdebug.h>
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief A class representing an interval
|
||||
|
||||
The interval is represented by 2 doubles, the lower and the upper limit.
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtInterval
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Flag indicating if a border is included or excluded
|
||||
\sa setBorderFlags(), borderFlags()
|
||||
*/
|
||||
enum BorderFlag
|
||||
{
|
||||
//! Min/Max values are inside the interval
|
||||
IncludeBorders = 0x00,
|
||||
|
||||
//! Min value is not included in the interval
|
||||
ExcludeMinimum = 0x01,
|
||||
|
||||
//! Max value is not included in the interval
|
||||
ExcludeMaximum = 0x02,
|
||||
|
||||
//! Min/Max values are not included in the interval
|
||||
ExcludeBorders = ExcludeMinimum | ExcludeMaximum
|
||||
};
|
||||
|
||||
//! Border flags
|
||||
typedef QFlags<BorderFlag> BorderFlags;
|
||||
|
||||
QwtInterval();
|
||||
QwtInterval( double minValue, double maxValue,
|
||||
BorderFlags = IncludeBorders );
|
||||
|
||||
void setInterval( double minValue, double maxValue,
|
||||
BorderFlags = IncludeBorders );
|
||||
|
||||
QwtInterval normalized() const;
|
||||
QwtInterval inverted() const;
|
||||
QwtInterval limited( double minValue, double maxValue ) const;
|
||||
|
||||
bool operator==( const QwtInterval & ) const;
|
||||
bool operator!=( const QwtInterval & ) const;
|
||||
|
||||
void setBorderFlags( BorderFlags );
|
||||
BorderFlags borderFlags() const;
|
||||
|
||||
double minValue() const;
|
||||
double maxValue() const;
|
||||
|
||||
double width() const;
|
||||
|
||||
void setMinValue( double );
|
||||
void setMaxValue( double );
|
||||
|
||||
bool contains( double value ) const;
|
||||
|
||||
bool intersects( const QwtInterval & ) const;
|
||||
QwtInterval intersect( const QwtInterval & ) const;
|
||||
QwtInterval unite( const QwtInterval & ) const;
|
||||
|
||||
QwtInterval operator|( const QwtInterval & ) const;
|
||||
QwtInterval operator&( const QwtInterval & ) const;
|
||||
|
||||
QwtInterval &operator|=( const QwtInterval & );
|
||||
QwtInterval &operator&=( const QwtInterval & );
|
||||
|
||||
QwtInterval extend( double value ) const;
|
||||
QwtInterval operator|( double ) const;
|
||||
QwtInterval &operator|=( double );
|
||||
|
||||
bool isValid() const;
|
||||
bool isNull() const;
|
||||
void invalidate();
|
||||
|
||||
QwtInterval symmetrize( double value ) const;
|
||||
|
||||
private:
|
||||
double d_minValue;
|
||||
double d_maxValue;
|
||||
BorderFlags d_borderFlags;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QwtInterval, Q_MOVABLE_TYPE);
|
||||
|
||||
/*!
|
||||
\brief Default Constructor
|
||||
|
||||
Creates an invalid interval [0.0, -1.0]
|
||||
\sa setInterval(), isValid()
|
||||
*/
|
||||
inline QwtInterval::QwtInterval():
|
||||
d_minValue( 0.0 ),
|
||||
d_maxValue( -1.0 ),
|
||||
d_borderFlags( IncludeBorders )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
Build an interval with from min/max values
|
||||
|
||||
\param minValue Minimum value
|
||||
\param maxValue Maximum value
|
||||
\param borderFlags Include/Exclude borders
|
||||
*/
|
||||
inline QwtInterval::QwtInterval(
|
||||
double minValue, double maxValue, BorderFlags borderFlags ):
|
||||
d_minValue( minValue ),
|
||||
d_maxValue( maxValue ),
|
||||
d_borderFlags( borderFlags )
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the limits of the interval
|
||||
|
||||
\param minValue Minimum value
|
||||
\param maxValue Maximum value
|
||||
\param borderFlags Include/Exclude borders
|
||||
*/
|
||||
inline void QwtInterval::setInterval(
|
||||
double minValue, double maxValue, BorderFlags borderFlags )
|
||||
{
|
||||
d_minValue = minValue;
|
||||
d_maxValue = maxValue;
|
||||
d_borderFlags = borderFlags;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the border flags
|
||||
|
||||
\param borderFlags Or'd BorderMode flags
|
||||
\sa borderFlags()
|
||||
*/
|
||||
inline void QwtInterval::setBorderFlags( BorderFlags borderFlags )
|
||||
{
|
||||
d_borderFlags = borderFlags;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Border flags
|
||||
\sa setBorderFlags()
|
||||
*/
|
||||
inline QwtInterval::BorderFlags QwtInterval::borderFlags() const
|
||||
{
|
||||
return d_borderFlags;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the lower limit of the interval
|
||||
|
||||
\param minValue Minimum value
|
||||
*/
|
||||
inline void QwtInterval::setMinValue( double minValue )
|
||||
{
|
||||
d_minValue = minValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the upper limit of the interval
|
||||
|
||||
\param maxValue Maximum value
|
||||
*/
|
||||
inline void QwtInterval::setMaxValue( double maxValue )
|
||||
{
|
||||
d_maxValue = maxValue;
|
||||
}
|
||||
|
||||
//! \return Lower limit of the interval
|
||||
inline double QwtInterval::minValue() const
|
||||
{
|
||||
return d_minValue;
|
||||
}
|
||||
|
||||
//! \return Upper limit of the interval
|
||||
inline double QwtInterval::maxValue() const
|
||||
{
|
||||
return d_maxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
A interval is valid when minValue() <= maxValue().
|
||||
In case of QwtInterval::ExcludeBorders it is true
|
||||
when minValue() < maxValue()
|
||||
|
||||
\return True, when the interval is valid
|
||||
*/
|
||||
inline bool QwtInterval::isValid() const
|
||||
{
|
||||
if ( ( d_borderFlags & ExcludeBorders ) == 0 )
|
||||
return d_minValue <= d_maxValue;
|
||||
else
|
||||
return d_minValue < d_maxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the width of an interval
|
||||
|
||||
The width of invalid intervals is 0.0, otherwise the result is
|
||||
maxValue() - minValue().
|
||||
|
||||
\return Interval width
|
||||
\sa isValid()
|
||||
*/
|
||||
inline double QwtInterval::width() const
|
||||
{
|
||||
return isValid() ? ( d_maxValue - d_minValue ) : 0.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Intersection of two intervals
|
||||
|
||||
\param other Interval to intersect with
|
||||
\return Intersection of this and other
|
||||
|
||||
\sa intersect()
|
||||
*/
|
||||
inline QwtInterval QwtInterval::operator&(
|
||||
const QwtInterval &other ) const
|
||||
{
|
||||
return intersect( other );
|
||||
}
|
||||
|
||||
/*!
|
||||
Union of two intervals
|
||||
|
||||
\param other Interval to unite with
|
||||
\return Union of this and other
|
||||
|
||||
\sa unite()
|
||||
*/
|
||||
inline QwtInterval QwtInterval::operator|(
|
||||
const QwtInterval &other ) const
|
||||
{
|
||||
return unite( other );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Compare two intervals
|
||||
|
||||
\param other Interval to compare with
|
||||
\return True, when this and other are equal
|
||||
*/
|
||||
inline bool QwtInterval::operator==( const QwtInterval &other ) const
|
||||
{
|
||||
return ( d_minValue == other.d_minValue ) &&
|
||||
( d_maxValue == other.d_maxValue ) &&
|
||||
( d_borderFlags == other.d_borderFlags );
|
||||
}
|
||||
/*!
|
||||
\brief Compare two intervals
|
||||
|
||||
\param other Interval to compare with
|
||||
\return True, when this and other are not equal
|
||||
*/
|
||||
inline bool QwtInterval::operator!=( const QwtInterval &other ) const
|
||||
{
|
||||
return ( !( *this == other ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Extend an interval
|
||||
|
||||
\param value Value
|
||||
\return Extended interval
|
||||
\sa extend()
|
||||
*/
|
||||
inline QwtInterval QwtInterval::operator|( double value ) const
|
||||
{
|
||||
return extend( value );
|
||||
}
|
||||
|
||||
//! \return true, if isValid() && (minValue() >= maxValue())
|
||||
inline bool QwtInterval::isNull() const
|
||||
{
|
||||
return isValid() && d_minValue >= d_maxValue;
|
||||
}
|
||||
|
||||
/*!
|
||||
Invalidate the interval
|
||||
|
||||
The limits are set to interval [0.0, -1.0]
|
||||
\sa isValid()
|
||||
*/
|
||||
inline void QwtInterval::invalidate()
|
||||
{
|
||||
d_minValue = 0.0;
|
||||
d_maxValue = -1.0;
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtInterval::BorderFlags )
|
||||
Q_DECLARE_METATYPE( QwtInterval )
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QWT_EXPORT QDebug operator<<( QDebug, const QwtInterval & );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,319 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_interval_symbol.h"
|
||||
#include "qwt_painter.h"
|
||||
#include "qwt_math.h"
|
||||
#include <qpainter.h>
|
||||
|
||||
#if QT_VERSION < 0x040601
|
||||
#define qAtan2(y, x) ::atan2(y, x)
|
||||
#define qFastSin(x) qSin(x)
|
||||
#define qFastCos(x) qCos(x)
|
||||
#endif
|
||||
|
||||
class QwtIntervalSymbol::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
style( QwtIntervalSymbol::NoSymbol ),
|
||||
width( 6 )
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==( const PrivateData &other ) const
|
||||
{
|
||||
return ( style == other.style )
|
||||
&& ( width == other.width )
|
||||
&& ( brush == other.brush )
|
||||
&& ( pen == other.pen );
|
||||
}
|
||||
|
||||
QwtIntervalSymbol::Style style;
|
||||
int width;
|
||||
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
\param style Style of the symbol
|
||||
\sa setStyle(), style(), Style
|
||||
*/
|
||||
QwtIntervalSymbol::QwtIntervalSymbol( Style style )
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
d_data->style = style;
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
QwtIntervalSymbol::QwtIntervalSymbol( const QwtIntervalSymbol &other )
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
*d_data = *other.d_data;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtIntervalSymbol::~QwtIntervalSymbol()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
//! \brief Assignment operator
|
||||
QwtIntervalSymbol &QwtIntervalSymbol::operator=(
|
||||
const QwtIntervalSymbol &other )
|
||||
{
|
||||
*d_data = *other.d_data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! \brief Compare two symbols
|
||||
bool QwtIntervalSymbol::operator==(
|
||||
const QwtIntervalSymbol &other ) const
|
||||
{
|
||||
return *d_data == *other.d_data;
|
||||
}
|
||||
|
||||
//! \brief Compare two symbols
|
||||
bool QwtIntervalSymbol::operator!=(
|
||||
const QwtIntervalSymbol &other ) const
|
||||
{
|
||||
return !( *d_data == *other.d_data );
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify the symbol style
|
||||
|
||||
\param style Style
|
||||
\sa style(), Style
|
||||
*/
|
||||
void QwtIntervalSymbol::setStyle( Style style )
|
||||
{
|
||||
d_data->style = style;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Current symbol style
|
||||
\sa setStyle()
|
||||
*/
|
||||
QwtIntervalSymbol::Style QwtIntervalSymbol::style() const
|
||||
{
|
||||
return d_data->style;
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify the width of the symbol
|
||||
It is used depending on the style.
|
||||
|
||||
\param width Width
|
||||
\sa width(), setStyle()
|
||||
*/
|
||||
void QwtIntervalSymbol::setWidth( int width )
|
||||
{
|
||||
d_data->width = width;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Width of the symbol.
|
||||
\sa setWidth(), setStyle()
|
||||
*/
|
||||
int QwtIntervalSymbol::width() const
|
||||
{
|
||||
return d_data->width;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a brush
|
||||
|
||||
The brush is used for the Box style.
|
||||
|
||||
\param brush Brush
|
||||
\sa brush()
|
||||
*/
|
||||
void QwtIntervalSymbol::setBrush( const QBrush &brush )
|
||||
{
|
||||
d_data->brush = brush;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Brush
|
||||
\sa setBrush()
|
||||
*/
|
||||
const QBrush& QwtIntervalSymbol::brush() const
|
||||
{
|
||||
return d_data->brush;
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtIntervalSymbol::setPen( const QColor &color,
|
||||
qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a pen
|
||||
|
||||
\param pen Pen
|
||||
\sa pen(), setBrush()
|
||||
*/
|
||||
void QwtIntervalSymbol::setPen( const QPen &pen )
|
||||
{
|
||||
d_data->pen = pen;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Pen
|
||||
\sa setPen(), brush()
|
||||
*/
|
||||
const QPen& QwtIntervalSymbol::pen() const
|
||||
{
|
||||
return d_data->pen;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a symbol depending on its style
|
||||
|
||||
\param painter Painter
|
||||
\param orientation Orientation
|
||||
\param from Start point of the interval in target device coordinates
|
||||
\param to End point of the interval in target device coordinates
|
||||
|
||||
\sa setStyle()
|
||||
*/
|
||||
void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation,
|
||||
const QPointF &from, const QPointF &to ) const
|
||||
{
|
||||
const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) );
|
||||
|
||||
QPointF p1 = from;
|
||||
QPointF p2 = to;
|
||||
if ( QwtPainter::roundingAlignment( painter ) )
|
||||
{
|
||||
p1 = p1.toPoint();
|
||||
p2 = p2.toPoint();
|
||||
}
|
||||
|
||||
switch ( d_data->style )
|
||||
{
|
||||
case QwtIntervalSymbol::Bar:
|
||||
{
|
||||
QwtPainter::drawLine( painter, p1, p2 );
|
||||
if ( d_data->width > pw )
|
||||
{
|
||||
if ( ( orientation == Qt::Horizontal )
|
||||
&& ( p1.y() == p2.y() ) )
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double y = p1.y() - sw / 2;
|
||||
QwtPainter::drawLine( painter,
|
||||
p1.x(), y, p1.x(), y + sw );
|
||||
QwtPainter::drawLine( painter,
|
||||
p2.x(), y, p2.x(), y + sw );
|
||||
}
|
||||
else if ( ( orientation == Qt::Vertical )
|
||||
&& ( p1.x() == p2.x() ) )
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double x = p1.x() - sw / 2;
|
||||
QwtPainter::drawLine( painter,
|
||||
x, p1.y(), x + sw, p1.y() );
|
||||
QwtPainter::drawLine( painter,
|
||||
x, p2.y(), x + sw, p2.y() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double dx = p2.x() - p1.x();
|
||||
const double dy = p2.y() - p1.y();
|
||||
const double angle = qAtan2( dy, dx ) + M_PI_2;
|
||||
double dw2 = sw / 2.0;
|
||||
|
||||
const double cx = qFastCos( angle ) * dw2;
|
||||
const double sy = qFastSin( angle ) * dw2;
|
||||
|
||||
QwtPainter::drawLine( painter,
|
||||
p1.x() - cx, p1.y() - sy,
|
||||
p1.x() + cx, p1.y() + sy );
|
||||
QwtPainter::drawLine( painter,
|
||||
p2.x() - cx, p2.y() - sy,
|
||||
p2.x() + cx, p2.y() + sy );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QwtIntervalSymbol::Box:
|
||||
{
|
||||
if ( d_data->width <= pw )
|
||||
{
|
||||
QwtPainter::drawLine( painter, p1, p2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( orientation == Qt::Horizontal )
|
||||
&& ( p1.y() == p2.y() ) )
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double y = p1.y() - d_data->width / 2;
|
||||
QwtPainter::drawRect( painter,
|
||||
p1.x(), y, p2.x() - p1.x(), sw );
|
||||
}
|
||||
else if ( ( orientation == Qt::Vertical )
|
||||
&& ( p1.x() == p2.x() ) )
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double x = p1.x() - d_data->width / 2;
|
||||
QwtPainter::drawRect( painter,
|
||||
x, p1.y(), sw, p2.y() - p1.y() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const double sw = d_data->width;
|
||||
|
||||
const double dx = p2.x() - p1.x();
|
||||
const double dy = p2.y() - p1.y();
|
||||
const double angle = qAtan2( dy, dx ) + M_PI_2;
|
||||
double dw2 = sw / 2.0;
|
||||
|
||||
const double cx = qFastCos( angle ) * dw2;
|
||||
const double sy = qFastSin( angle ) * dw2;
|
||||
|
||||
QPolygonF polygon;
|
||||
polygon += QPointF( p1.x() - cx, p1.y() - sy );
|
||||
polygon += QPointF( p1.x() + cx, p1.y() + sy );
|
||||
polygon += QPointF( p2.x() + cx, p2.y() + sy );
|
||||
polygon += QPointF( p2.x() - cx, p2.y() - sy );
|
||||
|
||||
QwtPainter::drawPolygon( painter, polygon );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_INTERVAL_SYMBOL_H
|
||||
#define QWT_INTERVAL_SYMBOL_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpen.h>
|
||||
#include <qsize.h>
|
||||
|
||||
class QPainter;
|
||||
class QRect;
|
||||
class QPointF;
|
||||
|
||||
/*!
|
||||
\brief A drawing primitive for displaying an interval like an error bar
|
||||
|
||||
\sa QwtPlotIntervalCurve
|
||||
*/
|
||||
class QWT_EXPORT QwtIntervalSymbol
|
||||
{
|
||||
public:
|
||||
//! Symbol style
|
||||
enum Style
|
||||
{
|
||||
//! No Style. The symbol cannot be drawn.
|
||||
NoSymbol = -1,
|
||||
|
||||
/*!
|
||||
The symbol displays a line with caps at the beginning/end.
|
||||
The size of the caps depends on the symbol width().
|
||||
*/
|
||||
Bar,
|
||||
|
||||
/*!
|
||||
The symbol displays a plain rectangle using pen() and brush().
|
||||
The size of the rectangle depends on the translated interval and
|
||||
the width(),
|
||||
*/
|
||||
Box,
|
||||
|
||||
/*!
|
||||
Styles >= UserSymbol are reserved for derived
|
||||
classes of QwtIntervalSymbol that overload draw() with
|
||||
additional application specific symbol types.
|
||||
*/
|
||||
UserSymbol = 1000
|
||||
};
|
||||
|
||||
public:
|
||||
QwtIntervalSymbol( Style = NoSymbol );
|
||||
QwtIntervalSymbol( const QwtIntervalSymbol & );
|
||||
virtual ~QwtIntervalSymbol();
|
||||
|
||||
QwtIntervalSymbol &operator=( const QwtIntervalSymbol & );
|
||||
bool operator==( const QwtIntervalSymbol & ) const;
|
||||
bool operator!=( const QwtIntervalSymbol & ) const;
|
||||
|
||||
void setWidth( int );
|
||||
int width() const;
|
||||
|
||||
void setBrush( const QBrush& b );
|
||||
const QBrush& brush() const;
|
||||
|
||||
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setPen( const QPen & );
|
||||
const QPen& pen() const;
|
||||
|
||||
void setStyle( Style );
|
||||
Style style() const;
|
||||
|
||||
virtual void draw( QPainter *, Qt::Orientation,
|
||||
const QPointF& from, const QPointF& to ) const;
|
||||
|
||||
private:
|
||||
|
||||
class PrivateData;
|
||||
PrivateData* d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,855 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_knob.h"
|
||||
#include "qwt_round_scale_draw.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_painter.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include <qpainter.h>
|
||||
#include <qpalette.h>
|
||||
#include <qstyle.h>
|
||||
#include <qstyleoption.h>
|
||||
#include <qevent.h>
|
||||
#include <qmath.h>
|
||||
#include <qapplication.h>
|
||||
|
||||
#if QT_VERSION < 0x040601
|
||||
#define qAtan2(y, x) ::atan2(y, x)
|
||||
#define qFabs(x) ::fabs(x)
|
||||
#define qFastCos(x) qCos(x)
|
||||
#define qFastSin(x) qSin(x)
|
||||
#endif
|
||||
|
||||
static QSize qwtKnobSizeHint( const QwtKnob *knob, int min )
|
||||
{
|
||||
int knobWidth = knob->knobWidth();
|
||||
if ( knobWidth <= 0 )
|
||||
knobWidth = qMax( 3 * knob->markerSize(), min );
|
||||
|
||||
// Add the scale radial thickness to the knobWidth
|
||||
const int extent = qCeil( knob->scaleDraw()->extent( knob->font() ) );
|
||||
const int d = 2 * ( extent + 4 ) + knobWidth;
|
||||
|
||||
int left, right, top, bottom;
|
||||
knob->getContentsMargins( &left, &top, &right, &bottom );
|
||||
|
||||
return QSize( d + left + right, d + top + bottom );
|
||||
}
|
||||
|
||||
static inline double qwtToScaleAngle( double angle )
|
||||
{
|
||||
// the map is counter clockwise with the origin
|
||||
// at 90° using angles from -180° -> 180°
|
||||
|
||||
double a = 90.0 - angle;
|
||||
if ( a <= -180.0 )
|
||||
a += 360.0;
|
||||
else if ( a >= 180.0 )
|
||||
a -= 360.0;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static double qwtToDegrees( double value )
|
||||
{
|
||||
return qwtNormalizeDegrees( 90.0 - value );
|
||||
}
|
||||
|
||||
class QwtKnob::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
knobStyle( QwtKnob::Raised ),
|
||||
markerStyle( QwtKnob::Notch ),
|
||||
borderWidth( 2 ),
|
||||
borderDist( 4 ),
|
||||
scaleDist( 4 ),
|
||||
maxScaleTicks( 11 ),
|
||||
knobWidth( 0 ),
|
||||
alignment( Qt::AlignCenter ),
|
||||
markerSize( 8 ),
|
||||
totalAngle( 270.0 ),
|
||||
mouseOffset( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
QwtKnob::KnobStyle knobStyle;
|
||||
QwtKnob::MarkerStyle markerStyle;
|
||||
|
||||
int borderWidth;
|
||||
int borderDist;
|
||||
int scaleDist;
|
||||
int maxScaleTicks;
|
||||
int knobWidth;
|
||||
Qt::Alignment alignment;
|
||||
int markerSize;
|
||||
|
||||
double totalAngle;
|
||||
|
||||
double mouseOffset;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Constructor
|
||||
|
||||
Construct a knob with an angle of 270°. The style is
|
||||
QwtKnob::Raised and the marker style is QwtKnob::Notch.
|
||||
The width of the knob is set to 50 pixels.
|
||||
|
||||
\param parent Parent widget
|
||||
|
||||
\sa setTotalAngle()
|
||||
*/
|
||||
QwtKnob::QwtKnob( QWidget* parent ):
|
||||
QwtAbstractSlider( parent )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
setScaleDraw( new QwtRoundScaleDraw() );
|
||||
|
||||
setTotalAngle( 270.0 );
|
||||
|
||||
setScale( 0.0, 10.0 );
|
||||
setValue( 0.0 );
|
||||
|
||||
setSizePolicy( QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::MinimumExpanding );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtKnob::~QwtKnob()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the knob type
|
||||
|
||||
\param knobStyle Knob type
|
||||
\sa knobStyle(), setBorderWidth()
|
||||
*/
|
||||
void QwtKnob::setKnobStyle( KnobStyle knobStyle )
|
||||
{
|
||||
if ( d_data->knobStyle != knobStyle )
|
||||
{
|
||||
d_data->knobStyle = knobStyle;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Marker type of the knob
|
||||
\sa setKnobStyle(), setBorderWidth()
|
||||
*/
|
||||
QwtKnob::KnobStyle QwtKnob::knobStyle() const
|
||||
{
|
||||
return d_data->knobStyle;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the marker type of the knob
|
||||
|
||||
\param markerStyle Marker type
|
||||
\sa markerStyle(), setMarkerSize()
|
||||
*/
|
||||
void QwtKnob::setMarkerStyle( MarkerStyle markerStyle )
|
||||
{
|
||||
if ( d_data->markerStyle != markerStyle )
|
||||
{
|
||||
d_data->markerStyle = markerStyle;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Marker type of the knob
|
||||
\sa setMarkerStyle(), setMarkerSize()
|
||||
*/
|
||||
QwtKnob::MarkerStyle QwtKnob::markerStyle() const
|
||||
{
|
||||
return d_data->markerStyle;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the total angle by which the knob can be turned
|
||||
\param angle Angle in degrees.
|
||||
|
||||
The angle has to be between [10, 360] degrees. Angles above
|
||||
360 ( so that the knob can be turned several times around its axis )
|
||||
have to be set using setNumTurns().
|
||||
|
||||
The default angle is 270 degrees.
|
||||
|
||||
\sa totalAngle(), setNumTurns()
|
||||
*/
|
||||
void QwtKnob::setTotalAngle ( double angle )
|
||||
{
|
||||
angle = qBound( 10.0, angle, 360.0 );
|
||||
|
||||
if ( angle != d_data->totalAngle )
|
||||
{
|
||||
d_data->totalAngle = angle;
|
||||
|
||||
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
|
||||
0.5 * d_data->totalAngle );
|
||||
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the total angle
|
||||
\sa setTotalAngle(), setNumTurns(), numTurns()
|
||||
*/
|
||||
double QwtKnob::totalAngle() const
|
||||
{
|
||||
return d_data->totalAngle;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the number of turns
|
||||
|
||||
When numTurns > 1 the knob can be turned several times around its axis
|
||||
- otherwise the total angle is floored to 360°.
|
||||
|
||||
\sa numTurns(), totalAngle(), setTotalAngle()
|
||||
*/
|
||||
|
||||
void QwtKnob::setNumTurns( int numTurns )
|
||||
{
|
||||
numTurns = qMax( numTurns, 1 );
|
||||
|
||||
if ( numTurns == 1 && d_data->totalAngle <= 360.0 )
|
||||
return;
|
||||
|
||||
const double angle = numTurns * 360.0;
|
||||
if ( angle != d_data->totalAngle )
|
||||
{
|
||||
d_data->totalAngle = angle;
|
||||
|
||||
scaleDraw()->setAngleRange( -0.5 * d_data->totalAngle,
|
||||
0.5 * d_data->totalAngle );
|
||||
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of turns.
|
||||
|
||||
When the total angle is below 360° numTurns() is ceiled to 1.
|
||||
\sa setNumTurns(), setTotalAngle(), totalAngle()
|
||||
*/
|
||||
int QwtKnob::numTurns() const
|
||||
{
|
||||
return qCeil( d_data->totalAngle / 360.0 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the scale draw of the knob
|
||||
|
||||
For changing the labels of the scales, it
|
||||
is necessary to derive from QwtRoundScaleDraw and
|
||||
overload QwtRoundScaleDraw::label().
|
||||
|
||||
\sa scaleDraw()
|
||||
*/
|
||||
void QwtKnob::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
|
||||
{
|
||||
setAbstractScaleDraw( scaleDraw );
|
||||
setTotalAngle( d_data->totalAngle );
|
||||
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the scale draw of the knob
|
||||
\sa setScaleDraw()
|
||||
*/
|
||||
const QwtRoundScaleDraw *QwtKnob::scaleDraw() const
|
||||
{
|
||||
return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the scale draw of the knob
|
||||
\sa setScaleDraw()
|
||||
*/
|
||||
QwtRoundScaleDraw *QwtKnob::scaleDraw()
|
||||
{
|
||||
return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
|
||||
}
|
||||
|
||||
/*!
|
||||
Calculate the bounding rectangle of the knob without the scale
|
||||
|
||||
\return Bounding rectangle of the knob
|
||||
\sa knobWidth(), alignment(), QWidget::contentsRect()
|
||||
*/
|
||||
QRect QwtKnob::knobRect() const
|
||||
{
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
const int extent = qCeil( scaleDraw()->extent( font() ) );
|
||||
const int d = extent + d_data->scaleDist;
|
||||
|
||||
int w = d_data->knobWidth;
|
||||
if ( w <= 0 )
|
||||
{
|
||||
const int dim = qMin( cr.width(), cr.height() );
|
||||
|
||||
w = dim - 2 * ( d );
|
||||
w = qMax( 0, w );
|
||||
}
|
||||
|
||||
QRect r( 0, 0, w, w );
|
||||
|
||||
if ( d_data->alignment & Qt::AlignLeft )
|
||||
{
|
||||
r.moveLeft( cr.left() + d );
|
||||
}
|
||||
else if ( d_data->alignment & Qt::AlignRight )
|
||||
{
|
||||
r.moveRight( cr.right() - d );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.moveCenter( QPoint( cr.center().x(), r.center().y() ) );
|
||||
}
|
||||
|
||||
if ( d_data->alignment & Qt::AlignTop )
|
||||
{
|
||||
r.moveTop( cr.top() + d );
|
||||
}
|
||||
else if ( d_data->alignment & Qt::AlignBottom )
|
||||
{
|
||||
r.moveBottom( cr.bottom() - d );
|
||||
}
|
||||
else
|
||||
{
|
||||
r.moveCenter( QPoint( r.center().x(), cr.center().y() ) );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Determine what to do when the user presses a mouse button.
|
||||
|
||||
\param pos Mouse position
|
||||
|
||||
\retval True, when pos is inside the circle of the knob.
|
||||
\sa scrolledTo()
|
||||
*/
|
||||
bool QwtKnob::isScrollPosition( const QPoint &pos ) const
|
||||
{
|
||||
const QRect kr = knobRect();
|
||||
|
||||
const QRegion region( kr, QRegion::Ellipse );
|
||||
if ( region.contains( pos ) && ( pos != kr.center() ) )
|
||||
{
|
||||
const double angle = QLineF( kr.center(), pos ).angle();
|
||||
const double valueAngle = qwtToDegrees( scaleMap().transform( value() ) );
|
||||
|
||||
d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Determine the value for a new position of the mouse
|
||||
|
||||
\param pos Mouse position
|
||||
|
||||
\return Value for the mouse position
|
||||
\sa isScrollPosition()
|
||||
*/
|
||||
double QwtKnob::scrolledTo( const QPoint &pos ) const
|
||||
{
|
||||
double angle = QLineF( rect().center(), pos ).angle();
|
||||
angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
|
||||
|
||||
if ( scaleMap().pDist() > 360.0 )
|
||||
{
|
||||
angle = qwtToDegrees( angle );
|
||||
|
||||
const double v = scaleMap().transform( value() );
|
||||
|
||||
int numTurns = qFloor( ( v - scaleMap().p1() ) / 360.0 );
|
||||
|
||||
double valueAngle = qwtNormalizeDegrees( v );
|
||||
if ( qAbs( valueAngle - angle ) > 180.0 )
|
||||
{
|
||||
numTurns += ( angle > valueAngle ) ? -1 : 1;
|
||||
}
|
||||
|
||||
angle += scaleMap().p1() + numTurns * 360.0;
|
||||
|
||||
if ( !wrapping() )
|
||||
{
|
||||
const double boundedAngle =
|
||||
qBound( scaleMap().p1(), angle, scaleMap().p2() );
|
||||
|
||||
d_data->mouseOffset += ( boundedAngle - angle );
|
||||
angle = boundedAngle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = qwtToScaleAngle( angle );
|
||||
|
||||
double boundedAngle = qBound( scaleMap().p1(), angle, scaleMap().p2() );
|
||||
|
||||
if ( !wrapping() )
|
||||
{
|
||||
const double currentAngle = scaleMap().transform( value() );
|
||||
|
||||
if ( ( currentAngle > 90.0 ) && ( boundedAngle < -90.0 ) )
|
||||
boundedAngle = scaleMap().p2();
|
||||
else if ( ( currentAngle < -90.0 ) && ( boundedAngle > 90.0 ) )
|
||||
boundedAngle = scaleMap().p1();
|
||||
|
||||
d_data->mouseOffset += ( boundedAngle - angle );
|
||||
}
|
||||
|
||||
angle = boundedAngle;
|
||||
}
|
||||
|
||||
return scaleMap().invTransform( angle );
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle QEvent::StyleChange and QEvent::FontChange;
|
||||
\param event Change event
|
||||
*/
|
||||
void QwtKnob::changeEvent( QEvent *event )
|
||||
{
|
||||
switch( event->type() )
|
||||
{
|
||||
case QEvent::StyleChange:
|
||||
case QEvent::FontChange:
|
||||
{
|
||||
updateGeometry();
|
||||
update();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Repaint the knob
|
||||
\param event Paint event
|
||||
*/
|
||||
void QwtKnob::paintEvent( QPaintEvent *event )
|
||||
{
|
||||
const QRectF knobRect = this->knobRect();
|
||||
|
||||
QPainter painter( this );
|
||||
painter.setClipRegion( event->region() );
|
||||
|
||||
QStyleOption opt;
|
||||
opt.init(this);
|
||||
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||
|
||||
painter.setRenderHint( QPainter::Antialiasing, true );
|
||||
|
||||
if ( !knobRect.contains( event->region().boundingRect() ) )
|
||||
{
|
||||
scaleDraw()->setRadius( 0.5 * knobRect.width() + d_data->scaleDist );
|
||||
scaleDraw()->moveCenter( knobRect.center() );
|
||||
|
||||
scaleDraw()->draw( &painter, palette() );
|
||||
}
|
||||
|
||||
drawKnob( &painter, knobRect );
|
||||
|
||||
drawMarker( &painter, knobRect,
|
||||
qwtNormalizeDegrees( scaleMap().transform( value() ) ) );
|
||||
|
||||
painter.setRenderHint( QPainter::Antialiasing, false );
|
||||
|
||||
if ( hasFocus() )
|
||||
drawFocusIndicator( &painter );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Draw the knob
|
||||
|
||||
\param painter painter
|
||||
\param knobRect Bounding rectangle of the knob (without scale)
|
||||
*/
|
||||
void QwtKnob::drawKnob( QPainter *painter, const QRectF &knobRect ) const
|
||||
{
|
||||
double dim = qMin( knobRect.width(), knobRect.height() );
|
||||
dim -= d_data->borderWidth * 0.5;
|
||||
|
||||
QRectF aRect( 0, 0, dim, dim );
|
||||
aRect.moveCenter( knobRect.center() );
|
||||
|
||||
QPen pen( Qt::NoPen );
|
||||
if ( d_data->borderWidth > 0 )
|
||||
{
|
||||
QColor c1 = palette().color( QPalette::Light );
|
||||
QColor c2 = palette().color( QPalette::Dark );
|
||||
|
||||
QLinearGradient gradient( aRect.topLeft(), aRect.bottomRight() );
|
||||
gradient.setColorAt( 0.0, c1 );
|
||||
gradient.setColorAt( 0.3, c1 );
|
||||
gradient.setColorAt( 0.7, c2 );
|
||||
gradient.setColorAt( 1.0, c2 );
|
||||
|
||||
pen = QPen( gradient, d_data->borderWidth );
|
||||
}
|
||||
|
||||
QBrush brush;
|
||||
switch( d_data->knobStyle )
|
||||
{
|
||||
case QwtKnob::Raised:
|
||||
{
|
||||
double off = 0.3 * knobRect.width();
|
||||
QRadialGradient gradient( knobRect.center(),
|
||||
knobRect.width(), knobRect.topLeft() + QPointF( off, off ) );
|
||||
|
||||
gradient.setColorAt( 0.0, palette().color( QPalette::Midlight ) );
|
||||
gradient.setColorAt( 1.0, palette().color( QPalette::Button ) );
|
||||
|
||||
brush = QBrush( gradient );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtKnob::Styled:
|
||||
{
|
||||
QRadialGradient gradient(knobRect.center().x() - knobRect.width() / 3,
|
||||
knobRect.center().y() - knobRect.height() / 2,
|
||||
knobRect.width() * 1.3,
|
||||
knobRect.center().x(),
|
||||
knobRect.center().y() - knobRect.height() / 2);
|
||||
|
||||
const QColor c = palette().color( QPalette::Button );
|
||||
gradient.setColorAt(0, c.lighter(110));
|
||||
gradient.setColorAt(qreal(0.5), c);
|
||||
gradient.setColorAt(qreal(0.501), c.darker(102));
|
||||
gradient.setColorAt(1, c.darker(115));
|
||||
|
||||
brush = QBrush( gradient );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtKnob::Sunken:
|
||||
{
|
||||
QLinearGradient gradient(
|
||||
knobRect.topLeft(), knobRect.bottomRight() );
|
||||
gradient.setColorAt( 0.0, palette().color( QPalette::Mid ) );
|
||||
gradient.setColorAt( 0.5, palette().color( QPalette::Button ) );
|
||||
gradient.setColorAt( 1.0, palette().color( QPalette::Midlight ) );
|
||||
brush = QBrush( gradient );
|
||||
|
||||
break;
|
||||
}
|
||||
case QwtKnob::Flat:
|
||||
default:
|
||||
brush = palette().brush( QPalette::Button );
|
||||
}
|
||||
|
||||
painter->setPen( pen );
|
||||
painter->setBrush( brush );
|
||||
painter->drawEllipse( aRect );
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Draw the marker at the knob's front
|
||||
|
||||
\param painter Painter
|
||||
\param rect Bounding rectangle of the knob without scale
|
||||
\param angle Angle of the marker in degrees
|
||||
( clockwise, 0 at the 12 o'clock position )
|
||||
*/
|
||||
void QwtKnob::drawMarker( QPainter *painter,
|
||||
const QRectF &rect, double angle ) const
|
||||
{
|
||||
if ( d_data->markerStyle == NoMarker || !isValid() )
|
||||
return;
|
||||
|
||||
const double radians = qwtRadians( angle );
|
||||
const double sinA = -qFastSin( radians );
|
||||
const double cosA = qFastCos( radians );
|
||||
|
||||
const double xm = rect.center().x();
|
||||
const double ym = rect.center().y();
|
||||
const double margin = 4.0;
|
||||
|
||||
double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
|
||||
if ( radius < 1.0 )
|
||||
radius = 1.0;
|
||||
|
||||
int markerSize = d_data->markerSize;
|
||||
if ( markerSize <= 0 )
|
||||
markerSize = qRound( 0.4 * radius );
|
||||
|
||||
switch ( d_data->markerStyle )
|
||||
{
|
||||
case Notch:
|
||||
case Nub:
|
||||
{
|
||||
const double dotWidth =
|
||||
qMin( double( markerSize ), radius);
|
||||
|
||||
const double dotCenterDist = radius - 0.5 * dotWidth;
|
||||
if ( dotCenterDist > 0.0 )
|
||||
{
|
||||
const QPointF center( xm - sinA * dotCenterDist,
|
||||
ym - cosA * dotCenterDist );
|
||||
|
||||
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
|
||||
ellipse.moveCenter( center );
|
||||
|
||||
QColor c1 = palette().color( QPalette::Light );
|
||||
QColor c2 = palette().color( QPalette::Mid );
|
||||
|
||||
if ( d_data->markerStyle == Notch )
|
||||
qSwap( c1, c2 );
|
||||
|
||||
QLinearGradient gradient(
|
||||
ellipse.topLeft(), ellipse.bottomRight() );
|
||||
gradient.setColorAt( 0.0, c1 );
|
||||
gradient.setColorAt( 1.0, c2 );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( gradient );
|
||||
|
||||
painter->drawEllipse( ellipse );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Dot:
|
||||
{
|
||||
const double dotWidth =
|
||||
qMin( double( markerSize ), radius);
|
||||
|
||||
const double dotCenterDist = radius - 0.5 * dotWidth;
|
||||
if ( dotCenterDist > 0.0 )
|
||||
{
|
||||
const QPointF center( xm - sinA * dotCenterDist,
|
||||
ym - cosA * dotCenterDist );
|
||||
|
||||
QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
|
||||
ellipse.moveCenter( center );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( palette().color( QPalette::ButtonText ) );
|
||||
painter->drawEllipse( ellipse );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Tick:
|
||||
{
|
||||
const double rb = qMax( radius - markerSize, 1.0 );
|
||||
const double re = radius;
|
||||
|
||||
const QLineF line( xm - sinA * rb, ym - cosA * rb,
|
||||
xm - sinA * re, ym - cosA * re );
|
||||
|
||||
QPen pen( palette().color( QPalette::ButtonText ), 0 );
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
painter->setPen( pen );
|
||||
painter->drawLine ( line );
|
||||
|
||||
break;
|
||||
}
|
||||
case Triangle:
|
||||
{
|
||||
const double rb = qMax( radius - markerSize, 1.0 );
|
||||
const double re = radius;
|
||||
|
||||
painter->translate( rect.center() );
|
||||
painter->rotate( angle - 90.0 );
|
||||
|
||||
QPolygonF polygon;
|
||||
polygon += QPointF( re, 0.0 );
|
||||
polygon += QPointF( rb, 0.5 * ( re - rb ) );
|
||||
polygon += QPointF( rb, -0.5 * ( re - rb ) );
|
||||
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( palette().color( QPalette::ButtonText ) );
|
||||
painter->drawPolygon( polygon );
|
||||
|
||||
painter->resetTransform();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the focus indicator
|
||||
\param painter Painter
|
||||
*/
|
||||
void QwtKnob::drawFocusIndicator( QPainter *painter ) const
|
||||
{
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
int w = d_data->knobWidth;
|
||||
if ( w <= 0 )
|
||||
{
|
||||
w = qMin( cr.width(), cr.height() );
|
||||
}
|
||||
else
|
||||
{
|
||||
const int extent = qCeil( scaleDraw()->extent( font() ) );
|
||||
w += 2 * ( extent + d_data->scaleDist );
|
||||
}
|
||||
|
||||
QRect focusRect( 0, 0, w, w );
|
||||
focusRect.moveCenter( cr.center() );
|
||||
|
||||
QwtPainter::drawFocusRect( painter, this, focusRect );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the alignment of the knob
|
||||
|
||||
Similar to a QLabel::alignment() the flags decide how
|
||||
to align the knob inside of contentsRect().
|
||||
|
||||
The default setting is Qt::AlignCenter
|
||||
|
||||
\param alignment Or'd alignment flags
|
||||
|
||||
\sa alignment(), setKnobWidth(), knobRect()
|
||||
*/
|
||||
void QwtKnob::setAlignment( Qt::Alignment alignment )
|
||||
{
|
||||
if ( d_data->alignment != alignment )
|
||||
{
|
||||
d_data->alignment = alignment;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Alignment of the knob inside of contentsRect()
|
||||
\sa setAlignment(), knobWidth(), knobRect()
|
||||
*/
|
||||
Qt::Alignment QwtKnob::alignment() const
|
||||
{
|
||||
return d_data->alignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the knob's width.
|
||||
|
||||
Setting a fixed value for the diameter of the knob
|
||||
is helpful for aligning several knobs in a row.
|
||||
|
||||
\param width New width
|
||||
|
||||
\sa knobWidth(), setAlignment()
|
||||
\note Modifies the sizePolicy()
|
||||
*/
|
||||
void QwtKnob::setKnobWidth( int width )
|
||||
{
|
||||
width = qMax( width, 0 );
|
||||
|
||||
if ( width != d_data->knobWidth )
|
||||
{
|
||||
QSizePolicy::Policy policy;
|
||||
if ( width > 0 )
|
||||
policy = QSizePolicy::Minimum;
|
||||
else
|
||||
policy = QSizePolicy::MinimumExpanding;
|
||||
|
||||
setSizePolicy( policy, policy );
|
||||
|
||||
d_data->knobWidth = width;
|
||||
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
//! Return the width of the knob
|
||||
int QwtKnob::knobWidth() const
|
||||
{
|
||||
return d_data->knobWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the knob's border width
|
||||
\param borderWidth new border width
|
||||
*/
|
||||
void QwtKnob::setBorderWidth( int borderWidth )
|
||||
{
|
||||
d_data->borderWidth = qMax( borderWidth, 0 );
|
||||
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
//! Return the border width
|
||||
int QwtKnob::borderWidth() const
|
||||
{
|
||||
return d_data->borderWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the size of the marker
|
||||
|
||||
When setting a size <= 0 the marker will
|
||||
automatically scaled to 40% of the radius of the knob.
|
||||
|
||||
\sa markerSize(), markerStyle()
|
||||
*/
|
||||
void QwtKnob::setMarkerSize( int size )
|
||||
{
|
||||
if ( d_data->markerSize != size )
|
||||
{
|
||||
d_data->markerSize = size;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Marker size
|
||||
\sa setMarkerSize()
|
||||
*/
|
||||
int QwtKnob::markerSize() const
|
||||
{
|
||||
return d_data->markerSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return sizeHint()
|
||||
*/
|
||||
QSize QwtKnob::sizeHint() const
|
||||
{
|
||||
const QSize hint = qwtKnobSizeHint( this, 50 );
|
||||
return hint.expandedTo( QApplication::globalStrut() );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Minimum size hint
|
||||
\sa sizeHint()
|
||||
*/
|
||||
QSize QwtKnob::minimumSizeHint() const
|
||||
{
|
||||
return qwtKnobSizeHint( this, 20 );
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_KNOB_H
|
||||
#define QWT_KNOB_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_abstract_slider.h"
|
||||
|
||||
class QwtRoundScaleDraw;
|
||||
|
||||
/*!
|
||||
\brief The Knob Widget
|
||||
|
||||
The QwtKnob widget imitates look and behavior of a volume knob on a radio.
|
||||
It looks similar to QDial - not to QwtDial.
|
||||
|
||||
The value range of a knob might be divided into several turns.
|
||||
|
||||
The layout of the knob depends on the knobWidth().
|
||||
|
||||
- width > 0
|
||||
The diameter of the knob is fixed and the knob is aligned
|
||||
according to the alignment() flags inside of the contentsRect().
|
||||
|
||||
- width <= 0
|
||||
The knob is extended to the minimum of width/height of the contentsRect()
|
||||
and aligned in the other direction according to alignment().
|
||||
|
||||
Setting a fixed knobWidth() is helpful to align several knobs with different
|
||||
scale labels.
|
||||
|
||||
\image html knob.png
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtKnob: public QwtAbstractSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS ( KnobStyle MarkerStyle )
|
||||
|
||||
Q_PROPERTY( KnobStyle knobStyle READ knobStyle WRITE setKnobStyle )
|
||||
Q_PROPERTY( int knobWidth READ knobWidth WRITE setKnobWidth )
|
||||
Q_PROPERTY( Qt::Alignment alignment READ alignment WRITE setAlignment )
|
||||
Q_PROPERTY( double totalAngle READ totalAngle WRITE setTotalAngle )
|
||||
Q_PROPERTY( int numTurns READ numTurns WRITE setNumTurns )
|
||||
Q_PROPERTY( MarkerStyle markerStyle READ markerStyle WRITE setMarkerStyle )
|
||||
Q_PROPERTY( int markerSize READ markerSize WRITE setMarkerSize )
|
||||
Q_PROPERTY( int borderWidth READ borderWidth WRITE setBorderWidth )
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Style of the knob surface
|
||||
|
||||
Depending on the KnobStyle the surface of the knob is
|
||||
filled from the brushes of the widget palette().
|
||||
|
||||
\sa setKnobStyle(), knobStyle()
|
||||
*/
|
||||
enum KnobStyle
|
||||
{
|
||||
//! Fill the knob with a brush from QPalette::Button.
|
||||
Flat,
|
||||
|
||||
//! Build a gradient from QPalette::Midlight and QPalette::Button
|
||||
Raised,
|
||||
|
||||
/*!
|
||||
Build a gradient from QPalette::Midlight, QPalette::Button
|
||||
and QPalette::Midlight
|
||||
*/
|
||||
Sunken,
|
||||
|
||||
/*!
|
||||
Build a radial gradient from QPalette::Button
|
||||
like it is used for QDial in various Qt styles.
|
||||
*/
|
||||
Styled
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Marker type
|
||||
|
||||
The marker indicates the current value on the knob
|
||||
The default setting is a Notch marker.
|
||||
|
||||
\sa setMarkerStyle(), setMarkerSize()
|
||||
*/
|
||||
enum MarkerStyle
|
||||
{
|
||||
//! Don't paint any marker
|
||||
NoMarker = -1,
|
||||
|
||||
//! Paint a single tick in QPalette::ButtonText color
|
||||
Tick,
|
||||
|
||||
//! Paint a triangle in QPalette::ButtonText color
|
||||
Triangle,
|
||||
|
||||
//! Paint a circle in QPalette::ButtonText color
|
||||
Dot,
|
||||
|
||||
/*!
|
||||
Draw a raised ellipse with a gradient build from
|
||||
QPalette::Light and QPalette::Mid
|
||||
*/
|
||||
Nub,
|
||||
|
||||
/*!
|
||||
Draw a sunken ellipse with a gradient build from
|
||||
QPalette::Light and QPalette::Mid
|
||||
*/
|
||||
Notch
|
||||
};
|
||||
|
||||
explicit QwtKnob( QWidget* parent = NULL );
|
||||
virtual ~QwtKnob();
|
||||
|
||||
void setAlignment( Qt::Alignment );
|
||||
Qt::Alignment alignment() const;
|
||||
|
||||
void setKnobWidth( int );
|
||||
int knobWidth() const;
|
||||
|
||||
void setNumTurns( int );
|
||||
int numTurns() const;
|
||||
|
||||
void setTotalAngle ( double angle );
|
||||
double totalAngle() const;
|
||||
|
||||
void setKnobStyle( KnobStyle );
|
||||
KnobStyle knobStyle() const;
|
||||
|
||||
void setBorderWidth( int bw );
|
||||
int borderWidth() const;
|
||||
|
||||
void setMarkerStyle( MarkerStyle );
|
||||
MarkerStyle markerStyle() const;
|
||||
|
||||
void setMarkerSize( int );
|
||||
int markerSize() const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
|
||||
void setScaleDraw( QwtRoundScaleDraw * );
|
||||
|
||||
const QwtRoundScaleDraw *scaleDraw() const;
|
||||
QwtRoundScaleDraw *scaleDraw();
|
||||
|
||||
QRect knobRect() const;
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
virtual void changeEvent( QEvent * );
|
||||
|
||||
virtual void drawKnob( QPainter *, const QRectF & ) const;
|
||||
|
||||
virtual void drawFocusIndicator( QPainter * ) const;
|
||||
|
||||
virtual void drawMarker( QPainter *,
|
||||
const QRectF &, double arc ) const;
|
||||
|
||||
virtual double scrolledTo( const QPoint & ) const;
|
||||
virtual bool isScrollPosition( const QPoint & ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,811 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_legend.h"
|
||||
#include "qwt_legend_label.h"
|
||||
#include "qwt_dyngrid_layout.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_plot_item.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qapplication.h>
|
||||
#include <qscrollbar.h>
|
||||
#include <qscrollarea.h>
|
||||
#include <qpainter.h>
|
||||
#include <qstyle.h>
|
||||
#include <qstyleoption.h>
|
||||
|
||||
class QwtLegendMap
|
||||
{
|
||||
public:
|
||||
inline bool isEmpty() const { return d_entries.isEmpty(); }
|
||||
|
||||
void insert( const QVariant &, const QList<QWidget *> & );
|
||||
void remove( const QVariant & );
|
||||
|
||||
void removeWidget( const QWidget * );
|
||||
|
||||
QList<QWidget *> legendWidgets( const QVariant & ) const;
|
||||
QVariant itemInfo( const QWidget * ) const;
|
||||
|
||||
private:
|
||||
// we don't know anything about itemInfo and therefore don't have
|
||||
// any key that can be used for a map or hashtab.
|
||||
// But a simple linear list is o.k. here, as we will never have
|
||||
// more than a few entries.
|
||||
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
QVariant itemInfo;
|
||||
QList<QWidget *> widgets;
|
||||
};
|
||||
|
||||
QList< Entry > d_entries;
|
||||
};
|
||||
|
||||
void QwtLegendMap::insert( const QVariant &itemInfo,
|
||||
const QList<QWidget *> &widgets )
|
||||
{
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
{
|
||||
Entry &entry = d_entries[i];
|
||||
if ( entry.itemInfo == itemInfo )
|
||||
{
|
||||
entry.widgets = widgets;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Entry newEntry;
|
||||
newEntry.itemInfo = itemInfo;
|
||||
newEntry.widgets = widgets;
|
||||
|
||||
d_entries += newEntry;
|
||||
}
|
||||
|
||||
void QwtLegendMap::remove( const QVariant &itemInfo )
|
||||
{
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
{
|
||||
Entry &entry = d_entries[i];
|
||||
if ( entry.itemInfo == itemInfo )
|
||||
{
|
||||
d_entries.removeAt( i );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QwtLegendMap::removeWidget( const QWidget *widget )
|
||||
{
|
||||
QWidget *w = const_cast<QWidget *>( widget );
|
||||
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
d_entries[ i ].widgets.removeAll( w );
|
||||
}
|
||||
|
||||
QVariant QwtLegendMap::itemInfo( const QWidget *widget ) const
|
||||
{
|
||||
if ( widget != NULL )
|
||||
{
|
||||
QWidget *w = const_cast<QWidget *>( widget );
|
||||
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
{
|
||||
const Entry &entry = d_entries[i];
|
||||
if ( entry.widgets.indexOf( w ) >= 0 )
|
||||
return entry.itemInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QList<QWidget *> QwtLegendMap::legendWidgets( const QVariant &itemInfo ) const
|
||||
{
|
||||
if ( itemInfo.isValid() )
|
||||
{
|
||||
for ( int i = 0; i < d_entries.size(); i++ )
|
||||
{
|
||||
const Entry &entry = d_entries[i];
|
||||
if ( entry.itemInfo == itemInfo )
|
||||
return entry.widgets;
|
||||
}
|
||||
}
|
||||
|
||||
return QList<QWidget *>();
|
||||
}
|
||||
|
||||
class QwtLegend::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
itemMode( QwtLegendData::ReadOnly ),
|
||||
view( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
QwtLegendData::Mode itemMode;
|
||||
QwtLegendMap itemMap;
|
||||
|
||||
class LegendView;
|
||||
LegendView *view;
|
||||
};
|
||||
|
||||
class QwtLegend::PrivateData::LegendView: public QScrollArea
|
||||
{
|
||||
public:
|
||||
LegendView( QWidget *parent ):
|
||||
QScrollArea( parent )
|
||||
{
|
||||
contentsWidget = new QWidget( this );
|
||||
contentsWidget->setObjectName( "QwtLegendViewContents" );
|
||||
|
||||
setWidget( contentsWidget );
|
||||
setWidgetResizable( false );
|
||||
|
||||
viewport()->setObjectName( "QwtLegendViewport" );
|
||||
|
||||
// QScrollArea::setWidget internally sets autoFillBackground to true
|
||||
// But we don't want a background.
|
||||
contentsWidget->setAutoFillBackground( false );
|
||||
viewport()->setAutoFillBackground( false );
|
||||
}
|
||||
|
||||
virtual bool event( QEvent *event )
|
||||
{
|
||||
if ( event->type() == QEvent::PolishRequest )
|
||||
{
|
||||
setFocusPolicy( Qt::NoFocus );
|
||||
}
|
||||
|
||||
if ( event->type() == QEvent::Resize )
|
||||
{
|
||||
// adjust the size to en/disable the scrollbars
|
||||
// before QScrollArea adjusts the viewport size
|
||||
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
int w = cr.width();
|
||||
int h = contentsWidget->heightForWidth( cr.width() );
|
||||
if ( h > w )
|
||||
{
|
||||
w -= verticalScrollBar()->sizeHint().width();
|
||||
h = contentsWidget->heightForWidth( w );
|
||||
}
|
||||
|
||||
contentsWidget->resize( w, h );
|
||||
}
|
||||
|
||||
return QScrollArea::event( event );
|
||||
}
|
||||
|
||||
virtual bool viewportEvent( QEvent *event )
|
||||
{
|
||||
bool ok = QScrollArea::viewportEvent( event );
|
||||
|
||||
if ( event->type() == QEvent::Resize )
|
||||
{
|
||||
layoutContents();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
QSize viewportSize( int w, int h ) const
|
||||
{
|
||||
const int sbHeight = horizontalScrollBar()->sizeHint().height();
|
||||
const int sbWidth = verticalScrollBar()->sizeHint().width();
|
||||
|
||||
const int cw = contentsRect().width();
|
||||
const int ch = contentsRect().height();
|
||||
|
||||
int vw = cw;
|
||||
int vh = ch;
|
||||
|
||||
if ( w > vw )
|
||||
vh -= sbHeight;
|
||||
|
||||
if ( h > vh )
|
||||
{
|
||||
vw -= sbWidth;
|
||||
if ( w > vw && vh == ch )
|
||||
vh -= sbHeight;
|
||||
}
|
||||
return QSize( vw, vh );
|
||||
}
|
||||
|
||||
void layoutContents()
|
||||
{
|
||||
const QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||
contentsWidget->layout() );
|
||||
if ( tl == NULL )
|
||||
return;
|
||||
|
||||
const QSize visibleSize = viewport()->contentsRect().size();
|
||||
|
||||
const int minW = int( tl->maxItemWidth() ) + 2 * tl->margin();
|
||||
|
||||
int w = qMax( visibleSize.width(), minW );
|
||||
int h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||
|
||||
const int vpWidth = viewportSize( w, h ).width();
|
||||
if ( w > vpWidth )
|
||||
{
|
||||
w = qMax( vpWidth, minW );
|
||||
h = qMax( tl->heightForWidth( w ), visibleSize.height() );
|
||||
}
|
||||
|
||||
contentsWidget->resize( w, h );
|
||||
}
|
||||
|
||||
QWidget *contentsWidget;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param parent Parent widget
|
||||
*/
|
||||
QwtLegend::QwtLegend( QWidget *parent ):
|
||||
QwtAbstractLegend( parent )
|
||||
{
|
||||
setFrameStyle( NoFrame );
|
||||
|
||||
d_data = new QwtLegend::PrivateData;
|
||||
|
||||
d_data->view = new QwtLegend::PrivateData::LegendView( this );
|
||||
d_data->view->setObjectName( "QwtLegendView" );
|
||||
d_data->view->setFrameStyle( NoFrame );
|
||||
|
||||
QwtDynGridLayout *gridLayout = new QwtDynGridLayout(
|
||||
d_data->view->contentsWidget );
|
||||
gridLayout->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
|
||||
|
||||
d_data->view->contentsWidget->installEventFilter( this );
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout( this );
|
||||
layout->setContentsMargins( 0, 0, 0, 0 );
|
||||
layout->addWidget( d_data->view );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtLegend::~QwtLegend()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the maximum number of entries in a row
|
||||
|
||||
F.e when the maximum is set to 1 all items are aligned
|
||||
vertically. 0 means unlimited
|
||||
|
||||
\param numColums Maximum number of entries in a row
|
||||
|
||||
\sa maxColumns(), QwtDynGridLayout::setMaxColumns()
|
||||
*/
|
||||
void QwtLegend::setMaxColumns( uint numColums )
|
||||
{
|
||||
QwtDynGridLayout *tl = qobject_cast<QwtDynGridLayout *>(
|
||||
d_data->view->contentsWidget->layout() );
|
||||
if ( tl )
|
||||
tl->setMaxColumns( numColums );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Maximum number of entries in a row
|
||||
\sa setMaxColumns(), QwtDynGridLayout::maxColumns()
|
||||
*/
|
||||
uint QwtLegend::maxColumns() const
|
||||
{
|
||||
uint maxCols = 0;
|
||||
|
||||
const QwtDynGridLayout *tl = qobject_cast<const QwtDynGridLayout *>(
|
||||
d_data->view->contentsWidget->layout() );
|
||||
if ( tl )
|
||||
maxCols = tl->maxColumns();
|
||||
|
||||
return maxCols;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the default mode for legend labels
|
||||
|
||||
Legend labels will be constructed according to the
|
||||
attributes in a QwtLegendData object. When it doesn't
|
||||
contain a value for the QwtLegendData::ModeRole the
|
||||
label will be initialized with the default mode of the legend.
|
||||
|
||||
\param mode Default item mode
|
||||
|
||||
\sa itemMode(), QwtLegendData::value(), QwtPlotItem::legendData()
|
||||
\note Changing the mode doesn't have any effect on existing labels.
|
||||
*/
|
||||
void QwtLegend::setDefaultItemMode( QwtLegendData::Mode mode )
|
||||
{
|
||||
d_data->itemMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Default item mode
|
||||
\sa setDefaultItemMode()
|
||||
*/
|
||||
QwtLegendData::Mode QwtLegend::defaultItemMode() const
|
||||
{
|
||||
return d_data->itemMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
The contents widget is the only child of the viewport of
|
||||
the internal QScrollArea and the parent widget of all legend items.
|
||||
|
||||
\return Container widget of the legend items
|
||||
*/
|
||||
QWidget *QwtLegend::contentsWidget()
|
||||
{
|
||||
return d_data->view->contentsWidget;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Horizontal scrollbar
|
||||
\sa verticalScrollBar()
|
||||
*/
|
||||
QScrollBar *QwtLegend::horizontalScrollBar() const
|
||||
{
|
||||
return d_data->view->horizontalScrollBar();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Vertical scrollbar
|
||||
\sa horizontalScrollBar()
|
||||
*/
|
||||
QScrollBar *QwtLegend::verticalScrollBar() const
|
||||
{
|
||||
return d_data->view->verticalScrollBar();
|
||||
}
|
||||
|
||||
/*!
|
||||
The contents widget is the only child of the viewport of
|
||||
the internal QScrollArea and the parent widget of all legend items.
|
||||
|
||||
\return Container widget of the legend items
|
||||
|
||||
*/
|
||||
const QWidget *QwtLegend::contentsWidget() const
|
||||
{
|
||||
return d_data->view->contentsWidget;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Update the entries for an item
|
||||
|
||||
\param itemInfo Info for an item
|
||||
\param data List of legend entry attributes for the item
|
||||
*/
|
||||
void QwtLegend::updateLegend( const QVariant &itemInfo,
|
||||
const QList<QwtLegendData> &data )
|
||||
{
|
||||
QList<QWidget *> widgetList = legendWidgets( itemInfo );
|
||||
|
||||
if ( widgetList.size() != data.size() )
|
||||
{
|
||||
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||
|
||||
while ( widgetList.size() > data.size() )
|
||||
{
|
||||
QWidget *w = widgetList.takeLast();
|
||||
|
||||
contentsLayout->removeWidget( w );
|
||||
|
||||
// updates might be triggered by signals from the legend widget
|
||||
// itself. So we better don't delete it here.
|
||||
|
||||
w->hide();
|
||||
w->deleteLater();
|
||||
}
|
||||
|
||||
for ( int i = widgetList.size(); i < data.size(); i++ )
|
||||
{
|
||||
QWidget *widget = createWidget( data[i] );
|
||||
|
||||
if ( contentsLayout )
|
||||
contentsLayout->addWidget( widget );
|
||||
|
||||
if ( isVisible() )
|
||||
{
|
||||
// QLayout does a delayed show, with the effect, that
|
||||
// the size hint will be wrong, when applications
|
||||
// call replot() right after changing the list
|
||||
// of plot items. So we better do the show now.
|
||||
|
||||
widget->setVisible( true );
|
||||
}
|
||||
|
||||
widgetList += widget;
|
||||
}
|
||||
|
||||
if ( widgetList.isEmpty() )
|
||||
{
|
||||
d_data->itemMap.remove( itemInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
d_data->itemMap.insert( itemInfo, widgetList );
|
||||
}
|
||||
|
||||
updateTabOrder();
|
||||
}
|
||||
|
||||
for ( int i = 0; i < data.size(); i++ )
|
||||
updateWidget( widgetList[i], data[i] );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Create a widget to be inserted into the legend
|
||||
|
||||
The default implementation returns a QwtLegendLabel.
|
||||
|
||||
\param data Attributes of the legend entry
|
||||
\return Widget representing data on the legend
|
||||
|
||||
\note updateWidget() will called soon after createWidget()
|
||||
with the same attributes.
|
||||
*/
|
||||
QWidget *QwtLegend::createWidget( const QwtLegendData &data ) const
|
||||
{
|
||||
Q_UNUSED( data );
|
||||
|
||||
QwtLegendLabel *label = new QwtLegendLabel();
|
||||
label->setItemMode( defaultItemMode() );
|
||||
|
||||
connect( label, SIGNAL( clicked() ), SLOT( itemClicked() ) );
|
||||
connect( label, SIGNAL( checked( bool ) ), SLOT( itemChecked( bool ) ) );
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Update the widget
|
||||
|
||||
\param widget Usually a QwtLegendLabel
|
||||
\param data Attributes to be displayed
|
||||
|
||||
\sa createWidget()
|
||||
\note When widget is no QwtLegendLabel updateWidget() does nothing.
|
||||
*/
|
||||
void QwtLegend::updateWidget( QWidget *widget, const QwtLegendData &data )
|
||||
{
|
||||
QwtLegendLabel *label = qobject_cast<QwtLegendLabel *>( widget );
|
||||
if ( label )
|
||||
{
|
||||
label->setData( data );
|
||||
if ( !data.value( QwtLegendData::ModeRole ).isValid() )
|
||||
{
|
||||
// use the default mode, when there is no specific
|
||||
// hint from the legend data
|
||||
|
||||
label->setItemMode( defaultItemMode() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QwtLegend::updateTabOrder()
|
||||
{
|
||||
QLayout *contentsLayout = d_data->view->contentsWidget->layout();
|
||||
if ( contentsLayout )
|
||||
{
|
||||
// set tab focus chain
|
||||
|
||||
QWidget *w = NULL;
|
||||
|
||||
for ( int i = 0; i < contentsLayout->count(); i++ )
|
||||
{
|
||||
QLayoutItem *item = contentsLayout->itemAt( i );
|
||||
if ( w && item->widget() )
|
||||
QWidget::setTabOrder( w, item->widget() );
|
||||
|
||||
w = item->widget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Return a size hint.
|
||||
QSize QwtLegend::sizeHint() const
|
||||
{
|
||||
QSize hint = d_data->view->contentsWidget->sizeHint();
|
||||
hint += QSize( 2 * frameWidth(), 2 * frameWidth() );
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The preferred height, for a width.
|
||||
\param width Width
|
||||
*/
|
||||
int QwtLegend::heightForWidth( int width ) const
|
||||
{
|
||||
width -= 2 * frameWidth();
|
||||
|
||||
int h = d_data->view->contentsWidget->heightForWidth( width );
|
||||
if ( h >= 0 )
|
||||
h += 2 * frameWidth();
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Handle QEvent::ChildRemoved andQEvent::LayoutRequest events
|
||||
for the contentsWidget().
|
||||
|
||||
\param object Object to be filtered
|
||||
\param event Event
|
||||
|
||||
\return Forwarded to QwtAbstractLegend::eventFilter()
|
||||
*/
|
||||
bool QwtLegend::eventFilter( QObject *object, QEvent *event )
|
||||
{
|
||||
if ( object == d_data->view->contentsWidget )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::ChildRemoved:
|
||||
{
|
||||
const QChildEvent *ce =
|
||||
static_cast<const QChildEvent *>(event);
|
||||
if ( ce->child()->isWidgetType() )
|
||||
{
|
||||
QWidget *w = static_cast< QWidget * >( ce->child() );
|
||||
d_data->itemMap.removeWidget( w );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::LayoutRequest:
|
||||
{
|
||||
d_data->view->layoutContents();
|
||||
|
||||
if ( parentWidget() && parentWidget()->layout() == NULL )
|
||||
{
|
||||
/*
|
||||
We want the parent widget ( usually QwtPlot ) to recalculate
|
||||
its layout, when the contentsWidget has changed. But
|
||||
because of the scroll view we have to forward the LayoutRequest
|
||||
event manually.
|
||||
|
||||
We don't use updateGeometry() because it doesn't post LayoutRequest
|
||||
events when the legend is hidden. But we want the
|
||||
parent widget notified, so it can show/hide the legend
|
||||
depending on its items.
|
||||
*/
|
||||
QApplication::postEvent( parentWidget(),
|
||||
new QEvent( QEvent::LayoutRequest ) );
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QwtAbstractLegend::eventFilter( object, event );
|
||||
}
|
||||
|
||||
/*!
|
||||
Called internally when the legend has been clicked on.
|
||||
Emits a clicked() signal.
|
||||
*/
|
||||
void QwtLegend::itemClicked()
|
||||
{
|
||||
QWidget *w = qobject_cast<QWidget *>( sender() );
|
||||
if ( w )
|
||||
{
|
||||
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
|
||||
if ( itemInfo.isValid() )
|
||||
{
|
||||
const QList<QWidget *> widgetList =
|
||||
d_data->itemMap.legendWidgets( itemInfo );
|
||||
|
||||
const int index = widgetList.indexOf( w );
|
||||
if ( index >= 0 )
|
||||
Q_EMIT clicked( itemInfo, index );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Called internally when the legend has been checked
|
||||
Emits a checked() signal.
|
||||
*/
|
||||
void QwtLegend::itemChecked( bool on )
|
||||
{
|
||||
QWidget *w = qobject_cast<QWidget *>( sender() );
|
||||
if ( w )
|
||||
{
|
||||
const QVariant itemInfo = d_data->itemMap.itemInfo( w );
|
||||
if ( itemInfo.isValid() )
|
||||
{
|
||||
const QList<QWidget *> widgetList =
|
||||
d_data->itemMap.legendWidgets( itemInfo );
|
||||
|
||||
const int index = widgetList.indexOf( w );
|
||||
if ( index >= 0 )
|
||||
Q_EMIT checked( itemInfo, on, index );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Render the legend into a given rectangle.
|
||||
|
||||
\param painter Painter
|
||||
\param rect Bounding rectangle
|
||||
\param fillBackground When true, fill rect with the widget background
|
||||
|
||||
\sa renderLegend() is used by QwtPlotRenderer - not by QwtLegend itself
|
||||
*/
|
||||
void QwtLegend::renderLegend( QPainter *painter,
|
||||
const QRectF &rect, bool fillBackground ) const
|
||||
{
|
||||
if ( d_data->itemMap.isEmpty() )
|
||||
return;
|
||||
|
||||
if ( fillBackground )
|
||||
{
|
||||
if ( autoFillBackground() ||
|
||||
testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
QwtPainter::drawBackgound( painter, rect, this );
|
||||
}
|
||||
}
|
||||
|
||||
const QwtDynGridLayout *legendLayout =
|
||||
qobject_cast<QwtDynGridLayout *>( contentsWidget()->layout() );
|
||||
if ( legendLayout == NULL )
|
||||
return;
|
||||
|
||||
int left, right, top, bottom;
|
||||
getContentsMargins( &left, &top, &right, &bottom );
|
||||
|
||||
QRect layoutRect;
|
||||
layoutRect.setLeft( qCeil( rect.left() ) + left );
|
||||
layoutRect.setTop( qCeil( rect.top() ) + top );
|
||||
layoutRect.setRight( qFloor( rect.right() ) - right );
|
||||
layoutRect.setBottom( qFloor( rect.bottom() ) - bottom );
|
||||
|
||||
uint numCols = legendLayout->columnsForWidth( layoutRect.width() );
|
||||
QList<QRect> itemRects =
|
||||
legendLayout->layoutItems( layoutRect, numCols );
|
||||
|
||||
int index = 0;
|
||||
|
||||
for ( int i = 0; i < legendLayout->count(); i++ )
|
||||
{
|
||||
QLayoutItem *item = legendLayout->itemAt( i );
|
||||
QWidget *w = item->widget();
|
||||
if ( w )
|
||||
{
|
||||
painter->save();
|
||||
|
||||
painter->setClipRect( itemRects[index], Qt::IntersectClip );
|
||||
renderItem( painter, w, itemRects[index], fillBackground );
|
||||
|
||||
index++;
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Render a legend entry into a given rectangle.
|
||||
|
||||
\param painter Painter
|
||||
\param widget Widget representing a legend entry
|
||||
\param rect Bounding rectangle
|
||||
\param fillBackground When true, fill rect with the widget background
|
||||
|
||||
\note When widget is not derived from QwtLegendLabel renderItem
|
||||
does nothing beside the background
|
||||
*/
|
||||
void QwtLegend::renderItem( QPainter *painter,
|
||||
const QWidget *widget, const QRectF &rect, bool fillBackground ) const
|
||||
{
|
||||
if ( fillBackground )
|
||||
{
|
||||
if ( widget->autoFillBackground() ||
|
||||
widget->testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
QwtPainter::drawBackgound( painter, rect, widget );
|
||||
}
|
||||
}
|
||||
|
||||
const QwtLegendLabel *label = qobject_cast<const QwtLegendLabel *>( widget );
|
||||
if ( label )
|
||||
{
|
||||
// icon
|
||||
|
||||
const QwtGraphic &icon = label->data().icon();
|
||||
const QSizeF sz = icon.defaultSize();
|
||||
|
||||
const QRectF iconRect( rect.x() + label->margin(),
|
||||
rect.center().y() - 0.5 * sz.height(),
|
||||
sz.width(), sz.height() );
|
||||
|
||||
icon.render( painter, iconRect, Qt::KeepAspectRatio );
|
||||
|
||||
// title
|
||||
|
||||
QRectF titleRect = rect;
|
||||
titleRect.setX( iconRect.right() + 2 * label->spacing() );
|
||||
|
||||
painter->setFont( label->font() );
|
||||
painter->setPen( label->palette().color( QPalette::Text ) );
|
||||
const_cast< QwtLegendLabel *>( label )->drawText( painter, titleRect );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return List of widgets associated to a item
|
||||
\param itemInfo Info about an item
|
||||
\sa legendWidget(), itemInfo(), QwtPlot::itemToInfo()
|
||||
*/
|
||||
QList<QWidget *> QwtLegend::legendWidgets( const QVariant &itemInfo ) const
|
||||
{
|
||||
return d_data->itemMap.legendWidgets( itemInfo );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return First widget in the list of widgets associated to an item
|
||||
\param itemInfo Info about an item
|
||||
\sa itemInfo(), QwtPlot::itemToInfo()
|
||||
\note Almost all types of items have only one widget
|
||||
*/
|
||||
QWidget *QwtLegend::legendWidget( const QVariant &itemInfo ) const
|
||||
{
|
||||
const QList<QWidget *> list = d_data->itemMap.legendWidgets( itemInfo );
|
||||
if ( list.isEmpty() )
|
||||
return NULL;
|
||||
|
||||
return list[0];
|
||||
}
|
||||
|
||||
/*!
|
||||
Find the item that is associated to a widget
|
||||
|
||||
\param widget Widget on the legend
|
||||
\return Associated item info
|
||||
\sa legendWidget()
|
||||
*/
|
||||
QVariant QwtLegend::itemInfo( const QWidget *widget ) const
|
||||
{
|
||||
return d_data->itemMap.itemInfo( widget );
|
||||
}
|
||||
|
||||
//! \return True, when no item is inserted
|
||||
bool QwtLegend::isEmpty() const
|
||||
{
|
||||
return d_data->itemMap.isEmpty();
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the extent, that is needed for the scrollbars
|
||||
|
||||
\param orientation Orientation (
|
||||
\return The width of the vertical scrollbar for Qt::Horizontal and v.v.
|
||||
*/
|
||||
int QwtLegend::scrollExtent( Qt::Orientation orientation ) const
|
||||
{
|
||||
int extent = 0;
|
||||
|
||||
if ( orientation == Qt::Horizontal )
|
||||
extent = verticalScrollBar()->sizeHint().width();
|
||||
else
|
||||
extent = horizontalScrollBar()->sizeHint().height();
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_LEGEND_H
|
||||
#define QWT_LEGEND_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_abstract_legend.h"
|
||||
#include <qvariant.h>
|
||||
|
||||
class QScrollBar;
|
||||
|
||||
/*!
|
||||
\brief The legend widget
|
||||
|
||||
The QwtLegend widget is a tabular arrangement of legend items. Legend
|
||||
items might be any type of widget, but in general they will be
|
||||
a QwtLegendLabel.
|
||||
|
||||
\sa QwtLegendLabel, QwtPlotItem, QwtPlot
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtLegend : public QwtAbstractLegend
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QwtLegend( QWidget *parent = NULL );
|
||||
virtual ~QwtLegend();
|
||||
|
||||
void setMaxColumns( uint numColums );
|
||||
uint maxColumns() const;
|
||||
|
||||
void setDefaultItemMode( QwtLegendData::Mode );
|
||||
QwtLegendData::Mode defaultItemMode() const;
|
||||
|
||||
QWidget *contentsWidget();
|
||||
const QWidget *contentsWidget() const;
|
||||
|
||||
QWidget *legendWidget( const QVariant & ) const;
|
||||
QList<QWidget *> legendWidgets( const QVariant & ) const;
|
||||
|
||||
QVariant itemInfo( const QWidget * ) const;
|
||||
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual int heightForWidth( int w ) const;
|
||||
|
||||
QScrollBar *horizontalScrollBar() const;
|
||||
QScrollBar *verticalScrollBar() const;
|
||||
|
||||
virtual void renderLegend( QPainter *,
|
||||
const QRectF &, bool fillBackground ) const;
|
||||
|
||||
virtual void renderItem( QPainter *,
|
||||
const QWidget *, const QRectF &, bool fillBackground ) const;
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
virtual int scrollExtent( Qt::Orientation ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/*!
|
||||
A signal which is emitted when the user has clicked on
|
||||
a legend label, which is in QwtLegendData::Clickable mode.
|
||||
|
||||
\param itemInfo Info for the item item of the
|
||||
selected legend item
|
||||
\param index Index of the legend label in the list of widgets
|
||||
that are associated with the plot item
|
||||
|
||||
\note clicks are disabled as default
|
||||
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
|
||||
*/
|
||||
void clicked( const QVariant &itemInfo, int index );
|
||||
|
||||
/*!
|
||||
A signal which is emitted when the user has clicked on
|
||||
a legend label, which is in QwtLegendData::Checkable mode
|
||||
|
||||
\param itemInfo Info for the item of the
|
||||
selected legend label
|
||||
\param index Index of the legend label in the list of widgets
|
||||
that are associated with the plot item
|
||||
\param on True when the legend label is checked
|
||||
|
||||
\note clicks are disabled as default
|
||||
\sa setDefaultItemMode(), defaultItemMode(), QwtPlot::itemToInfo()
|
||||
*/
|
||||
void checked( const QVariant &itemInfo, bool on, int index );
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void updateLegend( const QVariant &,
|
||||
const QList<QwtLegendData> & );
|
||||
|
||||
protected Q_SLOTS:
|
||||
void itemClicked();
|
||||
void itemChecked( bool );
|
||||
|
||||
protected:
|
||||
virtual QWidget *createWidget( const QwtLegendData & ) const;
|
||||
virtual void updateWidget( QWidget *widget, const QwtLegendData &data );
|
||||
|
||||
private:
|
||||
void updateTabOrder();
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_legend_data.h"
|
||||
|
||||
//! Constructor
|
||||
QwtLegendData::QwtLegendData()
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtLegendData::~QwtLegendData()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the legend attributes
|
||||
|
||||
QwtLegendData actually is a QMap<int, QVariant> with some
|
||||
convenience interfaces
|
||||
|
||||
\param map Values
|
||||
\sa values()
|
||||
*/
|
||||
void QwtLegendData::setValues( const QMap<int, QVariant> &map )
|
||||
{
|
||||
d_map = map;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Legend attributes
|
||||
\sa setValues()
|
||||
*/
|
||||
const QMap<int, QVariant> &QwtLegendData::values() const
|
||||
{
|
||||
return d_map;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param role Attribute role
|
||||
\return True, when the internal map has an entry for role
|
||||
*/
|
||||
bool QwtLegendData::hasRole( int role ) const
|
||||
{
|
||||
return d_map.contains( role );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set an attribute value
|
||||
|
||||
\param role Attribute role
|
||||
\param data Attribute value
|
||||
|
||||
\sa value()
|
||||
*/
|
||||
void QwtLegendData::setValue( int role, const QVariant &data )
|
||||
{
|
||||
d_map[role] = data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param role Attribute role
|
||||
\return Attribute value for a specific role
|
||||
*/
|
||||
QVariant QwtLegendData::value( int role ) const
|
||||
{
|
||||
if ( !d_map.contains( role ) )
|
||||
return QVariant();
|
||||
|
||||
return d_map[role];
|
||||
}
|
||||
|
||||
//! \return True, when the internal map is empty
|
||||
bool QwtLegendData::isValid() const
|
||||
{
|
||||
return !d_map.isEmpty();
|
||||
}
|
||||
|
||||
//! \return Value of the TitleRole attribute
|
||||
QwtText QwtLegendData::title() const
|
||||
{
|
||||
QwtText text;
|
||||
|
||||
const QVariant titleValue = value( QwtLegendData::TitleRole );
|
||||
if ( titleValue.canConvert<QwtText>() )
|
||||
{
|
||||
text = qvariant_cast<QwtText>( titleValue );
|
||||
}
|
||||
else if ( titleValue.canConvert<QString>() )
|
||||
{
|
||||
text.setText( qvariant_cast<QString>( titleValue ) );
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
//! \return Value of the IconRole attribute
|
||||
QwtGraphic QwtLegendData::icon() const
|
||||
{
|
||||
const QVariant iconValue = value( QwtLegendData::IconRole );
|
||||
|
||||
QwtGraphic graphic;
|
||||
if ( iconValue.canConvert<QwtGraphic>() )
|
||||
{
|
||||
graphic = qvariant_cast<QwtGraphic>( iconValue );
|
||||
}
|
||||
|
||||
return graphic;
|
||||
}
|
||||
|
||||
//! \return Value of the ModeRole attribute
|
||||
QwtLegendData::Mode QwtLegendData::mode() const
|
||||
{
|
||||
const QVariant modeValue = value( QwtLegendData::ModeRole );
|
||||
if ( modeValue.canConvert<int>() )
|
||||
{
|
||||
const int mode = qvariant_cast<int>( modeValue );
|
||||
return static_cast<QwtLegendData::Mode>( mode );
|
||||
}
|
||||
|
||||
return QwtLegendData::ReadOnly;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_LEGEND_DATA_H
|
||||
#define QWT_LEGEND_DATA_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_text.h"
|
||||
#include "qwt_graphic.h"
|
||||
#include <qvariant.h>
|
||||
#include <qpixmap.h>
|
||||
#include <qmap.h>
|
||||
|
||||
/*!
|
||||
\brief Attributes of an entry on a legend
|
||||
|
||||
QwtLegendData is an abstract container ( like QAbstractModel )
|
||||
to exchange attributes, that are only known between to
|
||||
the plot item and the legend.
|
||||
|
||||
By overloading QwtPlotItem::legendData() any other set of attributes
|
||||
could be used, that can be handled by a modified ( or completely
|
||||
different ) implementation of a legend.
|
||||
|
||||
\sa QwtLegend, QwtPlotLegendItem
|
||||
\note The stockchart example implements a legend as a tree
|
||||
with checkable items
|
||||
*/
|
||||
class QWT_EXPORT QwtLegendData
|
||||
{
|
||||
public:
|
||||
//! Mode defining how a legend entry interacts
|
||||
enum Mode
|
||||
{
|
||||
//! The legend item is not interactive, like a label
|
||||
ReadOnly,
|
||||
|
||||
//! The legend item is clickable, like a push button
|
||||
Clickable,
|
||||
|
||||
//! The legend item is checkable, like a checkable button
|
||||
Checkable
|
||||
};
|
||||
|
||||
//! Identifier how to interprete a QVariant
|
||||
enum Role
|
||||
{
|
||||
// The value is a Mode
|
||||
ModeRole,
|
||||
|
||||
// The value is a title
|
||||
TitleRole,
|
||||
|
||||
// The value is an icon
|
||||
IconRole,
|
||||
|
||||
// Values < UserRole are reserved for internal use
|
||||
UserRole = 32
|
||||
};
|
||||
|
||||
QwtLegendData();
|
||||
~QwtLegendData();
|
||||
|
||||
void setValues( const QMap<int, QVariant> & );
|
||||
const QMap<int, QVariant> &values() const;
|
||||
|
||||
void setValue( int role, const QVariant & );
|
||||
QVariant value( int role ) const;
|
||||
|
||||
bool hasRole( int role ) const;
|
||||
bool isValid() const;
|
||||
|
||||
QwtGraphic icon() const;
|
||||
QwtText title() const;
|
||||
Mode mode() const;
|
||||
|
||||
private:
|
||||
QMap<int, QVariant> d_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,421 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_legend_label.h"
|
||||
#include "qwt_legend_data.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_painter.h"
|
||||
#include "qwt_symbol.h"
|
||||
#include "qwt_graphic.h"
|
||||
#include <qpainter.h>
|
||||
#include <qdrawutil.h>
|
||||
#include <qstyle.h>
|
||||
#include <qpen.h>
|
||||
#include <qevent.h>
|
||||
#include <qstyleoption.h>
|
||||
#include <qapplication.h>
|
||||
|
||||
static const int ButtonFrame = 2;
|
||||
static const int Margin = 2;
|
||||
|
||||
static QSize buttonShift( const QwtLegendLabel *w )
|
||||
{
|
||||
QStyleOption option;
|
||||
option.init( w );
|
||||
|
||||
const int ph = w->style()->pixelMetric(
|
||||
QStyle::PM_ButtonShiftHorizontal, &option, w );
|
||||
const int pv = w->style()->pixelMetric(
|
||||
QStyle::PM_ButtonShiftVertical, &option, w );
|
||||
return QSize( ph, pv );
|
||||
}
|
||||
|
||||
class QwtLegendLabel::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
itemMode( QwtLegendData::ReadOnly ),
|
||||
isDown( false ),
|
||||
spacing( Margin )
|
||||
{
|
||||
}
|
||||
|
||||
QwtLegendData::Mode itemMode;
|
||||
QwtLegendData legendData;
|
||||
bool isDown;
|
||||
|
||||
QPixmap icon;
|
||||
|
||||
int spacing;
|
||||
};
|
||||
|
||||
/*!
|
||||
Set the attributes of the legend label
|
||||
|
||||
\param legendData Attributes of the label
|
||||
\sa data()
|
||||
*/
|
||||
void QwtLegendLabel::setData( const QwtLegendData &legendData )
|
||||
{
|
||||
d_data->legendData = legendData;
|
||||
|
||||
const bool doUpdate = updatesEnabled();
|
||||
setUpdatesEnabled( false );
|
||||
|
||||
setText( legendData.title() );
|
||||
setIcon( legendData.icon().toPixmap() );
|
||||
|
||||
if ( legendData.hasRole( QwtLegendData::ModeRole ) )
|
||||
setItemMode( legendData.mode() );
|
||||
|
||||
if ( doUpdate )
|
||||
{
|
||||
setUpdatesEnabled( true );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Attributes of the label
|
||||
\sa setData(), QwtPlotItem::legendData()
|
||||
*/
|
||||
const QwtLegendData &QwtLegendLabel::data() const
|
||||
{
|
||||
return d_data->legendData;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param parent Parent widget
|
||||
*/
|
||||
QwtLegendLabel::QwtLegendLabel( QWidget *parent ):
|
||||
QwtTextLabel( parent )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
setMargin( Margin );
|
||||
setIndent( Margin );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtLegendLabel::~QwtLegendLabel()
|
||||
{
|
||||
delete d_data;
|
||||
d_data = NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the text to the legend item
|
||||
|
||||
\param text Text label
|
||||
\sa QwtTextLabel::text()
|
||||
*/
|
||||
void QwtLegendLabel::setText( const QwtText &text )
|
||||
{
|
||||
const int flags = Qt::AlignLeft | Qt::AlignVCenter
|
||||
| Qt::TextExpandTabs | Qt::TextWordWrap;
|
||||
|
||||
QwtText txt = text;
|
||||
txt.setRenderFlags( flags );
|
||||
|
||||
QwtTextLabel::setText( txt );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the item mode
|
||||
The default is QwtLegendData::ReadOnly
|
||||
|
||||
\param mode Item mode
|
||||
\sa itemMode()
|
||||
*/
|
||||
void QwtLegendLabel::setItemMode( QwtLegendData::Mode mode )
|
||||
{
|
||||
if ( mode != d_data->itemMode )
|
||||
{
|
||||
d_data->itemMode = mode;
|
||||
d_data->isDown = false;
|
||||
|
||||
setFocusPolicy( ( mode != QwtLegendData::ReadOnly )
|
||||
? Qt::TabFocus : Qt::NoFocus );
|
||||
setMargin( ButtonFrame + Margin );
|
||||
|
||||
updateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Item mode
|
||||
\sa setItemMode()
|
||||
*/
|
||||
QwtLegendData::Mode QwtLegendLabel::itemMode() const
|
||||
{
|
||||
return d_data->itemMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the icon
|
||||
|
||||
\param icon Pixmap representing a plot item
|
||||
|
||||
\sa icon(), QwtPlotItem::legendIcon()
|
||||
*/
|
||||
void QwtLegendLabel::setIcon( const QPixmap &icon )
|
||||
{
|
||||
d_data->icon = icon;
|
||||
|
||||
int indent = margin() + d_data->spacing;
|
||||
if ( icon.width() > 0 )
|
||||
indent += icon.width() + d_data->spacing;
|
||||
|
||||
setIndent( indent );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Pixmap representing a plot item
|
||||
\sa setIcon()
|
||||
*/
|
||||
QPixmap QwtLegendLabel::icon() const
|
||||
{
|
||||
return d_data->icon;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the spacing between icon and text
|
||||
|
||||
\param spacing Spacing
|
||||
\sa spacing(), QwtTextLabel::margin()
|
||||
*/
|
||||
void QwtLegendLabel::setSpacing( int spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0 );
|
||||
if ( spacing != d_data->spacing )
|
||||
{
|
||||
d_data->spacing = spacing;
|
||||
|
||||
int indent = margin() + d_data->spacing;
|
||||
if ( d_data->icon.width() > 0 )
|
||||
indent += d_data->icon.width() + d_data->spacing;
|
||||
|
||||
setIndent( indent );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Spacing between icon and text
|
||||
\sa setSpacing(), QwtTextLabel::margin()
|
||||
*/
|
||||
int QwtLegendLabel::spacing() const
|
||||
{
|
||||
return d_data->spacing;
|
||||
}
|
||||
|
||||
/*!
|
||||
Check/Uncheck a the item
|
||||
|
||||
\param on check/uncheck
|
||||
\sa setItemMode()
|
||||
*/
|
||||
void QwtLegendLabel::setChecked( bool on )
|
||||
{
|
||||
if ( d_data->itemMode == QwtLegendData::Checkable )
|
||||
{
|
||||
const bool isBlocked = signalsBlocked();
|
||||
blockSignals( true );
|
||||
|
||||
setDown( on );
|
||||
|
||||
blockSignals( isBlocked );
|
||||
}
|
||||
}
|
||||
|
||||
//! Return true, if the item is checked
|
||||
bool QwtLegendLabel::isChecked() const
|
||||
{
|
||||
return d_data->itemMode == QwtLegendData::Checkable && isDown();
|
||||
}
|
||||
|
||||
//! Set the item being down
|
||||
void QwtLegendLabel::setDown( bool down )
|
||||
{
|
||||
if ( down == d_data->isDown )
|
||||
return;
|
||||
|
||||
d_data->isDown = down;
|
||||
update();
|
||||
|
||||
if ( d_data->itemMode == QwtLegendData::Clickable )
|
||||
{
|
||||
if ( d_data->isDown )
|
||||
Q_EMIT pressed();
|
||||
else
|
||||
{
|
||||
Q_EMIT released();
|
||||
Q_EMIT clicked();
|
||||
}
|
||||
}
|
||||
|
||||
if ( d_data->itemMode == QwtLegendData::Checkable )
|
||||
Q_EMIT checked( d_data->isDown );
|
||||
}
|
||||
|
||||
//! Return true, if the item is down
|
||||
bool QwtLegendLabel::isDown() const
|
||||
{
|
||||
return d_data->isDown;
|
||||
}
|
||||
|
||||
//! Return a size hint
|
||||
QSize QwtLegendLabel::sizeHint() const
|
||||
{
|
||||
QSize sz = QwtTextLabel::sizeHint();
|
||||
sz.setHeight( qMax( sz.height(), d_data->icon.height() + 4 ) );
|
||||
|
||||
if ( d_data->itemMode != QwtLegendData::ReadOnly )
|
||||
{
|
||||
sz += buttonShift( this );
|
||||
sz = sz.expandedTo( QApplication::globalStrut() );
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
//! Paint event
|
||||
void QwtLegendLabel::paintEvent( QPaintEvent *e )
|
||||
{
|
||||
const QRect cr = contentsRect();
|
||||
|
||||
QPainter painter( this );
|
||||
painter.setClipRegion( e->region() );
|
||||
|
||||
if ( d_data->isDown )
|
||||
{
|
||||
qDrawWinButton( &painter, 0, 0, width(), height(),
|
||||
palette(), true );
|
||||
}
|
||||
|
||||
painter.save();
|
||||
|
||||
if ( d_data->isDown )
|
||||
{
|
||||
const QSize shiftSize = buttonShift( this );
|
||||
painter.translate( shiftSize.width(), shiftSize.height() );
|
||||
}
|
||||
|
||||
painter.setClipRect( cr );
|
||||
|
||||
drawContents( &painter );
|
||||
|
||||
if ( !d_data->icon.isNull() )
|
||||
{
|
||||
QRect iconRect = cr;
|
||||
iconRect.setX( iconRect.x() + margin() );
|
||||
if ( d_data->itemMode != QwtLegendData::ReadOnly )
|
||||
iconRect.setX( iconRect.x() + ButtonFrame );
|
||||
|
||||
iconRect.setSize( d_data->icon.size() );
|
||||
iconRect.moveCenter( QPoint( iconRect.center().x(), cr.center().y() ) );
|
||||
|
||||
painter.drawPixmap( iconRect, d_data->icon );
|
||||
}
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
//! Handle mouse press events
|
||||
void QwtLegendLabel::mousePressEvent( QMouseEvent *e )
|
||||
{
|
||||
if ( e->button() == Qt::LeftButton )
|
||||
{
|
||||
switch ( d_data->itemMode )
|
||||
{
|
||||
case QwtLegendData::Clickable:
|
||||
{
|
||||
setDown( true );
|
||||
return;
|
||||
}
|
||||
case QwtLegendData::Checkable:
|
||||
{
|
||||
setDown( !isDown() );
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
QwtTextLabel::mousePressEvent( e );
|
||||
}
|
||||
|
||||
//! Handle mouse release events
|
||||
void QwtLegendLabel::mouseReleaseEvent( QMouseEvent *e )
|
||||
{
|
||||
if ( e->button() == Qt::LeftButton )
|
||||
{
|
||||
switch ( d_data->itemMode )
|
||||
{
|
||||
case QwtLegendData::Clickable:
|
||||
{
|
||||
setDown( false );
|
||||
return;
|
||||
}
|
||||
case QwtLegendData::Checkable:
|
||||
{
|
||||
return; // do nothing, but accept
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
QwtTextLabel::mouseReleaseEvent( e );
|
||||
}
|
||||
|
||||
//! Handle key press events
|
||||
void QwtLegendLabel::keyPressEvent( QKeyEvent *e )
|
||||
{
|
||||
if ( e->key() == Qt::Key_Space )
|
||||
{
|
||||
switch ( d_data->itemMode )
|
||||
{
|
||||
case QwtLegendData::Clickable:
|
||||
{
|
||||
if ( !e->isAutoRepeat() )
|
||||
setDown( true );
|
||||
return;
|
||||
}
|
||||
case QwtLegendData::Checkable:
|
||||
{
|
||||
if ( !e->isAutoRepeat() )
|
||||
setDown( !isDown() );
|
||||
return;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
QwtTextLabel::keyPressEvent( e );
|
||||
}
|
||||
|
||||
//! Handle key release events
|
||||
void QwtLegendLabel::keyReleaseEvent( QKeyEvent *e )
|
||||
{
|
||||
if ( e->key() == Qt::Key_Space )
|
||||
{
|
||||
switch ( d_data->itemMode )
|
||||
{
|
||||
case QwtLegendData::Clickable:
|
||||
{
|
||||
if ( !e->isAutoRepeat() )
|
||||
setDown( false );
|
||||
return;
|
||||
}
|
||||
case QwtLegendData::Checkable:
|
||||
{
|
||||
return; // do nothing, but accept
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
QwtTextLabel::keyReleaseEvent( e );
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_LEGEND_LABEL_H
|
||||
#define QWT_LEGEND_LABEL_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_legend_data.h"
|
||||
#include "qwt_text.h"
|
||||
#include "qwt_text_label.h"
|
||||
#include <qpixmap.h>
|
||||
|
||||
class QwtLegendData;
|
||||
|
||||
/*!
|
||||
\brief A widget representing something on a QwtLegend.
|
||||
*/
|
||||
class QWT_EXPORT QwtLegendLabel: public QwtTextLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QwtLegendLabel( QWidget *parent = 0 );
|
||||
virtual ~QwtLegendLabel();
|
||||
|
||||
void setData( const QwtLegendData & );
|
||||
const QwtLegendData &data() const;
|
||||
|
||||
void setItemMode( QwtLegendData::Mode );
|
||||
QwtLegendData::Mode itemMode() const;
|
||||
|
||||
void setSpacing( int spacing );
|
||||
int spacing() const;
|
||||
|
||||
virtual void setText( const QwtText & );
|
||||
|
||||
void setIcon( const QPixmap & );
|
||||
QPixmap icon() const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
bool isChecked() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setChecked( bool on );
|
||||
|
||||
Q_SIGNALS:
|
||||
//! Signal, when the legend item has been clicked
|
||||
void clicked();
|
||||
|
||||
//! Signal, when the legend item has been pressed
|
||||
void pressed();
|
||||
|
||||
//! Signal, when the legend item has been released
|
||||
void released();
|
||||
|
||||
//! Signal, when the legend item has been toggled
|
||||
void checked( bool );
|
||||
|
||||
protected:
|
||||
void setDown( bool );
|
||||
bool isDown() const;
|
||||
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
virtual void mousePressEvent( QMouseEvent * );
|
||||
virtual void mouseReleaseEvent( QMouseEvent * );
|
||||
virtual void keyPressEvent( QKeyEvent * );
|
||||
virtual void keyReleaseEvent( QKeyEvent * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,492 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_magnifier.h"
|
||||
#include "qwt_math.h"
|
||||
#include <qevent.h>
|
||||
#include <qwidget.h>
|
||||
|
||||
class QwtMagnifier::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
isEnabled( false ),
|
||||
wheelFactor( 0.9 ),
|
||||
wheelModifiers( Qt::NoModifier ),
|
||||
mouseFactor( 0.95 ),
|
||||
mouseButton( Qt::RightButton ),
|
||||
mouseButtonModifiers( Qt::NoModifier ),
|
||||
keyFactor( 0.9 ),
|
||||
zoomInKey( Qt::Key_Plus ),
|
||||
zoomInKeyModifiers( Qt::NoModifier ),
|
||||
zoomOutKey( Qt::Key_Minus ),
|
||||
zoomOutKeyModifiers( Qt::NoModifier ),
|
||||
mousePressed( false )
|
||||
{
|
||||
}
|
||||
|
||||
bool isEnabled;
|
||||
|
||||
double wheelFactor;
|
||||
Qt::KeyboardModifiers wheelModifiers;
|
||||
|
||||
double mouseFactor;
|
||||
|
||||
Qt::MouseButton mouseButton;
|
||||
Qt::KeyboardModifiers mouseButtonModifiers;
|
||||
|
||||
double keyFactor;
|
||||
|
||||
int zoomInKey;
|
||||
Qt::KeyboardModifiers zoomInKeyModifiers;
|
||||
|
||||
int zoomOutKey;
|
||||
Qt::KeyboardModifiers zoomOutKeyModifiers;
|
||||
|
||||
bool mousePressed;
|
||||
bool hasMouseTracking;
|
||||
QPoint mousePos;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param parent Widget to be magnified
|
||||
*/
|
||||
QwtMagnifier::QwtMagnifier( QWidget *parent ):
|
||||
QObject( parent )
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
setEnabled( true );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtMagnifier::~QwtMagnifier()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief En/disable the magnifier
|
||||
|
||||
When enabled is true an event filter is installed for
|
||||
the observed widget, otherwise the event filter is removed.
|
||||
|
||||
\param on true or false
|
||||
\sa isEnabled(), eventFilter()
|
||||
*/
|
||||
void QwtMagnifier::setEnabled( bool on )
|
||||
{
|
||||
if ( d_data->isEnabled != on )
|
||||
{
|
||||
d_data->isEnabled = on;
|
||||
|
||||
QObject *o = parent();
|
||||
if ( o )
|
||||
{
|
||||
if ( d_data->isEnabled )
|
||||
o->installEventFilter( this );
|
||||
else
|
||||
o->removeEventFilter( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true when enabled, false otherwise
|
||||
\sa setEnabled(), eventFilter()
|
||||
*/
|
||||
bool QwtMagnifier::isEnabled() const
|
||||
{
|
||||
return d_data->isEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the wheel factor
|
||||
|
||||
The wheel factor defines the ratio between the current range
|
||||
on the parent widget and the zoomed range for each step of the wheel.
|
||||
|
||||
Use values > 1 for magnification (i.e. 2.0) and values < 1 for
|
||||
scaling down (i.e. 1/2.0 = 0.5). You can use this feature for
|
||||
inverting the direction of the wheel.
|
||||
|
||||
The default value is 0.9.
|
||||
|
||||
\param factor Wheel factor
|
||||
\sa wheelFactor(), setWheelButtonState(),
|
||||
setMouseFactor(), setKeyFactor()
|
||||
*/
|
||||
void QwtMagnifier::setWheelFactor( double factor )
|
||||
{
|
||||
d_data->wheelFactor = factor;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Wheel factor
|
||||
\sa setWheelFactor()
|
||||
*/
|
||||
double QwtMagnifier::wheelFactor() const
|
||||
{
|
||||
return d_data->wheelFactor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign keyboard modifiers for zooming in/out using the wheel.
|
||||
The default modifiers are Qt::NoModifiers.
|
||||
|
||||
\param modifiers Keyboard modifiers
|
||||
\sa wheelModifiers()
|
||||
*/
|
||||
void QwtMagnifier::setWheelModifiers( Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->wheelModifiers = modifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Wheel modifiers
|
||||
\sa setWheelModifiers()
|
||||
*/
|
||||
Qt::KeyboardModifiers QwtMagnifier::wheelModifiers() const
|
||||
{
|
||||
return d_data->wheelModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the mouse factor
|
||||
|
||||
The mouse factor defines the ratio between the current range
|
||||
on the parent widget and the zoomed range for each vertical mouse movement.
|
||||
The default value is 0.95.
|
||||
|
||||
\param factor Wheel factor
|
||||
\sa mouseFactor(), setMouseButton(), setWheelFactor(), setKeyFactor()
|
||||
*/
|
||||
void QwtMagnifier::setMouseFactor( double factor )
|
||||
{
|
||||
d_data->mouseFactor = factor;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Mouse factor
|
||||
\sa setMouseFactor()
|
||||
*/
|
||||
double QwtMagnifier::mouseFactor() const
|
||||
{
|
||||
return d_data->mouseFactor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the mouse button, that is used for zooming in/out.
|
||||
The default value is Qt::RightButton.
|
||||
|
||||
\param button Button
|
||||
\param modifiers Keyboard modifiers
|
||||
|
||||
\sa getMouseButton()
|
||||
*/
|
||||
void QwtMagnifier::setMouseButton(
|
||||
Qt::MouseButton button, Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->mouseButton = button;
|
||||
d_data->mouseButtonModifiers = modifiers;
|
||||
}
|
||||
|
||||
//! \sa setMouseButton()
|
||||
void QwtMagnifier::getMouseButton(
|
||||
Qt::MouseButton &button, Qt::KeyboardModifiers &modifiers ) const
|
||||
{
|
||||
button = d_data->mouseButton;
|
||||
modifiers = d_data->mouseButtonModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the key factor
|
||||
|
||||
The key factor defines the ratio between the current range
|
||||
on the parent widget and the zoomed range for each key press of
|
||||
the zoom in/out keys. The default value is 0.9.
|
||||
|
||||
\param factor Key factor
|
||||
\sa keyFactor(), setZoomInKey(), setZoomOutKey(),
|
||||
setWheelFactor, setMouseFactor()
|
||||
*/
|
||||
void QwtMagnifier::setKeyFactor( double factor )
|
||||
{
|
||||
d_data->keyFactor = factor;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Key factor
|
||||
\sa setKeyFactor()
|
||||
*/
|
||||
double QwtMagnifier::keyFactor() const
|
||||
{
|
||||
return d_data->keyFactor;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the key, that is used for zooming in.
|
||||
The default combination is Qt::Key_Plus + Qt::NoModifier.
|
||||
|
||||
\param key
|
||||
\param modifiers
|
||||
\sa getZoomInKey(), setZoomOutKey()
|
||||
*/
|
||||
void QwtMagnifier::setZoomInKey( int key,
|
||||
Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->zoomInKey = key;
|
||||
d_data->zoomInKeyModifiers = modifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Retrieve the settings of the zoom in key
|
||||
|
||||
\param key Key code, see Qt::Key
|
||||
\param modifiers Keyboard modifiers
|
||||
|
||||
\sa setZoomInKey()
|
||||
*/
|
||||
void QwtMagnifier::getZoomInKey( int &key,
|
||||
Qt::KeyboardModifiers &modifiers ) const
|
||||
{
|
||||
key = d_data->zoomInKey;
|
||||
modifiers = d_data->zoomInKeyModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign the key, that is used for zooming out.
|
||||
The default combination is Qt::Key_Minus + Qt::NoModifier.
|
||||
|
||||
\param key
|
||||
\param modifiers
|
||||
\sa getZoomOutKey(), setZoomOutKey()
|
||||
*/
|
||||
void QwtMagnifier::setZoomOutKey( int key,
|
||||
Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->zoomOutKey = key;
|
||||
d_data->zoomOutKeyModifiers = modifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Retrieve the settings of the zoom out key
|
||||
|
||||
\param key Key code, see Qt::Key
|
||||
\param modifiers Keyboard modifiers
|
||||
|
||||
\sa setZoomOutKey()
|
||||
*/
|
||||
void QwtMagnifier::getZoomOutKey( int &key,
|
||||
Qt::KeyboardModifiers &modifiers ) const
|
||||
{
|
||||
key = d_data->zoomOutKey;
|
||||
modifiers = d_data->zoomOutKeyModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Event filter
|
||||
|
||||
When isEnabled() is true, the mouse events of the
|
||||
observed widget are filtered.
|
||||
|
||||
\param object Object to be filtered
|
||||
\param event Event
|
||||
|
||||
\return Forwarded to QObject::eventFilter()
|
||||
|
||||
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||
widgetMouseMoveEvent(), widgetWheelEvent(), widgetKeyPressEvent()
|
||||
widgetKeyReleaseEvent()
|
||||
*/
|
||||
bool QwtMagnifier::eventFilter( QObject *object, QEvent *event )
|
||||
{
|
||||
if ( object && object == parent() )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
widgetWheelEvent( static_cast<QWheelEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyRelease:
|
||||
{
|
||||
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
}
|
||||
return QObject::eventFilter( object, event );
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse press event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
\sa eventFilter(), widgetMouseReleaseEvent(), widgetMouseMoveEvent()
|
||||
*/
|
||||
void QwtMagnifier::widgetMousePressEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
if ( parentWidget() == NULL )
|
||||
return;
|
||||
|
||||
if ( ( mouseEvent->button() != d_data->mouseButton ) ||
|
||||
( mouseEvent->modifiers() != d_data->mouseButtonModifiers ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
d_data->hasMouseTracking = parentWidget()->hasMouseTracking();
|
||||
|
||||
parentWidget()->setMouseTracking( true );
|
||||
d_data->mousePos = mouseEvent->pos();
|
||||
d_data->mousePressed = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse release event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
|
||||
\sa eventFilter(), widgetMousePressEvent(), widgetMouseMoveEvent(),
|
||||
*/
|
||||
void QwtMagnifier::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
Q_UNUSED( mouseEvent );
|
||||
|
||||
if ( d_data->mousePressed && parentWidget() )
|
||||
{
|
||||
d_data->mousePressed = false;
|
||||
parentWidget()->setMouseTracking( d_data->hasMouseTracking );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse move event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||
*/
|
||||
void QwtMagnifier::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
if ( !d_data->mousePressed )
|
||||
return;
|
||||
|
||||
const int dy = mouseEvent->pos().y() - d_data->mousePos.y();
|
||||
if ( dy != 0 )
|
||||
{
|
||||
double f = d_data->mouseFactor;
|
||||
if ( dy < 0 )
|
||||
f = 1 / f;
|
||||
|
||||
rescale( f );
|
||||
}
|
||||
|
||||
d_data->mousePos = mouseEvent->pos();
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a wheel event for the observed widget.
|
||||
|
||||
\param wheelEvent Wheel event
|
||||
\sa eventFilter()
|
||||
*/
|
||||
void QwtMagnifier::widgetWheelEvent( QWheelEvent *wheelEvent )
|
||||
{
|
||||
if ( wheelEvent->modifiers() != d_data->wheelModifiers )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( d_data->wheelFactor != 0.0 )
|
||||
{
|
||||
/*
|
||||
A positive delta indicates that the wheel was
|
||||
rotated forwards away from the user; a negative
|
||||
value indicates that the wheel was rotated
|
||||
backwards toward the user.
|
||||
Most mouse types work in steps of 15 degrees,
|
||||
in which case the delta value is a multiple
|
||||
of 120 (== 15 * 8).
|
||||
*/
|
||||
double f = qPow( d_data->wheelFactor,
|
||||
qAbs( wheelEvent->delta() / 120.0 ) );
|
||||
|
||||
if ( wheelEvent->delta() > 0 )
|
||||
f = 1 / f;
|
||||
|
||||
rescale( f );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a key press event for the observed widget.
|
||||
|
||||
\param keyEvent Key event
|
||||
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||
*/
|
||||
void QwtMagnifier::widgetKeyPressEvent( QKeyEvent *keyEvent )
|
||||
{
|
||||
if ( keyEvent->key() == d_data->zoomInKey &&
|
||||
keyEvent->modifiers() == d_data->zoomInKeyModifiers )
|
||||
{
|
||||
rescale( d_data->keyFactor );
|
||||
}
|
||||
else if ( keyEvent->key() == d_data->zoomOutKey &&
|
||||
keyEvent->modifiers() == d_data->zoomOutKeyModifiers )
|
||||
{
|
||||
rescale( 1.0 / d_data->keyFactor );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a key release event for the observed widget.
|
||||
|
||||
\param keyEvent Key event
|
||||
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||
*/
|
||||
void QwtMagnifier::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
|
||||
{
|
||||
Q_UNUSED( keyEvent );
|
||||
}
|
||||
|
||||
//! \return Parent widget, where the rescaling happens
|
||||
QWidget *QwtMagnifier::parentWidget()
|
||||
{
|
||||
return qobject_cast<QWidget *>( parent() );
|
||||
}
|
||||
|
||||
//! \return Parent widget, where the rescaling happens
|
||||
const QWidget *QwtMagnifier::parentWidget() const
|
||||
{
|
||||
return qobject_cast<const QWidget *>( parent() );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_MAGNIFIER_H
|
||||
#define QWT_MAGNIFIER_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qobject.h>
|
||||
|
||||
class QWidget;
|
||||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
class QKeyEvent;
|
||||
|
||||
/*!
|
||||
\brief QwtMagnifier provides zooming, by magnifying in steps.
|
||||
|
||||
Using QwtMagnifier a plot can be zoomed in/out in steps using
|
||||
keys, the mouse wheel or moving a mouse button in vertical direction.
|
||||
*/
|
||||
class QWT_EXPORT QwtMagnifier: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QwtMagnifier( QWidget * );
|
||||
virtual ~QwtMagnifier();
|
||||
|
||||
QWidget *parentWidget();
|
||||
const QWidget *parentWidget() const;
|
||||
|
||||
void setEnabled( bool );
|
||||
bool isEnabled() const;
|
||||
|
||||
// mouse
|
||||
void setMouseFactor( double );
|
||||
double mouseFactor() const;
|
||||
|
||||
void setMouseButton( Qt::MouseButton, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
void getMouseButton( Qt::MouseButton &, Qt::KeyboardModifiers & ) const;
|
||||
|
||||
// mouse wheel
|
||||
void setWheelFactor( double );
|
||||
double wheelFactor() const;
|
||||
|
||||
void setWheelModifiers( Qt::KeyboardModifiers );
|
||||
Qt::KeyboardModifiers wheelModifiers() const;
|
||||
|
||||
// keyboard
|
||||
void setKeyFactor( double );
|
||||
double keyFactor() const;
|
||||
|
||||
void setZoomInKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
void getZoomInKey( int &key, Qt::KeyboardModifiers & ) const;
|
||||
|
||||
void setZoomOutKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
void getZoomOutKey( int &key, Qt::KeyboardModifiers & ) const;
|
||||
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
protected:
|
||||
/*!
|
||||
Rescale the parent widget
|
||||
\param factor Scale factor
|
||||
*/
|
||||
virtual void rescale( double factor ) = 0;
|
||||
|
||||
virtual void widgetMousePressEvent( QMouseEvent * );
|
||||
virtual void widgetMouseReleaseEvent( QMouseEvent * );
|
||||
virtual void widgetMouseMoveEvent( QMouseEvent * );
|
||||
virtual void widgetWheelEvent( QWheelEvent * );
|
||||
virtual void widgetKeyPressEvent( QKeyEvent * );
|
||||
virtual void widgetKeyReleaseEvent( QKeyEvent * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_math.h"
|
||||
|
||||
/*!
|
||||
\brief Find the smallest value in an array
|
||||
\param array Pointer to an array
|
||||
\param size Array size
|
||||
*/
|
||||
double qwtGetMin( const double *array, int size )
|
||||
{
|
||||
if ( size <= 0 )
|
||||
return 0.0;
|
||||
|
||||
double rv = array[0];
|
||||
for ( int i = 1; i < size; i++ )
|
||||
rv = qMin( rv, array[i] );
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Find the largest value in an array
|
||||
\param array Pointer to an array
|
||||
\param size Array size
|
||||
*/
|
||||
double qwtGetMax( const double *array, int size )
|
||||
{
|
||||
if ( size <= 0 )
|
||||
return 0.0;
|
||||
|
||||
double rv = array[0];
|
||||
for ( int i = 1; i < size; i++ )
|
||||
rv = qMax( rv, array[i] );
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Normalize an angle to be int the range [0.0, 2 * PI[
|
||||
\param radians Angle in radians
|
||||
\return Normalized angle in radians
|
||||
*/
|
||||
double qwtNormalizeRadians( double radians )
|
||||
{
|
||||
double a = ::fmod( radians, 2.0 * M_PI );
|
||||
if ( a < 0.0 )
|
||||
a += 2.0 * M_PI;
|
||||
|
||||
return a;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Normalize an angle to be int the range [0.0, 360.0[
|
||||
\param radians Angle in degrees
|
||||
\return Normalized angle in degrees
|
||||
*/
|
||||
double qwtNormalizeDegrees( double degrees )
|
||||
{
|
||||
double a = ::fmod( degrees, 360.0 );
|
||||
if ( a < 0.0 )
|
||||
a += 360.0;
|
||||
|
||||
return a;
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_MATH_H
|
||||
#define QWT_MATH_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
/*
|
||||
Microsoft says:
|
||||
|
||||
Define _USE_MATH_DEFINES before including math.h to expose these macro
|
||||
definitions for common math constants. These are placed under an #ifdef
|
||||
since these commonly-defined names are not part of the C/C++ standards.
|
||||
*/
|
||||
#define _USE_MATH_DEFINES 1
|
||||
#endif
|
||||
|
||||
#include <qmath.h>
|
||||
#include "qwt_global.h"
|
||||
|
||||
#ifndef M_PI_2
|
||||
// For Qt <= 4.8.4 M_PI_2 is not known by MinGW-w64
|
||||
// when compiling with -std=c++11
|
||||
#define M_PI_2 (1.57079632679489661923)
|
||||
#endif
|
||||
|
||||
#ifndef LOG_MIN
|
||||
//! Minimum value for logarithmic scales
|
||||
#define LOG_MIN 1.0e-100
|
||||
#endif
|
||||
|
||||
#ifndef LOG_MAX
|
||||
//! Maximum value for logarithmic scales
|
||||
#define LOG_MAX 1.0e100
|
||||
#endif
|
||||
|
||||
QWT_EXPORT double qwtGetMin( const double *array, int size );
|
||||
QWT_EXPORT double qwtGetMax( const double *array, int size );
|
||||
|
||||
QWT_EXPORT double qwtNormalizeRadians( double radians );
|
||||
QWT_EXPORT double qwtNormalizeDegrees( double degrees );
|
||||
|
||||
/*!
|
||||
\brief Compare 2 values, relative to an interval
|
||||
|
||||
Values are "equal", when :
|
||||
\f$\cdot value2 - value1 <= abs(intervalSize * 10e^{-6})\f$
|
||||
|
||||
\param value1 First value to compare
|
||||
\param value2 Second value to compare
|
||||
\param intervalSize interval size
|
||||
|
||||
\return 0: if equal, -1: if value2 > value1, 1: if value1 > value2
|
||||
*/
|
||||
inline int qwtFuzzyCompare( double value1, double value2, double intervalSize )
|
||||
{
|
||||
const double eps = qAbs( 1.0e-6 * intervalSize );
|
||||
|
||||
if ( value2 - value1 > eps )
|
||||
return -1;
|
||||
|
||||
if ( value1 - value2 > eps )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline bool qwtFuzzyGreaterOrEqual( double d1, double d2 )
|
||||
{
|
||||
return ( d1 >= d2 ) || qFuzzyCompare( d1, d2 );
|
||||
}
|
||||
|
||||
inline bool qwtFuzzyLessOrEqual( double d1, double d2 )
|
||||
{
|
||||
return ( d1 <= d2 ) || qFuzzyCompare( d1, d2 );
|
||||
}
|
||||
|
||||
//! Return the sign
|
||||
inline int qwtSign( double x )
|
||||
{
|
||||
if ( x > 0.0 )
|
||||
return 1;
|
||||
else if ( x < 0.0 )
|
||||
return ( -1 );
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Return the square of a number
|
||||
inline double qwtSqr( double x )
|
||||
{
|
||||
return x * x;
|
||||
}
|
||||
|
||||
//! Approximation of arc tangent ( error below 0,005 radians )
|
||||
inline double qwtFastAtan( double x )
|
||||
{
|
||||
if ( x < -1.0 )
|
||||
return -M_PI_2 - x / ( x * x + 0.28 );
|
||||
|
||||
if ( x > 1.0 )
|
||||
return M_PI_2 - x / ( x * x + 0.28 );
|
||||
|
||||
return x / ( 1.0 + x * x * 0.28 );
|
||||
}
|
||||
|
||||
//! Approximation of arc tangent ( error below 0,005 radians )
|
||||
inline double qwtFastAtan2( double y, double x )
|
||||
{
|
||||
if ( x > 0 )
|
||||
return qwtFastAtan( y / x );
|
||||
|
||||
if ( x < 0 )
|
||||
{
|
||||
const double d = qwtFastAtan( y / x );
|
||||
return ( y >= 0 ) ? d + M_PI : d - M_PI;
|
||||
}
|
||||
|
||||
if ( y < 0.0 )
|
||||
return -M_PI_2;
|
||||
|
||||
if ( y > 0.0 )
|
||||
return M_PI_2;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
//! Translate degrees into radians
|
||||
inline double qwtRadians( double degrees )
|
||||
{
|
||||
return degrees * M_PI / 180.0;
|
||||
}
|
||||
|
||||
//! Translate radians into degrees
|
||||
inline double qwtDegrees( double degrees )
|
||||
{
|
||||
return degrees * 180.0 / M_PI;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,298 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_matrix_raster_data.h"
|
||||
#include <qnumeric.h>
|
||||
#include <qmath.h>
|
||||
|
||||
class QwtMatrixRasterData::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
resampleMode(QwtMatrixRasterData::NearestNeighbour),
|
||||
numColumns(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline double value(int row, int col) const
|
||||
{
|
||||
return values.data()[ row * numColumns + col ];
|
||||
}
|
||||
|
||||
QwtMatrixRasterData::ResampleMode resampleMode;
|
||||
|
||||
QVector<double> values;
|
||||
int numColumns;
|
||||
int numRows;
|
||||
|
||||
double dx;
|
||||
double dy;
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
QwtMatrixRasterData::QwtMatrixRasterData()
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
update();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtMatrixRasterData::~QwtMatrixRasterData()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the resampling algorithm
|
||||
|
||||
\param mode Resampling mode
|
||||
\sa resampleMode(), value()
|
||||
*/
|
||||
void QwtMatrixRasterData::setResampleMode( ResampleMode mode )
|
||||
{
|
||||
d_data->resampleMode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return resampling algorithm
|
||||
\sa setResampleMode(), value()
|
||||
*/
|
||||
QwtMatrixRasterData::ResampleMode QwtMatrixRasterData::resampleMode() const
|
||||
{
|
||||
return d_data->resampleMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign the bounding interval for an axis
|
||||
|
||||
Setting the bounding intervals for the X/Y axis is mandatory
|
||||
to define the positions for the values of the value matrix.
|
||||
The interval in Z direction defines the possible range for
|
||||
the values in the matrix, what is f.e used by QwtPlotSpectrogram
|
||||
to map values to colors. The Z-interval might be the bounding
|
||||
interval of the values in the matrix, but usually it isn't.
|
||||
( f.e a interval of 0.0-100.0 for values in percentage )
|
||||
|
||||
\param axis X, Y or Z axis
|
||||
\param interval Interval
|
||||
|
||||
\sa QwtRasterData::interval(), setValueMatrix()
|
||||
*/
|
||||
void QwtMatrixRasterData::setInterval(
|
||||
Qt::Axis axis, const QwtInterval &interval )
|
||||
{
|
||||
QwtRasterData::setInterval( axis, interval );
|
||||
update();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a value matrix
|
||||
|
||||
The positions of the values are calculated by dividing
|
||||
the bounding rectangle of the X/Y intervals into equidistant
|
||||
rectangles ( pixels ). Each value corresponds to the center of
|
||||
a pixel.
|
||||
|
||||
\param values Vector of values
|
||||
\param numColumns Number of columns
|
||||
|
||||
\sa valueMatrix(), numColumns(), numRows(), setInterval()()
|
||||
*/
|
||||
void QwtMatrixRasterData::setValueMatrix(
|
||||
const QVector<double> &values, int numColumns )
|
||||
{
|
||||
d_data->values = values;
|
||||
d_data->numColumns = qMax( numColumns, 0 );
|
||||
update();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Value matrix
|
||||
\sa setValueMatrix(), numColumns(), numRows(), setInterval()
|
||||
*/
|
||||
const QVector<double> QwtMatrixRasterData::valueMatrix() const
|
||||
{
|
||||
return d_data->values;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change a single value in the matrix
|
||||
|
||||
\param row Row index
|
||||
\param col Column index
|
||||
\param value New value
|
||||
|
||||
\sa value(), setValueMatrix()
|
||||
*/
|
||||
void QwtMatrixRasterData::setValue( int row, int col, double value )
|
||||
{
|
||||
if ( row >= 0 && row < d_data->numRows &&
|
||||
col >= 0 && col < d_data->numColumns )
|
||||
{
|
||||
const int index = row * d_data->numColumns + col;
|
||||
d_data->values.data()[ index ] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of columns of the value matrix
|
||||
\sa valueMatrix(), numRows(), setValueMatrix()
|
||||
*/
|
||||
int QwtMatrixRasterData::numColumns() const
|
||||
{
|
||||
return d_data->numColumns;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Number of rows of the value matrix
|
||||
\sa valueMatrix(), numColumns(), setValueMatrix()
|
||||
*/
|
||||
int QwtMatrixRasterData::numRows() const
|
||||
{
|
||||
return d_data->numRows;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Calculate the pixel hint
|
||||
|
||||
pixelHint() returns the geometry of a pixel, that can be used
|
||||
to calculate the resolution and alignment of the plot item, that is
|
||||
representing the data.
|
||||
|
||||
- NearestNeighbour\n
|
||||
pixelHint() returns the surrounding pixel of the top left value
|
||||
in the matrix.
|
||||
|
||||
- BilinearInterpolation\n
|
||||
Returns an empty rectangle recommending
|
||||
to render in target device ( f.e. screen ) resolution.
|
||||
|
||||
\param area Requested area, ignored
|
||||
\return Calculated hint
|
||||
|
||||
\sa ResampleMode, setMatrix(), setInterval()
|
||||
*/
|
||||
QRectF QwtMatrixRasterData::pixelHint( const QRectF &area ) const
|
||||
{
|
||||
Q_UNUSED( area )
|
||||
|
||||
QRectF rect;
|
||||
if ( d_data->resampleMode == NearestNeighbour )
|
||||
{
|
||||
const QwtInterval intervalX = interval( Qt::XAxis );
|
||||
const QwtInterval intervalY = interval( Qt::YAxis );
|
||||
if ( intervalX.isValid() && intervalY.isValid() )
|
||||
{
|
||||
rect = QRectF( intervalX.minValue(), intervalY.minValue(),
|
||||
d_data->dx, d_data->dy );
|
||||
}
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the value at a raster position
|
||||
|
||||
\param x X value in plot coordinates
|
||||
\param y Y value in plot coordinates
|
||||
|
||||
\sa ResampleMode
|
||||
*/
|
||||
double QwtMatrixRasterData::value( double x, double y ) const
|
||||
{
|
||||
const QwtInterval xInterval = interval( Qt::XAxis );
|
||||
const QwtInterval yInterval = interval( Qt::YAxis );
|
||||
|
||||
if ( !( xInterval.contains(x) && yInterval.contains(y) ) )
|
||||
return qQNaN();
|
||||
|
||||
double value;
|
||||
|
||||
switch( d_data->resampleMode )
|
||||
{
|
||||
case BilinearInterpolation:
|
||||
{
|
||||
int col1 = qRound( (x - xInterval.minValue() ) / d_data->dx ) - 1;
|
||||
int row1 = qRound( (y - yInterval.minValue() ) / d_data->dy ) - 1;
|
||||
int col2 = col1 + 1;
|
||||
int row2 = row1 + 1;
|
||||
|
||||
if ( col1 < 0 )
|
||||
col1 = col2;
|
||||
else if ( col2 >= static_cast<int>( d_data->numColumns ) )
|
||||
col2 = col1;
|
||||
|
||||
if ( row1 < 0 )
|
||||
row1 = row2;
|
||||
else if ( row2 >= static_cast<int>( d_data->numRows ) )
|
||||
row2 = row1;
|
||||
|
||||
const double v11 = d_data->value( row1, col1 );
|
||||
const double v21 = d_data->value( row1, col2 );
|
||||
const double v12 = d_data->value( row2, col1 );
|
||||
const double v22 = d_data->value( row2, col2 );
|
||||
|
||||
const double x2 = xInterval.minValue() +
|
||||
( col2 + 0.5 ) * d_data->dx;
|
||||
const double y2 = yInterval.minValue() +
|
||||
( row2 + 0.5 ) * d_data->dy;
|
||||
|
||||
const double rx = ( x2 - x ) / d_data->dx;
|
||||
const double ry = ( y2 - y ) / d_data->dy;
|
||||
|
||||
const double vr1 = rx * v11 + ( 1.0 - rx ) * v21;
|
||||
const double vr2 = rx * v12 + ( 1.0 - rx ) * v22;
|
||||
|
||||
value = ry * vr1 + ( 1.0 - ry ) * vr2;
|
||||
|
||||
break;
|
||||
}
|
||||
case NearestNeighbour:
|
||||
default:
|
||||
{
|
||||
int row = int( (y - yInterval.minValue() ) / d_data->dy );
|
||||
int col = int( (x - xInterval.minValue() ) / d_data->dx );
|
||||
|
||||
// In case of intervals, where the maximum is included
|
||||
// we get out of bound for row/col, when the value for the
|
||||
// maximum is requested. Instead we return the value
|
||||
// from the last row/col
|
||||
|
||||
if ( row >= d_data->numRows )
|
||||
row = d_data->numRows - 1;
|
||||
|
||||
if ( col >= d_data->numColumns )
|
||||
col = d_data->numColumns - 1;
|
||||
|
||||
value = d_data->value( row, col );
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void QwtMatrixRasterData::update()
|
||||
{
|
||||
d_data->numRows = 0;
|
||||
d_data->dx = 0.0;
|
||||
d_data->dy = 0.0;
|
||||
|
||||
if ( d_data->numColumns > 0 )
|
||||
{
|
||||
d_data->numRows = d_data->values.size() / d_data->numColumns;
|
||||
|
||||
const QwtInterval xInterval = interval( Qt::XAxis );
|
||||
const QwtInterval yInterval = interval( Qt::YAxis );
|
||||
if ( xInterval.isValid() )
|
||||
d_data->dx = xInterval.width() / d_data->numColumns;
|
||||
if ( yInterval.isValid() )
|
||||
d_data->dy = yInterval.width() / d_data->numRows;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_MATRIX_RASTER_DATA_H
|
||||
#define QWT_MATRIX_RASTER_DATA_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_raster_data.h"
|
||||
#include <qvector.h>
|
||||
|
||||
/*!
|
||||
\brief A class representing a matrix of values as raster data
|
||||
|
||||
QwtMatrixRasterData implements an interface for a matrix of
|
||||
equidistant values, that can be used by a QwtPlotRasterItem.
|
||||
It implements a couple of resampling algorithms, to provide
|
||||
values for positions, that or not on the value matrix.
|
||||
*/
|
||||
class QWT_EXPORT QwtMatrixRasterData: public QwtRasterData
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Resampling algorithm
|
||||
The default setting is NearestNeighbour;
|
||||
*/
|
||||
enum ResampleMode
|
||||
{
|
||||
/*!
|
||||
Return the value from the matrix, that is nearest to the
|
||||
the requested position.
|
||||
*/
|
||||
NearestNeighbour,
|
||||
|
||||
/*!
|
||||
Interpolate the value from the distances and values of the
|
||||
4 surrounding values in the matrix,
|
||||
*/
|
||||
BilinearInterpolation
|
||||
};
|
||||
|
||||
QwtMatrixRasterData();
|
||||
virtual ~QwtMatrixRasterData();
|
||||
|
||||
void setResampleMode(ResampleMode mode);
|
||||
ResampleMode resampleMode() const;
|
||||
|
||||
virtual void setInterval( Qt::Axis, const QwtInterval & );
|
||||
|
||||
void setValueMatrix( const QVector<double> &values, int numColumns );
|
||||
const QVector<double> valueMatrix() const;
|
||||
|
||||
void setValue( int row, int col, double value );
|
||||
|
||||
int numColumns() const;
|
||||
int numRows() const;
|
||||
|
||||
virtual QRectF pixelHint( const QRectF & ) const;
|
||||
|
||||
virtual double value( double x, double y ) const;
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,593 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_null_paintdevice.h"
|
||||
#include <qpaintengine.h>
|
||||
#include <qpixmap.h>
|
||||
|
||||
class QwtNullPaintDevice::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
mode( QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
}
|
||||
|
||||
QwtNullPaintDevice::Mode mode;
|
||||
};
|
||||
|
||||
class QwtNullPaintDevice::PaintEngine: public QPaintEngine
|
||||
{
|
||||
public:
|
||||
PaintEngine();
|
||||
|
||||
virtual bool begin( QPaintDevice * );
|
||||
virtual bool end();
|
||||
|
||||
virtual Type type () const;
|
||||
virtual void updateState(const QPaintEngineState &);
|
||||
|
||||
virtual void drawRects(const QRect *, int );
|
||||
virtual void drawRects(const QRectF *, int );
|
||||
|
||||
virtual void drawLines(const QLine *, int );
|
||||
virtual void drawLines(const QLineF *, int );
|
||||
|
||||
virtual void drawEllipse(const QRectF &);
|
||||
virtual void drawEllipse(const QRect &);
|
||||
|
||||
virtual void drawPath(const QPainterPath &);
|
||||
|
||||
virtual void drawPoints(const QPointF *, int );
|
||||
virtual void drawPoints(const QPoint *, int );
|
||||
|
||||
virtual void drawPolygon(const QPointF *, int , PolygonDrawMode );
|
||||
virtual void drawPolygon(const QPoint *, int , PolygonDrawMode );
|
||||
|
||||
virtual void drawPixmap(const QRectF &,
|
||||
const QPixmap &, const QRectF &);
|
||||
|
||||
virtual void drawTextItem(const QPointF &, const QTextItem &);
|
||||
|
||||
virtual void drawTiledPixmap(const QRectF &,
|
||||
const QPixmap &, const QPointF &s);
|
||||
|
||||
virtual void drawImage(const QRectF &,
|
||||
const QImage &, const QRectF &, Qt::ImageConversionFlags );
|
||||
|
||||
private:
|
||||
QwtNullPaintDevice *nullDevice();
|
||||
};
|
||||
|
||||
QwtNullPaintDevice::PaintEngine::PaintEngine():
|
||||
QPaintEngine( QPaintEngine::AllFeatures )
|
||||
{
|
||||
}
|
||||
|
||||
bool QwtNullPaintDevice::PaintEngine::begin( QPaintDevice * )
|
||||
{
|
||||
setActive( true );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QwtNullPaintDevice::PaintEngine::end()
|
||||
{
|
||||
setActive( false );
|
||||
return true;
|
||||
}
|
||||
|
||||
QPaintEngine::Type QwtNullPaintDevice::PaintEngine::type() const
|
||||
{
|
||||
return QPaintEngine::User;
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawRects(
|
||||
const QRect *rects, int rectCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawRects( rects, rectCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawRects( rects, rectCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawRects(
|
||||
const QRectF *rects, int rectCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawRects( rects, rectCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawRects( rects, rectCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawLines(
|
||||
const QLine *lines, int lineCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawLines( lines, lineCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawLines( lines, lineCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawLines(
|
||||
const QLineF *lines, int lineCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawLines( lines, lineCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawLines( lines, lineCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawEllipse(
|
||||
const QRectF &rect)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawEllipse( rect );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawEllipse( rect );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawEllipse(
|
||||
const QRect &rect)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawEllipse( rect );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawEllipse( rect );
|
||||
}
|
||||
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPath(
|
||||
const QPainterPath &path)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
device->drawPath( path );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPoints(
|
||||
const QPointF *points, int pointCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawPoints( points, pointCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawPoints( points, pointCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPoints(
|
||||
const QPoint *points, int pointCount)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawPoints( points, pointCount );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawPoints( points, pointCount );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPolygon(
|
||||
const QPointF *points, int pointCount, PolygonDrawMode mode)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() == QwtNullPaintDevice::PathMode )
|
||||
{
|
||||
QPainterPath path;
|
||||
|
||||
if ( pointCount > 0 )
|
||||
{
|
||||
path.moveTo( points[0] );
|
||||
for ( int i = 1; i < pointCount; i++ )
|
||||
path.lineTo( points[i] );
|
||||
|
||||
if ( mode != PolylineMode )
|
||||
path.closeSubpath();
|
||||
}
|
||||
|
||||
device->drawPath( path );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawPolygon( points, pointCount, mode );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPolygon(
|
||||
const QPoint *points, int pointCount, PolygonDrawMode mode)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() == QwtNullPaintDevice::PathMode )
|
||||
{
|
||||
QPainterPath path;
|
||||
|
||||
if ( pointCount > 0 )
|
||||
{
|
||||
path.moveTo( points[0] );
|
||||
for ( int i = 1; i < pointCount; i++ )
|
||||
path.lineTo( points[i] );
|
||||
|
||||
if ( mode != PolylineMode )
|
||||
path.closeSubpath();
|
||||
}
|
||||
|
||||
device->drawPath( path );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawPolygon( points, pointCount, mode );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawPixmap(
|
||||
const QRectF &rect, const QPixmap &pm, const QRectF &subRect )
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
device->drawPixmap( rect, pm, subRect );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawTextItem(
|
||||
const QPointF &pos, const QTextItem &textItem)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawTextItem( pos, textItem );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawTextItem( pos, textItem );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawTiledPixmap(
|
||||
const QRectF &rect, const QPixmap &pixmap,
|
||||
const QPointF &subRect)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
if ( device->mode() != QwtNullPaintDevice::NormalMode )
|
||||
{
|
||||
QPaintEngine::drawTiledPixmap( rect, pixmap, subRect );
|
||||
return;
|
||||
}
|
||||
|
||||
device->drawTiledPixmap( rect, pixmap, subRect );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::drawImage(
|
||||
const QRectF &rect, const QImage &image,
|
||||
const QRectF &subRect, Qt::ImageConversionFlags flags)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
device->drawImage( rect, image, subRect, flags );
|
||||
}
|
||||
|
||||
void QwtNullPaintDevice::PaintEngine::updateState(
|
||||
const QPaintEngineState &state)
|
||||
{
|
||||
QwtNullPaintDevice *device = nullDevice();
|
||||
if ( device == NULL )
|
||||
return;
|
||||
|
||||
device->updateState( state );
|
||||
}
|
||||
|
||||
inline QwtNullPaintDevice *QwtNullPaintDevice::PaintEngine::nullDevice()
|
||||
{
|
||||
if ( !isActive() )
|
||||
return NULL;
|
||||
|
||||
return static_cast<QwtNullPaintDevice *>( paintDevice() );
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtNullPaintDevice::QwtNullPaintDevice():
|
||||
d_engine( NULL )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtNullPaintDevice::~QwtNullPaintDevice()
|
||||
{
|
||||
delete d_engine;
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the render mode
|
||||
|
||||
\param mode New mode
|
||||
\sa mode()
|
||||
*/
|
||||
void QwtNullPaintDevice::setMode( Mode mode )
|
||||
{
|
||||
d_data->mode = mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Render mode
|
||||
\sa setMode()
|
||||
*/
|
||||
QwtNullPaintDevice::Mode QwtNullPaintDevice::mode() const
|
||||
{
|
||||
return d_data->mode;
|
||||
}
|
||||
|
||||
//! See QPaintDevice::paintEngine()
|
||||
QPaintEngine *QwtNullPaintDevice::paintEngine() const
|
||||
{
|
||||
if ( d_engine == NULL )
|
||||
{
|
||||
QwtNullPaintDevice *that =
|
||||
const_cast< QwtNullPaintDevice * >( this );
|
||||
|
||||
that->d_engine = new PaintEngine();
|
||||
}
|
||||
|
||||
return d_engine;
|
||||
}
|
||||
|
||||
/*!
|
||||
See QPaintDevice::metric()
|
||||
|
||||
\param deviceMetric Type of metric
|
||||
\return Metric information for the given paint device metric.
|
||||
|
||||
\sa sizeMetrics()
|
||||
*/
|
||||
int QwtNullPaintDevice::metric( PaintDeviceMetric deviceMetric ) const
|
||||
{
|
||||
int value;
|
||||
|
||||
switch ( deviceMetric )
|
||||
{
|
||||
case PdmWidth:
|
||||
{
|
||||
value = sizeMetrics().width();
|
||||
break;
|
||||
}
|
||||
case PdmHeight:
|
||||
{
|
||||
value = sizeMetrics().height();
|
||||
break;
|
||||
}
|
||||
case PdmNumColors:
|
||||
{
|
||||
value = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
case PdmDepth:
|
||||
{
|
||||
value = 32;
|
||||
break;
|
||||
}
|
||||
case PdmPhysicalDpiX:
|
||||
case PdmPhysicalDpiY:
|
||||
case PdmDpiY:
|
||||
case PdmDpiX:
|
||||
{
|
||||
value = 72;
|
||||
break;
|
||||
}
|
||||
case PdmWidthMM:
|
||||
{
|
||||
value = qRound( metric( PdmWidth ) * 25.4 / metric( PdmDpiX ) );
|
||||
break;
|
||||
}
|
||||
case PdmHeightMM:
|
||||
{
|
||||
value = qRound( metric( PdmHeight ) * 25.4 / metric( PdmDpiY ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
value = 0;
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawRects()
|
||||
void QwtNullPaintDevice::drawRects(
|
||||
const QRect *rects, int rectCount)
|
||||
{
|
||||
Q_UNUSED(rects);
|
||||
Q_UNUSED(rectCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawRects()
|
||||
void QwtNullPaintDevice::drawRects(
|
||||
const QRectF *rects, int rectCount)
|
||||
{
|
||||
Q_UNUSED(rects);
|
||||
Q_UNUSED(rectCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawLines()
|
||||
void QwtNullPaintDevice::drawLines(
|
||||
const QLine *lines, int lineCount)
|
||||
{
|
||||
Q_UNUSED(lines);
|
||||
Q_UNUSED(lineCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawLines()
|
||||
void QwtNullPaintDevice::drawLines(
|
||||
const QLineF *lines, int lineCount)
|
||||
{
|
||||
Q_UNUSED(lines);
|
||||
Q_UNUSED(lineCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawEllipse()
|
||||
void QwtNullPaintDevice::drawEllipse( const QRectF &rect )
|
||||
{
|
||||
Q_UNUSED(rect);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawEllipse()
|
||||
void QwtNullPaintDevice::drawEllipse( const QRect &rect )
|
||||
{
|
||||
Q_UNUSED(rect);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPath()
|
||||
void QwtNullPaintDevice::drawPath( const QPainterPath &path )
|
||||
{
|
||||
Q_UNUSED(path);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPoints()
|
||||
void QwtNullPaintDevice::drawPoints(
|
||||
const QPointF *points, int pointCount)
|
||||
{
|
||||
Q_UNUSED(points);
|
||||
Q_UNUSED(pointCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPoints()
|
||||
void QwtNullPaintDevice::drawPoints(
|
||||
const QPoint *points, int pointCount)
|
||||
{
|
||||
Q_UNUSED(points);
|
||||
Q_UNUSED(pointCount);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPolygon()
|
||||
void QwtNullPaintDevice::drawPolygon(
|
||||
const QPointF *points, int pointCount,
|
||||
QPaintEngine::PolygonDrawMode mode)
|
||||
{
|
||||
Q_UNUSED(points);
|
||||
Q_UNUSED(pointCount);
|
||||
Q_UNUSED(mode);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPolygon()
|
||||
void QwtNullPaintDevice::drawPolygon(
|
||||
const QPoint *points, int pointCount,
|
||||
QPaintEngine::PolygonDrawMode mode)
|
||||
{
|
||||
Q_UNUSED(points);
|
||||
Q_UNUSED(pointCount);
|
||||
Q_UNUSED(mode);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawPixmap()
|
||||
void QwtNullPaintDevice::drawPixmap( const QRectF &rect,
|
||||
const QPixmap &pm, const QRectF &subRect )
|
||||
{
|
||||
Q_UNUSED(rect);
|
||||
Q_UNUSED(pm);
|
||||
Q_UNUSED(subRect);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawTextItem()
|
||||
void QwtNullPaintDevice::drawTextItem(
|
||||
const QPointF &pos, const QTextItem &textItem)
|
||||
{
|
||||
Q_UNUSED(pos);
|
||||
Q_UNUSED(textItem);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawTiledPixmap()
|
||||
void QwtNullPaintDevice::drawTiledPixmap(
|
||||
const QRectF &rect, const QPixmap &pixmap,
|
||||
const QPointF &subRect)
|
||||
{
|
||||
Q_UNUSED(rect);
|
||||
Q_UNUSED(pixmap);
|
||||
Q_UNUSED(subRect);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::drawImage()
|
||||
void QwtNullPaintDevice::drawImage(
|
||||
const QRectF &rect, const QImage &image,
|
||||
const QRectF &subRect, Qt::ImageConversionFlags flags)
|
||||
{
|
||||
Q_UNUSED(rect);
|
||||
Q_UNUSED(image);
|
||||
Q_UNUSED(subRect);
|
||||
Q_UNUSED(flags);
|
||||
}
|
||||
|
||||
//! See QPaintEngine::updateState()
|
||||
void QwtNullPaintDevice::updateState(
|
||||
const QPaintEngineState &state )
|
||||
{
|
||||
Q_UNUSED(state);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_NULL_PAINT_DEVICE_H
|
||||
#define QWT_NULL_PAINT_DEVICE_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpaintdevice.h>
|
||||
#include <qpaintengine.h>
|
||||
|
||||
/*!
|
||||
\brief A null paint device doing nothing
|
||||
|
||||
Sometimes important layout/rendering geometries are not
|
||||
available or changeable from the public Qt class interface.
|
||||
( f.e hidden in the style implementation ).
|
||||
|
||||
QwtNullPaintDevice can be used to manipulate or filter out
|
||||
this information by analyzing the stream of paint primitives.
|
||||
|
||||
F.e. QwtNullPaintDevice is used by QwtPlotCanvas to identify
|
||||
styled backgrounds with rounded corners.
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtNullPaintDevice: public QPaintDevice
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Render mode
|
||||
|
||||
\sa setMode(), mode()
|
||||
*/
|
||||
enum Mode
|
||||
{
|
||||
/*!
|
||||
All vector graphic primitives are painted by
|
||||
the corresponding draw methods
|
||||
*/
|
||||
NormalMode,
|
||||
|
||||
/*!
|
||||
Vector graphic primitives ( beside polygons ) are mapped to a QPainterPath
|
||||
and are painted by drawPath. In PathMode mode
|
||||
only a few draw methods are called:
|
||||
|
||||
- drawPath()
|
||||
- drawPixmap()
|
||||
- drawImage()
|
||||
- drawPolygon()
|
||||
*/
|
||||
PolygonPathMode,
|
||||
|
||||
/*!
|
||||
Vector graphic primitives are mapped to a QPainterPath
|
||||
and are painted by drawPath. In PathMode mode
|
||||
only a few draw methods are called:
|
||||
|
||||
- drawPath()
|
||||
- drawPixmap()
|
||||
- drawImage()
|
||||
*/
|
||||
PathMode
|
||||
};
|
||||
|
||||
QwtNullPaintDevice();
|
||||
virtual ~QwtNullPaintDevice();
|
||||
|
||||
void setMode( Mode );
|
||||
Mode mode() const;
|
||||
|
||||
virtual QPaintEngine *paintEngine() const;
|
||||
|
||||
virtual int metric( PaintDeviceMetric metric ) const;
|
||||
|
||||
virtual void drawRects(const QRect *, int );
|
||||
virtual void drawRects(const QRectF *, int );
|
||||
|
||||
virtual void drawLines(const QLine *, int );
|
||||
virtual void drawLines(const QLineF *, int );
|
||||
|
||||
virtual void drawEllipse(const QRectF &);
|
||||
virtual void drawEllipse(const QRect &);
|
||||
|
||||
virtual void drawPath(const QPainterPath &);
|
||||
|
||||
virtual void drawPoints(const QPointF *, int );
|
||||
virtual void drawPoints(const QPoint *, int );
|
||||
|
||||
virtual void drawPolygon(
|
||||
const QPointF *, int , QPaintEngine::PolygonDrawMode );
|
||||
|
||||
virtual void drawPolygon(
|
||||
const QPoint *, int , QPaintEngine::PolygonDrawMode );
|
||||
|
||||
virtual void drawPixmap(const QRectF &,
|
||||
const QPixmap &, const QRectF &);
|
||||
|
||||
virtual void drawTextItem(const QPointF &, const QTextItem &);
|
||||
|
||||
virtual void drawTiledPixmap(const QRectF &,
|
||||
const QPixmap &, const QPointF &s);
|
||||
|
||||
virtual void drawImage(const QRectF &,
|
||||
const QImage &, const QRectF &, Qt::ImageConversionFlags );
|
||||
|
||||
virtual void updateState( const QPaintEngineState &state );
|
||||
|
||||
protected:
|
||||
//! \return Size needed to implement metric()
|
||||
virtual QSize sizeMetrics() const = 0;
|
||||
|
||||
private:
|
||||
class PaintEngine;
|
||||
PaintEngine *d_engine;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,188 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PAINTER_H
|
||||
#define QWT_PAINTER_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
|
||||
#include <qpoint.h>
|
||||
#include <qrect.h>
|
||||
#include <qpen.h>
|
||||
#include <qline.h>
|
||||
#include <qpalette.h>
|
||||
|
||||
class QPainter;
|
||||
class QBrush;
|
||||
class QColor;
|
||||
class QWidget;
|
||||
class QPolygonF;
|
||||
class QRectF;
|
||||
class QImage;
|
||||
class QPixmap;
|
||||
class QwtScaleMap;
|
||||
class QwtColorMap;
|
||||
class QwtInterval;
|
||||
|
||||
class QTextDocument;
|
||||
class QPainterPath;
|
||||
|
||||
/*!
|
||||
\brief A collection of QPainter workarounds
|
||||
*/
|
||||
class QWT_EXPORT QwtPainter
|
||||
{
|
||||
public:
|
||||
static void setPolylineSplitting( bool );
|
||||
static bool polylineSplitting();
|
||||
|
||||
static void setRoundingAlignment( bool );
|
||||
static bool roundingAlignment();
|
||||
static bool roundingAlignment(QPainter *);
|
||||
|
||||
static void drawText( QPainter *, double x, double y, const QString & );
|
||||
static void drawText( QPainter *, const QPointF &, const QString & );
|
||||
static void drawText( QPainter *, double x, double y, double w, double h,
|
||||
int flags, const QString & );
|
||||
static void drawText( QPainter *, const QRectF &,
|
||||
int flags, const QString & );
|
||||
|
||||
#ifndef QT_NO_RICHTEXT
|
||||
static void drawSimpleRichText( QPainter *, const QRectF &,
|
||||
int flags, const QTextDocument & );
|
||||
#endif
|
||||
|
||||
static void drawRect( QPainter *, double x, double y, double w, double h );
|
||||
static void drawRect( QPainter *, const QRectF &rect );
|
||||
static void fillRect( QPainter *, const QRectF &, const QBrush & );
|
||||
|
||||
static void drawEllipse( QPainter *, const QRectF & );
|
||||
static void drawPie( QPainter *, const QRectF & r, int a, int alen );
|
||||
|
||||
static void drawLine( QPainter *, double x1, double y1, double x2, double y2 );
|
||||
static void drawLine( QPainter *, const QPointF &p1, const QPointF &p2 );
|
||||
static void drawLine( QPainter *, const QLineF & );
|
||||
|
||||
static void drawPolygon( QPainter *, const QPolygonF & );
|
||||
static void drawPolyline( QPainter *, const QPolygonF & );
|
||||
static void drawPolyline( QPainter *, const QPointF *, int pointCount );
|
||||
|
||||
static void drawPolygon( QPainter *, const QPolygon & );
|
||||
static void drawPolyline( QPainter *, const QPolygon & );
|
||||
static void drawPolyline( QPainter *, const QPoint *, int pointCount );
|
||||
|
||||
static void drawPoint( QPainter *, const QPoint & );
|
||||
static void drawPoints( QPainter *, const QPolygon & );
|
||||
static void drawPoints( QPainter *, const QPoint *, int pointCount );
|
||||
|
||||
static void drawPoint( QPainter *, double x, double y );
|
||||
static void drawPoint( QPainter *, const QPointF & );
|
||||
static void drawPoints( QPainter *, const QPolygonF & );
|
||||
static void drawPoints( QPainter *, const QPointF *, int pointCount );
|
||||
|
||||
static void drawPath( QPainter *, const QPainterPath & );
|
||||
static void drawImage( QPainter *, const QRectF &, const QImage & );
|
||||
static void drawPixmap( QPainter *, const QRectF &, const QPixmap & );
|
||||
|
||||
static void drawRoundFrame( QPainter *,
|
||||
const QRectF &, const QPalette &, int lineWidth, int frameStyle );
|
||||
|
||||
static void drawRoundedFrame( QPainter *,
|
||||
const QRectF &, double xRadius, double yRadius,
|
||||
const QPalette &, int lineWidth, int frameStyle );
|
||||
|
||||
static void drawFrame( QPainter *, const QRectF &rect,
|
||||
const QPalette &palette, QPalette::ColorRole foregroundRole,
|
||||
int lineWidth, int midLineWidth, int frameStyle );
|
||||
|
||||
static void drawFocusRect( QPainter *, const QWidget * );
|
||||
static void drawFocusRect( QPainter *, const QWidget *, const QRect & );
|
||||
|
||||
static void drawColorBar( QPainter *painter,
|
||||
const QwtColorMap &, const QwtInterval &,
|
||||
const QwtScaleMap &, Qt::Orientation, const QRectF & );
|
||||
|
||||
static bool isAligning( QPainter *painter );
|
||||
static bool isX11GraphicsSystem();
|
||||
|
||||
static void fillPixmap( const QWidget *,
|
||||
QPixmap &, const QPoint &offset = QPoint() );
|
||||
|
||||
static void drawBackgound( QPainter *painter,
|
||||
const QRectF &rect, const QWidget *widget );
|
||||
|
||||
static QPixmap backingStore( QWidget *, const QSize & );
|
||||
|
||||
private:
|
||||
static bool d_polylineSplitting;
|
||||
static bool d_roundingAlignment;
|
||||
};
|
||||
|
||||
//! Wrapper for QPainter::drawPoint()
|
||||
inline void QwtPainter::drawPoint( QPainter *painter, double x, double y )
|
||||
{
|
||||
QwtPainter::drawPoint( painter, QPointF( x, y ) );
|
||||
}
|
||||
|
||||
//! Wrapper for QPainter::drawPoints()
|
||||
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygon &polygon )
|
||||
{
|
||||
drawPoints( painter, polygon.data(), polygon.size() );
|
||||
}
|
||||
|
||||
//! Wrapper for QPainter::drawPoints()
|
||||
inline void QwtPainter::drawPoints( QPainter *painter, const QPolygonF &polygon )
|
||||
{
|
||||
drawPoints( painter, polygon.data(), polygon.size() );
|
||||
}
|
||||
|
||||
//! Wrapper for QPainter::drawLine()
|
||||
inline void QwtPainter::drawLine( QPainter *painter,
|
||||
double x1, double y1, double x2, double y2 )
|
||||
{
|
||||
QwtPainter::drawLine( painter, QPointF( x1, y1 ), QPointF( x2, y2 ) );
|
||||
}
|
||||
|
||||
//! Wrapper for QPainter::drawLine()
|
||||
inline void QwtPainter::drawLine( QPainter *painter, const QLineF &line )
|
||||
{
|
||||
QwtPainter::drawLine( painter, line.p1(), line.p2() );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, when line splitting for the raster paint engine is enabled.
|
||||
\sa setPolylineSplitting()
|
||||
*/
|
||||
inline bool QwtPainter::polylineSplitting()
|
||||
{
|
||||
return d_polylineSplitting;
|
||||
}
|
||||
|
||||
/*!
|
||||
Check whether coordinates should be rounded, before they are painted
|
||||
to a paint engine that rounds to integer values. For other paint engines
|
||||
( PDF, SVG ), this flag has no effect.
|
||||
|
||||
\return True, when rounding is enabled
|
||||
\sa setRoundingAlignment(), isAligning()
|
||||
*/
|
||||
inline bool QwtPainter::roundingAlignment()
|
||||
{
|
||||
return d_roundingAlignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return roundingAlignment() && isAligning(painter);
|
||||
\param painter Painter
|
||||
*/
|
||||
inline bool QwtPainter::roundingAlignment(QPainter *painter)
|
||||
{
|
||||
return d_roundingAlignment && isAligning(painter);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,237 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_painter_command.h"
|
||||
|
||||
//! Construct an invalid command
|
||||
QwtPainterCommand::QwtPainterCommand():
|
||||
d_type( Invalid )
|
||||
{
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
QwtPainterCommand::QwtPainterCommand( const QPainterPath &path ):
|
||||
d_type( Path )
|
||||
{
|
||||
d_path = new QPainterPath( path );
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor for Pixmap paint operation
|
||||
|
||||
\param rect Target rectangle
|
||||
\param pixmap Pixmap
|
||||
\param subRect Rectangle inside the pixmap
|
||||
|
||||
\sa QPainter::drawPixmap()
|
||||
*/
|
||||
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
|
||||
const QPixmap &pixmap, const QRectF& subRect ):
|
||||
d_type( Pixmap )
|
||||
{
|
||||
d_pixmapData = new PixmapData();
|
||||
d_pixmapData->rect = rect;
|
||||
d_pixmapData->pixmap = pixmap;
|
||||
d_pixmapData->subRect = subRect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor for Image paint operation
|
||||
|
||||
\param rect Target rectangle
|
||||
\param image Image
|
||||
\param subRect Rectangle inside the image
|
||||
\param flags Conversion flags
|
||||
|
||||
\sa QPainter::drawImage()
|
||||
*/
|
||||
QwtPainterCommand::QwtPainterCommand( const QRectF &rect,
|
||||
const QImage &image, const QRectF& subRect,
|
||||
Qt::ImageConversionFlags flags ):
|
||||
d_type( Image )
|
||||
{
|
||||
d_imageData = new ImageData();
|
||||
d_imageData->rect = rect;
|
||||
d_imageData->image = image;
|
||||
d_imageData->subRect = subRect;
|
||||
d_imageData->flags = flags;
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor for State paint operation
|
||||
\param state Paint engine state
|
||||
*/
|
||||
QwtPainterCommand::QwtPainterCommand( const QPaintEngineState &state ):
|
||||
d_type( State )
|
||||
{
|
||||
d_stateData = new StateData();
|
||||
|
||||
d_stateData->flags = state.state();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyPen )
|
||||
d_stateData->pen = state.pen();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyBrush )
|
||||
d_stateData->brush = state.brush();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyBrushOrigin )
|
||||
d_stateData->brushOrigin = state.brushOrigin();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyFont )
|
||||
d_stateData->font = state.font();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyBackground )
|
||||
{
|
||||
d_stateData->backgroundMode = state.backgroundMode();
|
||||
d_stateData->backgroundBrush = state.backgroundBrush();
|
||||
}
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyTransform )
|
||||
d_stateData->transform = state.transform();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyClipEnabled )
|
||||
d_stateData->isClipEnabled = state.isClipEnabled();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyClipRegion )
|
||||
{
|
||||
d_stateData->clipRegion = state.clipRegion();
|
||||
d_stateData->clipOperation = state.clipOperation();
|
||||
}
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyClipPath )
|
||||
{
|
||||
d_stateData->clipPath = state.clipPath();
|
||||
d_stateData->clipOperation = state.clipOperation();
|
||||
}
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyHints )
|
||||
d_stateData->renderHints = state.renderHints();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyCompositionMode )
|
||||
d_stateData->compositionMode = state.compositionMode();
|
||||
|
||||
if ( d_stateData->flags & QPaintEngine::DirtyOpacity )
|
||||
d_stateData->opacity = state.opacity();
|
||||
}
|
||||
|
||||
/*!
|
||||
Copy constructor
|
||||
\param other Command to be copied
|
||||
|
||||
*/
|
||||
QwtPainterCommand::QwtPainterCommand(const QwtPainterCommand &other)
|
||||
{
|
||||
copy( other );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPainterCommand::~QwtPainterCommand()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
Assignment operator
|
||||
|
||||
\param other Command to be copied
|
||||
\return Modified command
|
||||
*/
|
||||
QwtPainterCommand &QwtPainterCommand::operator=(const QwtPainterCommand &other)
|
||||
{
|
||||
reset();
|
||||
copy( other );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void QwtPainterCommand::copy( const QwtPainterCommand &other )
|
||||
{
|
||||
d_type = other.d_type;
|
||||
|
||||
switch( other.d_type )
|
||||
{
|
||||
case Path:
|
||||
{
|
||||
d_path = new QPainterPath( *other.d_path );
|
||||
break;
|
||||
}
|
||||
case Pixmap:
|
||||
{
|
||||
d_pixmapData = new PixmapData( *other.d_pixmapData );
|
||||
break;
|
||||
}
|
||||
case Image:
|
||||
{
|
||||
d_imageData = new ImageData( *other.d_imageData );
|
||||
break;
|
||||
}
|
||||
case State:
|
||||
{
|
||||
d_stateData = new StateData( *other.d_stateData );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void QwtPainterCommand::reset()
|
||||
{
|
||||
switch( d_type )
|
||||
{
|
||||
case Path:
|
||||
{
|
||||
delete d_path;
|
||||
break;
|
||||
}
|
||||
case Pixmap:
|
||||
{
|
||||
delete d_pixmapData;
|
||||
break;
|
||||
}
|
||||
case Image:
|
||||
{
|
||||
delete d_imageData;
|
||||
break;
|
||||
}
|
||||
case State:
|
||||
{
|
||||
delete d_stateData;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
d_type = Invalid;
|
||||
}
|
||||
|
||||
//! \return Painter path to be painted
|
||||
QPainterPath *QwtPainterCommand::path()
|
||||
{
|
||||
return d_path;
|
||||
}
|
||||
|
||||
//! \return Attributes how to paint a QPixmap
|
||||
QwtPainterCommand::PixmapData* QwtPainterCommand::pixmapData()
|
||||
{
|
||||
return d_pixmapData;
|
||||
}
|
||||
|
||||
//! \return Attributes how to paint a QImage
|
||||
QwtPainterCommand::ImageData* QwtPainterCommand::imageData()
|
||||
{
|
||||
return d_imageData;
|
||||
}
|
||||
|
||||
//! \return Attributes of a state change
|
||||
QwtPainterCommand::StateData* QwtPainterCommand::stateData()
|
||||
{
|
||||
return d_stateData;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PAINTER_COMMAND_H
|
||||
#define QWT_PAINTER_COMMAND_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qpaintengine.h>
|
||||
#include <qpixmap.h>
|
||||
#include <qimage.h>
|
||||
#include <qpolygon.h>
|
||||
|
||||
class QPainterPath;
|
||||
|
||||
/*!
|
||||
QwtPainterCommand represents the attributes of a paint operation
|
||||
how it is used between QPainter and QPaintDevice
|
||||
|
||||
It is used by QwtGraphic to record and replay paint operations
|
||||
|
||||
\sa QwtGraphic::commands()
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPainterCommand
|
||||
{
|
||||
public:
|
||||
//! Type of the paint command
|
||||
enum Type
|
||||
{
|
||||
//! Invalid command
|
||||
Invalid = -1,
|
||||
|
||||
//! Draw a QPainterPath
|
||||
Path,
|
||||
|
||||
//! Draw a QPixmap
|
||||
Pixmap,
|
||||
|
||||
//! Draw a QImage
|
||||
Image,
|
||||
|
||||
//! QPainter state change
|
||||
State
|
||||
};
|
||||
|
||||
//! Attributes how to paint a QPixmap
|
||||
struct PixmapData
|
||||
{
|
||||
QRectF rect;
|
||||
QPixmap pixmap;
|
||||
QRectF subRect;
|
||||
};
|
||||
|
||||
//! Attributes how to paint a QImage
|
||||
struct ImageData
|
||||
{
|
||||
QRectF rect;
|
||||
QImage image;
|
||||
QRectF subRect;
|
||||
Qt::ImageConversionFlags flags;
|
||||
};
|
||||
|
||||
//! Attributes of a state change
|
||||
struct StateData
|
||||
{
|
||||
QPaintEngine::DirtyFlags flags;
|
||||
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
QPointF brushOrigin;
|
||||
QBrush backgroundBrush;
|
||||
Qt::BGMode backgroundMode;
|
||||
QFont font;
|
||||
QMatrix matrix;
|
||||
QTransform transform;
|
||||
|
||||
Qt::ClipOperation clipOperation;
|
||||
QRegion clipRegion;
|
||||
QPainterPath clipPath;
|
||||
bool isClipEnabled;
|
||||
|
||||
QPainter::RenderHints renderHints;
|
||||
QPainter::CompositionMode compositionMode;
|
||||
qreal opacity;
|
||||
};
|
||||
|
||||
QwtPainterCommand();
|
||||
QwtPainterCommand(const QwtPainterCommand &);
|
||||
|
||||
QwtPainterCommand( const QPainterPath & );
|
||||
|
||||
QwtPainterCommand( const QRectF &rect,
|
||||
const QPixmap &, const QRectF& subRect );
|
||||
|
||||
QwtPainterCommand( const QRectF &rect,
|
||||
const QImage &, const QRectF& subRect,
|
||||
Qt::ImageConversionFlags );
|
||||
|
||||
QwtPainterCommand( const QPaintEngineState & );
|
||||
|
||||
~QwtPainterCommand();
|
||||
|
||||
QwtPainterCommand &operator=(const QwtPainterCommand & );
|
||||
|
||||
Type type() const;
|
||||
|
||||
QPainterPath *path();
|
||||
const QPainterPath *path() const;
|
||||
|
||||
PixmapData* pixmapData();
|
||||
const PixmapData* pixmapData() const;
|
||||
|
||||
ImageData* imageData();
|
||||
const ImageData* imageData() const;
|
||||
|
||||
StateData* stateData();
|
||||
const StateData* stateData() const;
|
||||
|
||||
private:
|
||||
void copy( const QwtPainterCommand & );
|
||||
void reset();
|
||||
|
||||
Type d_type;
|
||||
|
||||
union
|
||||
{
|
||||
QPainterPath *d_path;
|
||||
PixmapData *d_pixmapData;
|
||||
ImageData *d_imageData;
|
||||
StateData *d_stateData;
|
||||
};
|
||||
};
|
||||
|
||||
//! \return Type of the command
|
||||
inline QwtPainterCommand::Type QwtPainterCommand::type() const
|
||||
{
|
||||
return d_type;
|
||||
}
|
||||
|
||||
//! \return Painter path to be painted
|
||||
inline const QPainterPath *QwtPainterCommand::path() const
|
||||
{
|
||||
return d_path;
|
||||
}
|
||||
|
||||
//! \return Attributes how to paint a QPixmap
|
||||
inline const QwtPainterCommand::PixmapData*
|
||||
QwtPainterCommand::pixmapData() const
|
||||
{
|
||||
return d_pixmapData;
|
||||
}
|
||||
|
||||
//! \return Attributes how to paint a QImage
|
||||
inline const QwtPainterCommand::ImageData *
|
||||
QwtPainterCommand::imageData() const
|
||||
{
|
||||
return d_imageData;
|
||||
}
|
||||
|
||||
//! \return Attributes of a state change
|
||||
inline const QwtPainterCommand::StateData *
|
||||
QwtPainterCommand::stateData() const
|
||||
{
|
||||
return d_stateData;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,538 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_panner.h"
|
||||
#include "qwt_picker.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qpainter.h>
|
||||
#include <qpixmap.h>
|
||||
#include <qevent.h>
|
||||
#include <qcursor.h>
|
||||
#include <qbitmap.h>
|
||||
|
||||
static QVector<QwtPicker *> qwtActivePickers( QWidget *w )
|
||||
{
|
||||
QVector<QwtPicker *> pickers;
|
||||
|
||||
QObjectList children = w->children();
|
||||
for ( int i = 0; i < children.size(); i++ )
|
||||
{
|
||||
QwtPicker *picker = qobject_cast<QwtPicker *>( children[i] );
|
||||
if ( picker && picker->isEnabled() )
|
||||
pickers += picker;
|
||||
}
|
||||
|
||||
return pickers;
|
||||
}
|
||||
|
||||
class QwtPanner::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
button( Qt::LeftButton ),
|
||||
buttonModifiers( Qt::NoModifier ),
|
||||
abortKey( Qt::Key_Escape ),
|
||||
abortKeyModifiers( Qt::NoModifier ),
|
||||
#ifndef QT_NO_CURSOR
|
||||
cursor( NULL ),
|
||||
restoreCursor( NULL ),
|
||||
hasCursor( false ),
|
||||
#endif
|
||||
isEnabled( false )
|
||||
{
|
||||
orientations = Qt::Vertical | Qt::Horizontal;
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
#ifndef QT_NO_CURSOR
|
||||
delete cursor;
|
||||
delete restoreCursor;
|
||||
#endif
|
||||
}
|
||||
|
||||
Qt::MouseButton button;
|
||||
Qt::KeyboardModifiers buttonModifiers;
|
||||
|
||||
int abortKey;
|
||||
Qt::KeyboardModifiers abortKeyModifiers;
|
||||
|
||||
QPoint initialPos;
|
||||
QPoint pos;
|
||||
|
||||
QPixmap pixmap;
|
||||
QBitmap contentsMask;
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
QCursor *cursor;
|
||||
QCursor *restoreCursor;
|
||||
bool hasCursor;
|
||||
#endif
|
||||
bool isEnabled;
|
||||
Qt::Orientations orientations;
|
||||
};
|
||||
|
||||
/*!
|
||||
Creates an panner that is enabled for the left mouse button.
|
||||
|
||||
\param parent Parent widget to be panned
|
||||
*/
|
||||
QwtPanner::QwtPanner( QWidget *parent ):
|
||||
QWidget( parent )
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
|
||||
setAttribute( Qt::WA_TransparentForMouseEvents );
|
||||
setAttribute( Qt::WA_NoSystemBackground );
|
||||
setFocusPolicy( Qt::NoFocus );
|
||||
hide();
|
||||
|
||||
setEnabled( true );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPanner::~QwtPanner()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the mouse button and modifiers used for panning
|
||||
The defaults are Qt::LeftButton and Qt::NoModifier
|
||||
*/
|
||||
void QwtPanner::setMouseButton( Qt::MouseButton button,
|
||||
Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->button = button;
|
||||
d_data->buttonModifiers = modifiers;
|
||||
}
|
||||
|
||||
//! Get mouse button and modifiers used for panning
|
||||
void QwtPanner::getMouseButton( Qt::MouseButton &button,
|
||||
Qt::KeyboardModifiers &modifiers ) const
|
||||
{
|
||||
button = d_data->button;
|
||||
modifiers = d_data->buttonModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the abort key
|
||||
The defaults are Qt::Key_Escape and Qt::NoModifiers
|
||||
|
||||
\param key Key ( See Qt::Keycode )
|
||||
\param modifiers Keyboard modifiers
|
||||
*/
|
||||
void QwtPanner::setAbortKey( int key,
|
||||
Qt::KeyboardModifiers modifiers )
|
||||
{
|
||||
d_data->abortKey = key;
|
||||
d_data->abortKeyModifiers = modifiers;
|
||||
}
|
||||
|
||||
//! Get the abort key and modifiers
|
||||
void QwtPanner::getAbortKey( int &key,
|
||||
Qt::KeyboardModifiers &modifiers ) const
|
||||
{
|
||||
key = d_data->abortKey;
|
||||
modifiers = d_data->abortKeyModifiers;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the cursor, that is active while panning
|
||||
The default is the cursor of the parent widget.
|
||||
|
||||
\param cursor New cursor
|
||||
|
||||
\sa setCursor()
|
||||
*/
|
||||
#ifndef QT_NO_CURSOR
|
||||
void QwtPanner::setCursor( const QCursor &cursor )
|
||||
{
|
||||
d_data->cursor = new QCursor( cursor );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\return Cursor that is active while panning
|
||||
\sa setCursor()
|
||||
*/
|
||||
#ifndef QT_NO_CURSOR
|
||||
const QCursor QwtPanner::cursor() const
|
||||
{
|
||||
if ( d_data->cursor )
|
||||
return *d_data->cursor;
|
||||
|
||||
if ( parentWidget() )
|
||||
return parentWidget()->cursor();
|
||||
|
||||
return QCursor();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
\brief En/disable the panner
|
||||
|
||||
When enabled is true an event filter is installed for
|
||||
the observed widget, otherwise the event filter is removed.
|
||||
|
||||
\param on true or false
|
||||
\sa isEnabled(), eventFilter()
|
||||
*/
|
||||
void QwtPanner::setEnabled( bool on )
|
||||
{
|
||||
if ( d_data->isEnabled != on )
|
||||
{
|
||||
d_data->isEnabled = on;
|
||||
|
||||
QWidget *w = parentWidget();
|
||||
if ( w )
|
||||
{
|
||||
if ( d_data->isEnabled )
|
||||
{
|
||||
w->installEventFilter( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
w->removeEventFilter( this );
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the orientations, where panning is enabled
|
||||
The default value is in both directions: Qt::Horizontal | Qt::Vertical
|
||||
|
||||
/param o Orientation
|
||||
*/
|
||||
void QwtPanner::setOrientations( Qt::Orientations o )
|
||||
{
|
||||
d_data->orientations = o;
|
||||
}
|
||||
|
||||
//! Return the orientation, where paning is enabled
|
||||
Qt::Orientations QwtPanner::orientations() const
|
||||
{
|
||||
return d_data->orientations;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True if an orientation is enabled
|
||||
\sa orientations(), setOrientations()
|
||||
*/
|
||||
bool QwtPanner::isOrientationEnabled( Qt::Orientation o ) const
|
||||
{
|
||||
return d_data->orientations & o;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true when enabled, false otherwise
|
||||
\sa setEnabled, eventFilter()
|
||||
*/
|
||||
bool QwtPanner::isEnabled() const
|
||||
{
|
||||
return d_data->isEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Paint event
|
||||
|
||||
Repaint the grabbed pixmap on its current position and
|
||||
fill the empty spaces by the background of the parent widget.
|
||||
|
||||
\param pe Paint event
|
||||
*/
|
||||
void QwtPanner::paintEvent( QPaintEvent *pe )
|
||||
{
|
||||
int dx = d_data->pos.x() - d_data->initialPos.x();
|
||||
int dy = d_data->pos.y() - d_data->initialPos.y();
|
||||
|
||||
QRect r( 0, 0, d_data->pixmap.width(), d_data->pixmap.height() );
|
||||
r.moveCenter( QPoint( r.center().x() + dx, r.center().y() + dy ) );
|
||||
|
||||
QPixmap pm( size() );
|
||||
QwtPainter::fillPixmap( parentWidget(), pm );
|
||||
|
||||
QPainter painter( &pm );
|
||||
|
||||
if ( !d_data->contentsMask.isNull() )
|
||||
{
|
||||
QPixmap masked = d_data->pixmap;
|
||||
masked.setMask( d_data->contentsMask );
|
||||
painter.drawPixmap( r, masked );
|
||||
}
|
||||
else
|
||||
{
|
||||
painter.drawPixmap( r, d_data->pixmap );
|
||||
}
|
||||
|
||||
painter.end();
|
||||
|
||||
if ( !d_data->contentsMask.isNull() )
|
||||
pm.setMask( d_data->contentsMask );
|
||||
|
||||
painter.begin( this );
|
||||
painter.setClipRegion( pe->region() );
|
||||
painter.drawPixmap( 0, 0, pm );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Calculate a mask for the contents of the panned widget
|
||||
|
||||
Sometimes only parts of the contents of a widget should be
|
||||
panned. F.e. for a widget with a styled background with rounded borders
|
||||
only the area inside of the border should be panned.
|
||||
|
||||
\return An empty bitmap, indicating no mask
|
||||
*/
|
||||
QBitmap QwtPanner::contentsMask() const
|
||||
{
|
||||
return QBitmap();
|
||||
}
|
||||
|
||||
/*!
|
||||
Grab the widget into a pixmap.
|
||||
\return Grabbed pixmap
|
||||
*/
|
||||
QPixmap QwtPanner::grab() const
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return parentWidget()->grab( parentWidget()->rect() );
|
||||
#else
|
||||
return QPixmap::grabWidget( parentWidget() );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Event filter
|
||||
|
||||
When isEnabled() is true mouse events of the
|
||||
observed widget are filtered.
|
||||
|
||||
\param object Object to be filtered
|
||||
\param event Event
|
||||
|
||||
\return Always false, beside for paint events for the
|
||||
parent widget.
|
||||
|
||||
\sa widgetMousePressEvent(), widgetMouseReleaseEvent(),
|
||||
widgetMouseMoveEvent()
|
||||
*/
|
||||
bool QwtPanner::eventFilter( QObject *object, QEvent *event )
|
||||
{
|
||||
if ( object == NULL || object != parentWidget() )
|
||||
return false;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
widgetMousePressEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
widgetMouseMoveEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
widgetMouseReleaseEvent( static_cast<QMouseEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
widgetKeyPressEvent( static_cast<QKeyEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyRelease:
|
||||
{
|
||||
widgetKeyReleaseEvent( static_cast<QKeyEvent *>( event ) );
|
||||
break;
|
||||
}
|
||||
case QEvent::Paint:
|
||||
{
|
||||
if ( isVisible() )
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse press event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
\sa eventFilter(), widgetMouseReleaseEvent(),
|
||||
widgetMouseMoveEvent(),
|
||||
*/
|
||||
void QwtPanner::widgetMousePressEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
if ( ( mouseEvent->button() != d_data->button )
|
||||
|| ( mouseEvent->modifiers() != d_data->buttonModifiers ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *w = parentWidget();
|
||||
if ( w == NULL )
|
||||
return;
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
showCursor( true );
|
||||
#endif
|
||||
|
||||
d_data->initialPos = d_data->pos = mouseEvent->pos();
|
||||
|
||||
setGeometry( parentWidget()->rect() );
|
||||
|
||||
// We don't want to grab the picker !
|
||||
QVector<QwtPicker *> pickers = qwtActivePickers( parentWidget() );
|
||||
for ( int i = 0; i < pickers.size(); i++ )
|
||||
pickers[i]->setEnabled( false );
|
||||
|
||||
d_data->pixmap = grab();
|
||||
d_data->contentsMask = contentsMask();
|
||||
|
||||
for ( int i = 0; i < pickers.size(); i++ )
|
||||
pickers[i]->setEnabled( true );
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse move event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
\sa eventFilter(), widgetMousePressEvent(), widgetMouseReleaseEvent()
|
||||
*/
|
||||
void QwtPanner::widgetMouseMoveEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
if ( !isVisible() )
|
||||
return;
|
||||
|
||||
QPoint pos = mouseEvent->pos();
|
||||
if ( !isOrientationEnabled( Qt::Horizontal ) )
|
||||
pos.setX( d_data->initialPos.x() );
|
||||
if ( !isOrientationEnabled( Qt::Vertical ) )
|
||||
pos.setY( d_data->initialPos.y() );
|
||||
|
||||
if ( pos != d_data->pos && rect().contains( pos ) )
|
||||
{
|
||||
d_data->pos = pos;
|
||||
update();
|
||||
|
||||
Q_EMIT moved( d_data->pos.x() - d_data->initialPos.x(),
|
||||
d_data->pos.y() - d_data->initialPos.y() );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a mouse release event for the observed widget.
|
||||
|
||||
\param mouseEvent Mouse event
|
||||
\sa eventFilter(), widgetMousePressEvent(),
|
||||
widgetMouseMoveEvent(),
|
||||
*/
|
||||
void QwtPanner::widgetMouseReleaseEvent( QMouseEvent *mouseEvent )
|
||||
{
|
||||
if ( isVisible() )
|
||||
{
|
||||
hide();
|
||||
#ifndef QT_NO_CURSOR
|
||||
showCursor( false );
|
||||
#endif
|
||||
|
||||
QPoint pos = mouseEvent->pos();
|
||||
if ( !isOrientationEnabled( Qt::Horizontal ) )
|
||||
pos.setX( d_data->initialPos.x() );
|
||||
if ( !isOrientationEnabled( Qt::Vertical ) )
|
||||
pos.setY( d_data->initialPos.y() );
|
||||
|
||||
d_data->pixmap = QPixmap();
|
||||
d_data->contentsMask = QBitmap();
|
||||
d_data->pos = pos;
|
||||
|
||||
if ( d_data->pos != d_data->initialPos )
|
||||
{
|
||||
Q_EMIT panned( d_data->pos.x() - d_data->initialPos.x(),
|
||||
d_data->pos.y() - d_data->initialPos.y() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a key press event for the observed widget.
|
||||
|
||||
\param keyEvent Key event
|
||||
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||
*/
|
||||
void QwtPanner::widgetKeyPressEvent( QKeyEvent *keyEvent )
|
||||
{
|
||||
if ( ( keyEvent->key() == d_data->abortKey )
|
||||
&& ( keyEvent->modifiers() == d_data->abortKeyModifiers ) )
|
||||
{
|
||||
hide();
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
showCursor( false );
|
||||
#endif
|
||||
d_data->pixmap = QPixmap();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Handle a key release event for the observed widget.
|
||||
|
||||
\param keyEvent Key event
|
||||
\sa eventFilter(), widgetKeyReleaseEvent()
|
||||
*/
|
||||
void QwtPanner::widgetKeyReleaseEvent( QKeyEvent *keyEvent )
|
||||
{
|
||||
Q_UNUSED( keyEvent );
|
||||
}
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
void QwtPanner::showCursor( bool on )
|
||||
{
|
||||
if ( on == d_data->hasCursor )
|
||||
return;
|
||||
|
||||
QWidget *w = parentWidget();
|
||||
if ( w == NULL || d_data->cursor == NULL )
|
||||
return;
|
||||
|
||||
d_data->hasCursor = on;
|
||||
|
||||
if ( on )
|
||||
{
|
||||
if ( w->testAttribute( Qt::WA_SetCursor ) )
|
||||
{
|
||||
delete d_data->restoreCursor;
|
||||
d_data->restoreCursor = new QCursor( w->cursor() );
|
||||
}
|
||||
w->setCursor( *d_data->cursor );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( d_data->restoreCursor )
|
||||
{
|
||||
w->setCursor( *d_data->restoreCursor );
|
||||
delete d_data->restoreCursor;
|
||||
d_data->restoreCursor = NULL;
|
||||
}
|
||||
else
|
||||
w->unsetCursor();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PANNER_H
|
||||
#define QWT_PANNER_H 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qwidget.h>
|
||||
#include <qpixmap.h>
|
||||
|
||||
class QCursor;
|
||||
|
||||
/*!
|
||||
\brief QwtPanner provides panning of a widget
|
||||
|
||||
QwtPanner grabs the contents of a widget, that can be dragged
|
||||
in all directions. The offset between the start and the end position
|
||||
is emitted by the panned signal.
|
||||
|
||||
QwtPanner grabs the content of the widget into a pixmap and moves
|
||||
the pixmap around, without initiating any repaint events for the widget.
|
||||
Areas, that are not part of content are not painted while panning.
|
||||
This makes panning fast enough for widgets, where
|
||||
repaints are too slow for mouse movements.
|
||||
|
||||
For widgets, where repaints are very fast it might be better to
|
||||
implement panning manually by mapping mouse events into paint events.
|
||||
*/
|
||||
class QWT_EXPORT QwtPanner: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QwtPanner( QWidget* parent );
|
||||
virtual ~QwtPanner();
|
||||
|
||||
void setEnabled( bool );
|
||||
bool isEnabled() const;
|
||||
|
||||
void setMouseButton( Qt::MouseButton,
|
||||
Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
void getMouseButton( Qt::MouseButton &button,
|
||||
Qt::KeyboardModifiers & ) const;
|
||||
|
||||
void setAbortKey( int key, Qt::KeyboardModifiers = Qt::NoModifier );
|
||||
void getAbortKey( int &key, Qt::KeyboardModifiers & ) const;
|
||||
|
||||
void setCursor( const QCursor & );
|
||||
const QCursor cursor() const;
|
||||
|
||||
void setOrientations( Qt::Orientations );
|
||||
Qt::Orientations orientations() const;
|
||||
|
||||
bool isOrientationEnabled( Qt::Orientation ) const;
|
||||
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
Q_SIGNALS:
|
||||
/*!
|
||||
Signal emitted, when panning is done
|
||||
|
||||
\param dx Offset in horizontal direction
|
||||
\param dy Offset in vertical direction
|
||||
*/
|
||||
void panned( int dx, int dy );
|
||||
|
||||
/*!
|
||||
Signal emitted, while the widget moved, but panning
|
||||
is not finished.
|
||||
|
||||
\param dx Offset in horizontal direction
|
||||
\param dy Offset in vertical direction
|
||||
*/
|
||||
void moved( int dx, int dy );
|
||||
|
||||
protected:
|
||||
virtual void widgetMousePressEvent( QMouseEvent * );
|
||||
virtual void widgetMouseReleaseEvent( QMouseEvent * );
|
||||
virtual void widgetMouseMoveEvent( QMouseEvent * );
|
||||
virtual void widgetKeyPressEvent( QKeyEvent * );
|
||||
virtual void widgetKeyReleaseEvent( QKeyEvent * );
|
||||
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
|
||||
virtual QBitmap contentsMask() const;
|
||||
virtual QPixmap grab() const;
|
||||
|
||||
private:
|
||||
#ifndef QT_NO_CURSOR
|
||||
void showCursor( bool );
|
||||
#endif
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,329 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PICKER
|
||||
#define QWT_PICKER 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_text.h"
|
||||
#include "qwt_event_pattern.h"
|
||||
#include <qobject.h>
|
||||
#include <qpen.h>
|
||||
#include <qfont.h>
|
||||
#include <qrect.h>
|
||||
#include <qpainterpath.h>
|
||||
|
||||
class QWidget;
|
||||
class QMouseEvent;
|
||||
class QWheelEvent;
|
||||
class QKeyEvent;
|
||||
class QwtPickerMachine;
|
||||
class QwtWidgetOverlay;
|
||||
|
||||
/*!
|
||||
\brief QwtPicker provides selections on a widget
|
||||
|
||||
QwtPicker filters all enter, leave, mouse and keyboard events of a widget
|
||||
and translates them into an array of selected points.
|
||||
|
||||
The way how the points are collected depends on type of state machine
|
||||
that is connected to the picker. Qwt offers a couple of predefined
|
||||
state machines for selecting:
|
||||
|
||||
- Nothing\n
|
||||
QwtPickerTrackerMachine
|
||||
- Single points\n
|
||||
QwtPickerClickPointMachine, QwtPickerDragPointMachine
|
||||
- Rectangles\n
|
||||
QwtPickerClickRectMachine, QwtPickerDragRectMachine
|
||||
- Polygons\n
|
||||
QwtPickerPolygonMachine
|
||||
|
||||
While these state machines cover the most common ways to collect points
|
||||
it is also possible to implement individual machines as well.
|
||||
|
||||
QwtPicker translates the picked points into a selection using the
|
||||
adjustedPoints() method. adjustedPoints() is intended to be reimplemented
|
||||
to fix up the selection according to application specific requirements.
|
||||
(F.e. when an application accepts rectangles of a fixed aspect ratio only.)
|
||||
|
||||
Optionally QwtPicker support the process of collecting points by a
|
||||
rubber band and tracker displaying a text for the current mouse
|
||||
position.
|
||||
|
||||
\par Example
|
||||
\verbatim #include <qwt_picker.h>
|
||||
#include <qwt_picker_machine.h>
|
||||
|
||||
QwtPicker *picker = new QwtPicker(widget);
|
||||
picker->setStateMachine(new QwtPickerDragRectMachine);
|
||||
picker->setTrackerMode(QwtPicker::ActiveOnly);
|
||||
picker->setRubberBand(QwtPicker::RectRubberBand); \endverbatim\n
|
||||
|
||||
The state machine triggers the following commands:
|
||||
|
||||
- begin()\n
|
||||
Activate/Initialize the selection.
|
||||
- append()\n
|
||||
Add a new point
|
||||
- move() \n
|
||||
Change the position of the last point.
|
||||
- remove()\n
|
||||
Remove the last point.
|
||||
- end()\n
|
||||
Terminate the selection and call accept to validate the picked points.
|
||||
|
||||
The picker is active (isActive()), between begin() and end().
|
||||
In active state the rubber band is displayed, and the tracker is visible
|
||||
in case of trackerMode is ActiveOnly or AlwaysOn.
|
||||
|
||||
The cursor can be moved using the arrow keys. All selections can be aborted
|
||||
using the abort key. (QwtEventPattern::KeyPatternCode)
|
||||
|
||||
\warning In case of QWidget::NoFocus the focus policy of the observed
|
||||
widget is set to QWidget::WheelFocus and mouse tracking
|
||||
will be manipulated while the picker is active,
|
||||
or if trackerMode() is AlwayOn.
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPicker: public QObject, public QwtEventPattern
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS( RubberBand DisplayMode ResizeMode )
|
||||
|
||||
Q_PROPERTY( bool isEnabled READ isEnabled WRITE setEnabled )
|
||||
Q_PROPERTY( ResizeMode resizeMode READ resizeMode WRITE setResizeMode )
|
||||
|
||||
Q_PROPERTY( DisplayMode trackerMode READ trackerMode WRITE setTrackerMode )
|
||||
Q_PROPERTY( QPen trackerPen READ trackerPen WRITE setTrackerPen )
|
||||
Q_PROPERTY( QFont trackerFont READ trackerFont WRITE setTrackerFont )
|
||||
|
||||
Q_PROPERTY( RubberBand rubberBand READ rubberBand WRITE setRubberBand )
|
||||
Q_PROPERTY( QPen rubberBandPen READ rubberBandPen WRITE setRubberBandPen )
|
||||
|
||||
public:
|
||||
/*!
|
||||
Rubber band style
|
||||
|
||||
The default value is QwtPicker::NoRubberBand.
|
||||
\sa setRubberBand(), rubberBand()
|
||||
*/
|
||||
|
||||
enum RubberBand
|
||||
{
|
||||
//! No rubberband.
|
||||
NoRubberBand = 0,
|
||||
|
||||
//! A horizontal line ( only for QwtPickerMachine::PointSelection )
|
||||
HLineRubberBand,
|
||||
|
||||
//! A vertical line ( only for QwtPickerMachine::PointSelection )
|
||||
VLineRubberBand,
|
||||
|
||||
//! A crosshair ( only for QwtPickerMachine::PointSelection )
|
||||
CrossRubberBand,
|
||||
|
||||
//! A rectangle ( only for QwtPickerMachine::RectSelection )
|
||||
RectRubberBand,
|
||||
|
||||
//! An ellipse ( only for QwtPickerMachine::RectSelection )
|
||||
EllipseRubberBand,
|
||||
|
||||
//! A polygon ( only for QwtPickerMachine::PolygonSelection )
|
||||
PolygonRubberBand,
|
||||
|
||||
/*!
|
||||
Values >= UserRubberBand can be used to define additional
|
||||
rubber bands.
|
||||
*/
|
||||
UserRubberBand = 100
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Display mode
|
||||
\sa setTrackerMode(), trackerMode(), isActive()
|
||||
*/
|
||||
enum DisplayMode
|
||||
{
|
||||
//! Display never
|
||||
AlwaysOff,
|
||||
|
||||
//! Display always
|
||||
AlwaysOn,
|
||||
|
||||
//! Display only when the selection is active
|
||||
ActiveOnly
|
||||
};
|
||||
|
||||
/*!
|
||||
Controls what to do with the selected points of an active
|
||||
selection when the observed widget is resized.
|
||||
|
||||
The default value is QwtPicker::Stretch.
|
||||
\sa setResizeMode()
|
||||
*/
|
||||
|
||||
enum ResizeMode
|
||||
{
|
||||
//! All points are scaled according to the new size,
|
||||
Stretch,
|
||||
|
||||
//! All points remain unchanged.
|
||||
KeepSize
|
||||
};
|
||||
|
||||
explicit QwtPicker( QWidget *parent );
|
||||
explicit QwtPicker( RubberBand rubberBand,
|
||||
DisplayMode trackerMode, QWidget * );
|
||||
|
||||
virtual ~QwtPicker();
|
||||
|
||||
void setStateMachine( QwtPickerMachine * );
|
||||
const QwtPickerMachine *stateMachine() const;
|
||||
QwtPickerMachine *stateMachine();
|
||||
|
||||
void setRubberBand( RubberBand );
|
||||
RubberBand rubberBand() const;
|
||||
|
||||
void setTrackerMode( DisplayMode );
|
||||
DisplayMode trackerMode() const;
|
||||
|
||||
void setResizeMode( ResizeMode );
|
||||
ResizeMode resizeMode() const;
|
||||
|
||||
void setRubberBandPen( const QPen & );
|
||||
QPen rubberBandPen() const;
|
||||
|
||||
void setTrackerPen( const QPen & );
|
||||
QPen trackerPen() const;
|
||||
|
||||
void setTrackerFont( const QFont & );
|
||||
QFont trackerFont() const;
|
||||
|
||||
bool isEnabled() const;
|
||||
bool isActive() const;
|
||||
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
QWidget *parentWidget();
|
||||
const QWidget *parentWidget() const;
|
||||
|
||||
virtual QPainterPath pickArea() const;
|
||||
|
||||
virtual void drawRubberBand( QPainter * ) const;
|
||||
virtual void drawTracker( QPainter * ) const;
|
||||
|
||||
virtual QRegion rubberBandMask() const;
|
||||
|
||||
virtual QwtText trackerText( const QPoint &pos ) const;
|
||||
QPoint trackerPosition() const;
|
||||
virtual QRect trackerRect( const QFont & ) const;
|
||||
|
||||
QPolygon selection() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setEnabled( bool );
|
||||
|
||||
Q_SIGNALS:
|
||||
/*!
|
||||
A signal indicating, when the picker has been activated.
|
||||
Together with setEnabled() it can be used to implement
|
||||
selections with more than one picker.
|
||||
|
||||
\param on True, when the picker has been activated
|
||||
*/
|
||||
void activated( bool on );
|
||||
|
||||
/*!
|
||||
A signal emitting the selected points,
|
||||
at the end of a selection.
|
||||
|
||||
\param polygon Selected points
|
||||
*/
|
||||
void selected( const QPolygon &polygon );
|
||||
|
||||
/*!
|
||||
A signal emitted when a point has been appended to the selection
|
||||
|
||||
\param pos Position of the appended point.
|
||||
\sa append(). moved()
|
||||
*/
|
||||
void appended( const QPoint &pos );
|
||||
|
||||
/*!
|
||||
A signal emitted whenever the last appended point of the
|
||||
selection has been moved.
|
||||
|
||||
\param pos Position of the moved last point of the selection.
|
||||
\sa move(), appended()
|
||||
*/
|
||||
void moved( const QPoint &pos );
|
||||
|
||||
/*!
|
||||
A signal emitted whenever the last appended point of the
|
||||
selection has been removed.
|
||||
|
||||
\param pos Position of the point, that has been removed
|
||||
\sa remove(), appended()
|
||||
*/
|
||||
void removed( const QPoint &pos );
|
||||
/*!
|
||||
A signal emitted when the active selection has been changed.
|
||||
This might happen when the observed widget is resized.
|
||||
|
||||
\param selection Changed selection
|
||||
\sa stretchSelection()
|
||||
*/
|
||||
void changed( const QPolygon &selection );
|
||||
|
||||
protected:
|
||||
virtual QPolygon adjustedPoints( const QPolygon & ) const;
|
||||
|
||||
virtual void transition( const QEvent * );
|
||||
|
||||
virtual void begin();
|
||||
virtual void append( const QPoint & );
|
||||
virtual void move( const QPoint & );
|
||||
virtual void remove();
|
||||
virtual bool end( bool ok = true );
|
||||
|
||||
virtual bool accept( QPolygon & ) const;
|
||||
virtual void reset();
|
||||
|
||||
virtual void widgetMousePressEvent( QMouseEvent * );
|
||||
virtual void widgetMouseReleaseEvent( QMouseEvent * );
|
||||
virtual void widgetMouseDoubleClickEvent( QMouseEvent * );
|
||||
virtual void widgetMouseMoveEvent( QMouseEvent * );
|
||||
virtual void widgetWheelEvent( QWheelEvent * );
|
||||
virtual void widgetKeyPressEvent( QKeyEvent * );
|
||||
virtual void widgetKeyReleaseEvent( QKeyEvent * );
|
||||
virtual void widgetEnterEvent( QEvent * );
|
||||
virtual void widgetLeaveEvent( QEvent * );
|
||||
|
||||
virtual void stretchSelection( const QSize &oldSize,
|
||||
const QSize &newSize );
|
||||
|
||||
virtual void updateDisplay();
|
||||
|
||||
const QwtWidgetOverlay *rubberBandOverlay() const;
|
||||
const QwtWidgetOverlay *trackerOverlay() const;
|
||||
|
||||
const QPolygon &pickedPoints() const;
|
||||
|
||||
private:
|
||||
void init( QWidget *, RubberBand rubberBand, DisplayMode trackerMode );
|
||||
|
||||
void setMouseTracking( bool );
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,541 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_picker_machine.h"
|
||||
#include "qwt_event_pattern.h"
|
||||
#include <qevent.h>
|
||||
|
||||
//! Constructor
|
||||
QwtPickerMachine::QwtPickerMachine( SelectionType type ):
|
||||
d_selectionType( type ),
|
||||
d_state( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPickerMachine::~QwtPickerMachine()
|
||||
{
|
||||
}
|
||||
|
||||
//! Return the selection type
|
||||
QwtPickerMachine::SelectionType QwtPickerMachine::selectionType() const
|
||||
{
|
||||
return d_selectionType;
|
||||
}
|
||||
|
||||
//! Return the current state
|
||||
int QwtPickerMachine::state() const
|
||||
{
|
||||
return d_state;
|
||||
}
|
||||
|
||||
//! Change the current state
|
||||
void QwtPickerMachine::setState( int state )
|
||||
{
|
||||
d_state = state;
|
||||
}
|
||||
|
||||
//! Set the current state to 0.
|
||||
void QwtPickerMachine::reset()
|
||||
{
|
||||
setState( 0 );
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerTrackerMachine::QwtPickerTrackerMachine():
|
||||
QwtPickerMachine( NoSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerTrackerMachine::transition(
|
||||
const QwtEventPattern &, const QEvent *e )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( e->type() )
|
||||
{
|
||||
case QEvent::Enter:
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += Move;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave:
|
||||
{
|
||||
cmdList += Remove;
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerClickPointMachine::QwtPickerClickPointMachine():
|
||||
QwtPickerMachine( PointSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerClickPointMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += End;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
|
||||
{
|
||||
if ( !keyEvent->isAutoRepeat() )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += End;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerDragPointMachine::QwtPickerDragPointMachine():
|
||||
QwtPickerMachine( PointSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerDragPointMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
cmdList += Move;
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
|
||||
{
|
||||
if ( !keyEvent->isAutoRepeat() )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerClickRectMachine::QwtPickerClickRectMachine():
|
||||
QwtPickerMachine( RectSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerClickRectMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
switch ( state() )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
// Uh, strange we missed the MouseButtonRelease
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
cmdList += Move;
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 1 )
|
||||
{
|
||||
cmdList += Append;
|
||||
setState( 2 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
|
||||
{
|
||||
if ( !keyEvent->isAutoRepeat() )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( state() == 1 )
|
||||
{
|
||||
cmdList += Append;
|
||||
setState( 2 );
|
||||
}
|
||||
else if ( state() == 2 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerDragRectMachine::QwtPickerDragRectMachine():
|
||||
QwtPickerMachine( RectSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerDragRectMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 2 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
cmdList += Move;
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
if ( state() == 2 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1,
|
||||
static_cast<const QKeyEvent *> ( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerPolygonMachine::QwtPickerPolygonMachine():
|
||||
QwtPickerMachine( PolygonSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerPolygonMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += Append;
|
||||
}
|
||||
}
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect2,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 1 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
cmdList += Move;
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *> ( event );
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1, keyEvent ) )
|
||||
{
|
||||
if ( !keyEvent->isAutoRepeat() )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += Append;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( eventPattern.keyMatch( QwtEventPattern::KeySelect2, keyEvent ) )
|
||||
{
|
||||
if ( !keyEvent->isAutoRepeat() )
|
||||
{
|
||||
if ( state() == 1 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
|
||||
//! Constructor
|
||||
QwtPickerDragLineMachine::QwtPickerDragLineMachine():
|
||||
QwtPickerMachine( PolygonSelection )
|
||||
{
|
||||
}
|
||||
|
||||
//! Transition
|
||||
QList<QwtPickerMachine::Command> QwtPickerDragLineMachine::transition(
|
||||
const QwtEventPattern &eventPattern, const QEvent *event )
|
||||
{
|
||||
QList<QwtPickerMachine::Command> cmdList;
|
||||
|
||||
switch( event->type() )
|
||||
{
|
||||
case QEvent::MouseButtonPress:
|
||||
{
|
||||
if ( eventPattern.mouseMatch( QwtEventPattern::MouseSelect1,
|
||||
static_cast<const QMouseEvent *>( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
{
|
||||
if ( eventPattern.keyMatch( QwtEventPattern::KeySelect1,
|
||||
static_cast<const QKeyEvent *> ( event ) ) )
|
||||
{
|
||||
if ( state() == 0 )
|
||||
{
|
||||
cmdList += Begin;
|
||||
cmdList += Append;
|
||||
cmdList += Append;
|
||||
setState( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
cmdList += Move;
|
||||
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease:
|
||||
{
|
||||
if ( state() != 0 )
|
||||
{
|
||||
cmdList += End;
|
||||
setState( 0 );
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cmdList;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PICKER_MACHINE
|
||||
#define QWT_PICKER_MACHINE 1
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qlist.h>
|
||||
|
||||
class QEvent;
|
||||
class QwtEventPattern;
|
||||
|
||||
/*!
|
||||
\brief A state machine for QwtPicker selections
|
||||
|
||||
QwtPickerMachine accepts key and mouse events and translates them
|
||||
into selection commands.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Type of a selection.
|
||||
\sa selectionType()
|
||||
*/
|
||||
enum SelectionType
|
||||
{
|
||||
//! The state machine not usable for any type of selection.
|
||||
NoSelection = -1,
|
||||
|
||||
//! The state machine is for selecting a single point.
|
||||
PointSelection,
|
||||
|
||||
//! The state machine is for selecting a rectangle (2 points).
|
||||
RectSelection,
|
||||
|
||||
//! The state machine is for selecting a polygon (many points).
|
||||
PolygonSelection
|
||||
};
|
||||
|
||||
//! Commands - the output of a state machine
|
||||
enum Command
|
||||
{
|
||||
Begin,
|
||||
Append,
|
||||
Move,
|
||||
Remove,
|
||||
End
|
||||
};
|
||||
|
||||
QwtPickerMachine( SelectionType );
|
||||
virtual ~QwtPickerMachine();
|
||||
|
||||
//! Transition
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * ) = 0;
|
||||
void reset();
|
||||
|
||||
int state() const;
|
||||
void setState( int );
|
||||
|
||||
SelectionType selectionType() const;
|
||||
|
||||
private:
|
||||
const SelectionType d_selectionType;
|
||||
int d_state;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for indicating mouse movements
|
||||
|
||||
QwtPickerTrackerMachine supports displaying information
|
||||
corresponding to mouse movements, but is not intended for
|
||||
selecting anything. Begin/End are related to Enter/Leave events.
|
||||
*/
|
||||
class QWT_EXPORT QwtPickerTrackerMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerTrackerMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for point selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 or
|
||||
QwtEventPattern::KeySelect1 selects a point.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
class QWT_EXPORT QwtPickerClickPointMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerClickPointMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for point selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
|
||||
starts the selection, releasing QwtEventPattern::MouseSelect1 or
|
||||
a second press of QwtEventPattern::KeySelect1 terminates it.
|
||||
*/
|
||||
class QWT_EXPORT QwtPickerDragPointMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerDragPointMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for rectangle selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 starts
|
||||
the selection, releasing it selects the first point. Pressing it
|
||||
again selects the second point and terminates the selection.
|
||||
Pressing QwtEventPattern::KeySelect1 also starts the
|
||||
selection, a second press selects the first point. A third one selects
|
||||
the second point and terminates the selection.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPickerClickRectMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerClickRectMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for rectangle selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 selects
|
||||
the first point, releasing it the second point.
|
||||
Pressing QwtEventPattern::KeySelect1 also selects the
|
||||
first point, a second press selects the second point and terminates
|
||||
the selection.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPickerDragRectMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerDragRectMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for line selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 selects
|
||||
the first point, releasing it the second point.
|
||||
Pressing QwtEventPattern::KeySelect1 also selects the
|
||||
first point, a second press selects the second point and terminates
|
||||
the selection.
|
||||
|
||||
A common use case of QwtPickerDragLineMachine are pickers for
|
||||
distance measurements.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPickerDragLineMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerDragLineMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief A state machine for polygon selections
|
||||
|
||||
Pressing QwtEventPattern::MouseSelect1 or QwtEventPattern::KeySelect1
|
||||
starts the selection and selects the first point, or appends a point.
|
||||
Pressing QwtEventPattern::MouseSelect2 or QwtEventPattern::KeySelect2
|
||||
appends the last point and terminates the selection.
|
||||
|
||||
\sa QwtEventPattern::MousePatternCode, QwtEventPattern::KeyPatternCode
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPickerPolygonMachine: public QwtPickerMachine
|
||||
{
|
||||
public:
|
||||
QwtPickerPolygonMachine();
|
||||
|
||||
virtual QList<Command> transition(
|
||||
const QwtEventPattern &, const QEvent * );
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_pixel_matrix.h"
|
||||
|
||||
/*!
|
||||
\brief Constructor
|
||||
|
||||
\param rect Bounding rectangle for the matrix
|
||||
*/
|
||||
QwtPixelMatrix::QwtPixelMatrix( const QRect& rect ):
|
||||
QBitArray( qMax( rect.width() * rect.height(), 0 ) ),
|
||||
d_rect( rect )
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPixelMatrix::~QwtPixelMatrix()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the bounding rectangle of the matrix
|
||||
|
||||
\param rect Bounding rectangle
|
||||
|
||||
\note All bits are cleared
|
||||
*/
|
||||
void QwtPixelMatrix::setRect( const QRect& rect )
|
||||
{
|
||||
if ( rect != d_rect )
|
||||
{
|
||||
d_rect = rect;
|
||||
const int sz = qMax( rect.width() * rect.height(), 0 );
|
||||
resize( sz );
|
||||
}
|
||||
|
||||
fill( false );
|
||||
}
|
||||
|
||||
//! \return Bounding rectangle
|
||||
QRect QwtPixelMatrix::rect() const
|
||||
{
|
||||
return d_rect;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PIXEL_MATRIX_H
|
||||
#define QWT_PIXEL_MATRIX_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qbitarray.h>
|
||||
#include <qrect.h>
|
||||
|
||||
/*!
|
||||
\brief A bit field corresponding to the pixels of a rectangle
|
||||
|
||||
QwtPixelMatrix is intended to filter out duplicates in an
|
||||
unsorted array of points.
|
||||
*/
|
||||
class QWT_EXPORT QwtPixelMatrix: public QBitArray
|
||||
{
|
||||
public:
|
||||
QwtPixelMatrix( const QRect& rect );
|
||||
~QwtPixelMatrix();
|
||||
|
||||
void setRect( const QRect& rect );
|
||||
QRect rect() const;
|
||||
|
||||
bool testPixel( int x, int y ) const;
|
||||
bool testAndSetPixel( int x, int y, bool on );
|
||||
|
||||
int index( int x, int y ) const;
|
||||
|
||||
private:
|
||||
QRect d_rect;
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Test if a pixel has been set
|
||||
|
||||
\param x X-coordinate
|
||||
\param y Y-coordinate
|
||||
|
||||
\return true, when pos is outside of rect(), or when the pixel
|
||||
has already been set.
|
||||
*/
|
||||
inline bool QwtPixelMatrix::testPixel( int x, int y ) const
|
||||
{
|
||||
const int idx = index( x, y );
|
||||
return ( idx >= 0 ) ? testBit( idx ) : true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set a pixel and test if a pixel has been set before
|
||||
|
||||
\param x X-coordinate
|
||||
\param y Y-coordinate
|
||||
\param on Set/Clear the pixel
|
||||
|
||||
\return true, when pos is outside of rect(), or when the pixel
|
||||
was set before.
|
||||
*/
|
||||
inline bool QwtPixelMatrix::testAndSetPixel( int x, int y, bool on )
|
||||
{
|
||||
const int idx = index( x, y );
|
||||
if ( idx < 0 )
|
||||
return true;
|
||||
|
||||
const bool onBefore = testBit( idx );
|
||||
setBit( idx, on );
|
||||
|
||||
return onBefore;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Calculate the index in the bit field corresponding to a position
|
||||
|
||||
\param x X-coordinate
|
||||
\param y Y-coordinate
|
||||
\return Index, when rect() contains pos - otherwise -1.
|
||||
*/
|
||||
inline int QwtPixelMatrix::index( int x, int y ) const
|
||||
{
|
||||
const int dx = x - d_rect.x();
|
||||
if ( dx < 0 || dx >= d_rect.width() )
|
||||
return -1;
|
||||
|
||||
const int dy = y - d_rect.y();
|
||||
if ( dy < 0 || dy >= d_rect.height() )
|
||||
return -1;
|
||||
|
||||
return dy * d_rect.width() + dx;
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,312 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_H
|
||||
#define QWT_PLOT_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_text.h"
|
||||
#include "qwt_plot_dict.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_interval.h"
|
||||
#include <qframe.h>
|
||||
#include <qlist.h>
|
||||
#include <qvariant.h>
|
||||
|
||||
class QwtPlotLayout;
|
||||
class QwtAbstractLegend;
|
||||
class QwtScaleWidget;
|
||||
class QwtScaleEngine;
|
||||
class QwtScaleDiv;
|
||||
class QwtScaleDraw;
|
||||
class QwtTextLabel;
|
||||
|
||||
/*!
|
||||
\brief A 2-D plotting widget
|
||||
|
||||
QwtPlot is a widget for plotting two-dimensional graphs.
|
||||
An unlimited number of plot items can be displayed on
|
||||
its canvas. Plot items might be curves (QwtPlotCurve), markers
|
||||
(QwtPlotMarker), the grid (QwtPlotGrid), or anything else derived
|
||||
from QwtPlotItem.
|
||||
A plot can have up to four axes, with each plot item attached to an x- and
|
||||
a y axis. The scales at the axes can be explicitly set (QwtScaleDiv), or
|
||||
are calculated from the plot items, using algorithms (QwtScaleEngine) which
|
||||
can be configured separately for each axis.
|
||||
|
||||
The simpleplot example is a good starting point to see how to set up a
|
||||
plot widget.
|
||||
|
||||
\image html plot.png
|
||||
|
||||
\par Example
|
||||
The following example shows (schematically) the most simple
|
||||
way to use QwtPlot. By default, only the left and bottom axes are
|
||||
visible and their scales are computed automatically.
|
||||
\verbatim
|
||||
#include <qwt_plot.h>
|
||||
#include <qwt_plot_curve.h>
|
||||
|
||||
QwtPlot *myPlot = new QwtPlot("Two Curves", parent);
|
||||
|
||||
// add curves
|
||||
QwtPlotCurve *curve1 = new QwtPlotCurve("Curve 1");
|
||||
QwtPlotCurve *curve2 = new QwtPlotCurve("Curve 2");
|
||||
|
||||
// connect or copy the data to the curves
|
||||
curve1->setData(...);
|
||||
curve2->setData(...);
|
||||
|
||||
curve1->attach(myPlot);
|
||||
curve2->attach(myPlot);
|
||||
|
||||
// finally, refresh the plot
|
||||
myPlot->replot();
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPlot: public QFrame, public QwtPlotDict
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QBrush canvasBackground
|
||||
READ canvasBackground WRITE setCanvasBackground )
|
||||
Q_PROPERTY( bool autoReplot READ autoReplot WRITE setAutoReplot )
|
||||
|
||||
#if 0
|
||||
// This property is intended to configure the plot
|
||||
// widget from a special dialog in the deigner plugin.
|
||||
// Disabled until such a dialog has been implemented.
|
||||
|
||||
Q_PROPERTY( QString propertiesDocument
|
||||
READ grabProperties WRITE applyProperties )
|
||||
#endif
|
||||
|
||||
public:
|
||||
//! \brief Axis index
|
||||
enum Axis
|
||||
{
|
||||
//! Y axis left of the canvas
|
||||
yLeft,
|
||||
|
||||
//! Y axis right of the canvas
|
||||
yRight,
|
||||
|
||||
//! X axis below the canvas
|
||||
xBottom,
|
||||
|
||||
//! X axis above the canvas
|
||||
xTop,
|
||||
|
||||
//! Number of axes
|
||||
axisCnt
|
||||
};
|
||||
|
||||
/*!
|
||||
Position of the legend, relative to the canvas.
|
||||
|
||||
\sa insertLegend()
|
||||
*/
|
||||
enum LegendPosition
|
||||
{
|
||||
//! The legend will be left from the QwtPlot::yLeft axis.
|
||||
LeftLegend,
|
||||
|
||||
//! The legend will be right from the QwtPlot::yRight axis.
|
||||
RightLegend,
|
||||
|
||||
//! The legend will be below the footer
|
||||
BottomLegend,
|
||||
|
||||
//! The legend will be above the title
|
||||
TopLegend
|
||||
};
|
||||
|
||||
explicit QwtPlot( QWidget * = NULL );
|
||||
explicit QwtPlot( const QwtText &title, QWidget * = NULL );
|
||||
|
||||
virtual ~QwtPlot();
|
||||
|
||||
void applyProperties( const QString & );
|
||||
QString grabProperties() const;
|
||||
|
||||
void setAutoReplot( bool = true );
|
||||
bool autoReplot() const;
|
||||
|
||||
// Layout
|
||||
|
||||
void setPlotLayout( QwtPlotLayout * );
|
||||
|
||||
QwtPlotLayout *plotLayout();
|
||||
const QwtPlotLayout *plotLayout() const;
|
||||
|
||||
// Title
|
||||
|
||||
void setTitle( const QString & );
|
||||
void setTitle( const QwtText &t );
|
||||
QwtText title() const;
|
||||
|
||||
QwtTextLabel *titleLabel();
|
||||
const QwtTextLabel *titleLabel() const;
|
||||
|
||||
// Footer
|
||||
|
||||
void setFooter( const QString & );
|
||||
void setFooter( const QwtText &t );
|
||||
QwtText footer() const;
|
||||
|
||||
QwtTextLabel *footerLabel();
|
||||
const QwtTextLabel *footerLabel() const;
|
||||
|
||||
// Canvas
|
||||
|
||||
void setCanvas( QWidget * );
|
||||
|
||||
QWidget *canvas();
|
||||
const QWidget *canvas() const;
|
||||
|
||||
void setCanvasBackground( const QBrush & );
|
||||
QBrush canvasBackground() const;
|
||||
|
||||
virtual QwtScaleMap canvasMap( int axisId ) const;
|
||||
|
||||
double invTransform( int axisId, int pos ) const;
|
||||
double transform( int axisId, double value ) const;
|
||||
|
||||
// Axes
|
||||
|
||||
QwtScaleEngine *axisScaleEngine( int axisId );
|
||||
const QwtScaleEngine *axisScaleEngine( int axisId ) const;
|
||||
void setAxisScaleEngine( int axisId, QwtScaleEngine * );
|
||||
|
||||
void setAxisAutoScale( int axisId, bool on = true );
|
||||
bool axisAutoScale( int axisId ) const;
|
||||
|
||||
void enableAxis( int axisId, bool tf = true );
|
||||
bool axisEnabled( int axisId ) const;
|
||||
|
||||
void setAxisFont( int axisId, const QFont &f );
|
||||
QFont axisFont( int axisId ) const;
|
||||
|
||||
void setAxisScale( int axisId, double min, double max, double step = 0 );
|
||||
void setAxisScaleDiv( int axisId, const QwtScaleDiv & );
|
||||
void setAxisScaleDraw( int axisId, QwtScaleDraw * );
|
||||
|
||||
double axisStepSize( int axisId ) const;
|
||||
QwtInterval axisInterval( int axisId ) const;
|
||||
|
||||
const QwtScaleDiv &axisScaleDiv( int axisId ) const;
|
||||
|
||||
const QwtScaleDraw *axisScaleDraw( int axisId ) const;
|
||||
QwtScaleDraw *axisScaleDraw( int axisId );
|
||||
|
||||
const QwtScaleWidget *axisWidget( int axisId ) const;
|
||||
QwtScaleWidget *axisWidget( int axisId );
|
||||
|
||||
void setAxisLabelAlignment( int axisId, Qt::Alignment );
|
||||
void setAxisLabelRotation( int axisId, double rotation );
|
||||
|
||||
void setAxisTitle( int axisId, const QString & );
|
||||
void setAxisTitle( int axisId, const QwtText & );
|
||||
QwtText axisTitle( int axisId ) const;
|
||||
|
||||
void setAxisMaxMinor( int axisId, int maxMinor );
|
||||
int axisMaxMinor( int axisId ) const;
|
||||
|
||||
void setAxisMaxMajor( int axisId, int maxMajor );
|
||||
int axisMaxMajor( int axisId ) const;
|
||||
|
||||
// Legend
|
||||
|
||||
void insertLegend( QwtAbstractLegend *,
|
||||
LegendPosition = QwtPlot::RightLegend, double ratio = -1.0 );
|
||||
|
||||
QwtAbstractLegend *legend();
|
||||
const QwtAbstractLegend *legend() const;
|
||||
|
||||
void updateLegend();
|
||||
void updateLegend( const QwtPlotItem * );
|
||||
|
||||
// Misc
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual QSize minimumSizeHint() const;
|
||||
|
||||
virtual void updateLayout();
|
||||
virtual void drawCanvas( QPainter * );
|
||||
|
||||
void updateAxes();
|
||||
void updateCanvasMargins();
|
||||
|
||||
virtual void getCanvasMarginsHint(
|
||||
const QwtScaleMap maps[], const QRectF &canvasRect,
|
||||
double &left, double &top, double &right, double &bottom) const;
|
||||
|
||||
virtual bool event( QEvent * );
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
virtual void drawItems( QPainter *, const QRectF &,
|
||||
const QwtScaleMap maps[axisCnt] ) const;
|
||||
|
||||
virtual QVariant itemToInfo( QwtPlotItem * ) const;
|
||||
virtual QwtPlotItem *infoToItem( const QVariant & ) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/*!
|
||||
A signal indicating, that an item has been attached/detached
|
||||
|
||||
\param plotItem Plot item
|
||||
\param on Attached/Detached
|
||||
*/
|
||||
void itemAttached( QwtPlotItem *plotItem, bool on );
|
||||
|
||||
/*!
|
||||
A signal with the attributes how to update
|
||||
the legend entries for a plot item.
|
||||
|
||||
\param itemInfo Info about a plot item, build from itemToInfo()
|
||||
\param data Attributes of the entries ( usually <= 1 ) for
|
||||
the plot item.
|
||||
|
||||
\sa itemToInfo(), infoToItem(), QwtAbstractLegend::updateLegend()
|
||||
*/
|
||||
void legendDataChanged( const QVariant &itemInfo,
|
||||
const QList<QwtLegendData> &data );
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void replot();
|
||||
void autoRefresh();
|
||||
|
||||
protected:
|
||||
static bool axisValid( int axisId );
|
||||
|
||||
virtual void resizeEvent( QResizeEvent *e );
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateLegendItems( const QVariant &itemInfo,
|
||||
const QList<QwtLegendData> &data );
|
||||
|
||||
private:
|
||||
friend class QwtPlotItem;
|
||||
void attachItem( QwtPlotItem *, bool );
|
||||
|
||||
void initAxesData();
|
||||
void deleteAxesData();
|
||||
void updateScaleDiv();
|
||||
|
||||
void initPlot( const QwtText &title );
|
||||
|
||||
class AxisData;
|
||||
AxisData *d_axisData[axisCnt];
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,368 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_abstract_barchart.h"
|
||||
#include "qwt_scale_map.h"
|
||||
|
||||
static inline double qwtTransformWidth(
|
||||
const QwtScaleMap &map, double value, double width )
|
||||
{
|
||||
const double w2 = 0.5 * width;
|
||||
|
||||
const double v1 = map.transform( value - w2 );
|
||||
const double v2 = map.transform( value + w2 );
|
||||
|
||||
return qAbs( v2 - v1 );
|
||||
}
|
||||
|
||||
class QwtPlotAbstractBarChart::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
layoutPolicy( QwtPlotAbstractBarChart::AutoAdjustSamples ),
|
||||
layoutHint( 0.5 ),
|
||||
spacing( 10 ),
|
||||
margin( 5 ),
|
||||
baseline( 0.0 )
|
||||
{
|
||||
}
|
||||
|
||||
QwtPlotAbstractBarChart::LayoutPolicy layoutPolicy;
|
||||
double layoutHint;
|
||||
int spacing;
|
||||
int margin;
|
||||
double baseline;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the chart
|
||||
*/
|
||||
QwtPlotAbstractBarChart::QwtPlotAbstractBarChart( const QwtText &title ):
|
||||
QwtPlotSeriesItem( title )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
setItemAttribute( QwtPlotItem::Legend, true );
|
||||
setItemAttribute( QwtPlotItem::AutoScale, true );
|
||||
setItemAttribute( QwtPlotItem::Margins, true );
|
||||
setZ( 19.0 );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotAbstractBarChart::~QwtPlotAbstractBarChart()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
The combination of layoutPolicy() and layoutHint() define how the width
|
||||
of the bars is calculated
|
||||
|
||||
\param policy Layout policy
|
||||
|
||||
\sa layoutPolicy(), layoutHint()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::setLayoutPolicy( LayoutPolicy policy )
|
||||
{
|
||||
if ( policy != d_data->layoutPolicy )
|
||||
{
|
||||
d_data->layoutPolicy = policy;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
The combination of layoutPolicy() and layoutHint() define how the width
|
||||
of the bars is calculated
|
||||
|
||||
\return Layout policy of the chart item
|
||||
\sa setLayoutPolicy(), layoutHint()
|
||||
*/
|
||||
QwtPlotAbstractBarChart::LayoutPolicy QwtPlotAbstractBarChart::layoutPolicy() const
|
||||
{
|
||||
return d_data->layoutPolicy;
|
||||
}
|
||||
|
||||
/*!
|
||||
The combination of layoutPolicy() and layoutHint() define how the width
|
||||
of the bars is calculated
|
||||
|
||||
\param hint Layout hint
|
||||
|
||||
\sa LayoutPolicy, layoutPolicy(), layoutHint()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::setLayoutHint( double hint )
|
||||
{
|
||||
hint = qMax( 0.0, hint );
|
||||
if ( hint != d_data->layoutHint )
|
||||
{
|
||||
d_data->layoutHint = hint;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
The combination of layoutPolicy() and layoutHint() define how the width
|
||||
of the bars is calculated
|
||||
|
||||
\return Layout policy of the chart item
|
||||
\sa LayoutPolicy, setLayoutHint(), layoutPolicy()
|
||||
*/
|
||||
double QwtPlotAbstractBarChart::layoutHint() const
|
||||
{
|
||||
return d_data->layoutHint;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the spacing
|
||||
|
||||
The spacing is the distance between 2 samples ( bars for QwtPlotBarChart or
|
||||
a group of bars for QwtPlotMultiBarChart ) in paint device coordinates.
|
||||
|
||||
\sa spacing()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::setSpacing( int spacing )
|
||||
{
|
||||
spacing = qMax( spacing, 0 );
|
||||
if ( spacing != d_data->spacing )
|
||||
{
|
||||
d_data->spacing = spacing;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Spacing between 2 samples ( bars or groups of bars )
|
||||
\sa setSpacing(), margin()
|
||||
*/
|
||||
int QwtPlotAbstractBarChart::spacing() const
|
||||
{
|
||||
return d_data->spacing;
|
||||
}
|
||||
/*!
|
||||
\brief Set the margin
|
||||
|
||||
The margin is the distance between the outmost bars and the contentsRect()
|
||||
of the canvas. The default setting is 5 pixels.
|
||||
|
||||
\param margin Margin
|
||||
|
||||
\sa spacing(), margin()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::setMargin( int margin )
|
||||
{
|
||||
margin = qMax( margin, 0 );
|
||||
if ( margin != d_data->margin )
|
||||
{
|
||||
d_data->margin = margin;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Margin between the outmost bars and the contentsRect()
|
||||
of the canvas.
|
||||
|
||||
\sa setMargin(), spacing()
|
||||
*/
|
||||
int QwtPlotAbstractBarChart::margin() const
|
||||
{
|
||||
return d_data->margin;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the baseline
|
||||
|
||||
The baseline is the origin for the chart. Each bar is
|
||||
painted from the baseline in the direction of the sample
|
||||
value. In case of a horizontal orientation() the baseline
|
||||
is interpreted as x - otherwise as y - value.
|
||||
|
||||
The default value for the baseline is 0.
|
||||
|
||||
\param value Value for the baseline
|
||||
|
||||
\sa baseline(), QwtPlotSeriesItem::orientation()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::setBaseline( double value )
|
||||
{
|
||||
if ( value != d_data->baseline )
|
||||
{
|
||||
d_data->baseline = value;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Value for the origin of the bar chart
|
||||
\sa setBaseline(), QwtPlotSeriesItem::orientation()
|
||||
*/
|
||||
double QwtPlotAbstractBarChart::baseline() const
|
||||
{
|
||||
return d_data->baseline;
|
||||
}
|
||||
|
||||
/*!
|
||||
Calculate the width for a sample in paint device coordinates
|
||||
|
||||
\param map Scale map for the corresponding scale
|
||||
\param canvasSize Size of the canvas in paint device coordinates
|
||||
\param boundingSize Bounding size of the chart in plot coordinates
|
||||
( used in AutoAdjustSamples mode )
|
||||
\param value Value of the sample
|
||||
|
||||
\return Sample width
|
||||
\sa layoutPolicy(), layoutHint()
|
||||
*/
|
||||
double QwtPlotAbstractBarChart::sampleWidth( const QwtScaleMap &map,
|
||||
double canvasSize, double boundingSize, double value ) const
|
||||
{
|
||||
double width;
|
||||
|
||||
switch( d_data->layoutPolicy )
|
||||
{
|
||||
case ScaleSamplesToAxes:
|
||||
{
|
||||
width = qwtTransformWidth( map, value, d_data->layoutHint );
|
||||
break;
|
||||
}
|
||||
case ScaleSampleToCanvas:
|
||||
{
|
||||
width = canvasSize * d_data->layoutHint;
|
||||
break;
|
||||
}
|
||||
case FixedSampleSize:
|
||||
{
|
||||
width = d_data->layoutHint;
|
||||
break;
|
||||
}
|
||||
case AutoAdjustSamples:
|
||||
default:
|
||||
{
|
||||
const size_t numSamples = dataSize();
|
||||
|
||||
double w = 1.0;
|
||||
if ( numSamples > 1 )
|
||||
{
|
||||
w = qAbs( boundingSize / ( numSamples - 1 ) );
|
||||
}
|
||||
|
||||
width = qwtTransformWidth( map, value, w );
|
||||
width -= d_data->spacing;
|
||||
width = qMax( width, d_data->layoutHint );
|
||||
}
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Calculate a hint for the canvas margin
|
||||
|
||||
Bar charts need to reserve some space for displaying the bars
|
||||
for the first and the last sample. The hint is calculated
|
||||
from the layoutHint() depending on the layoutPolicy().
|
||||
|
||||
The margins are in target device coordinates ( pixels on screen )
|
||||
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param canvasRect Contents rectangle of the canvas in painter coordinates
|
||||
\param left Returns the left margin
|
||||
\param top Returns the top margin
|
||||
\param right Returns the right margin
|
||||
\param bottom Returns the bottom margin
|
||||
|
||||
\return Margin
|
||||
|
||||
\sa layoutPolicy(), layoutHint(), QwtPlotItem::Margins
|
||||
QwtPlot::getCanvasMarginsHint(), QwtPlot::updateCanvasMargins()
|
||||
*/
|
||||
void QwtPlotAbstractBarChart::getCanvasMarginHint( const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap, const QRectF &canvasRect,
|
||||
double &left, double &top, double &right, double &bottom ) const
|
||||
{
|
||||
double hint = -1.0;
|
||||
|
||||
switch( layoutPolicy() )
|
||||
{
|
||||
case ScaleSampleToCanvas:
|
||||
{
|
||||
if ( orientation() == Qt::Vertical )
|
||||
hint = 0.5 * canvasRect.width() * d_data->layoutHint;
|
||||
else
|
||||
hint = 0.5 * canvasRect.height() * d_data->layoutHint;
|
||||
|
||||
break;
|
||||
}
|
||||
case FixedSampleSize:
|
||||
{
|
||||
hint = 0.5 * d_data->layoutHint;
|
||||
break;
|
||||
}
|
||||
case AutoAdjustSamples:
|
||||
case ScaleSamplesToAxes:
|
||||
default:
|
||||
{
|
||||
const size_t numSamples = dataSize();
|
||||
if ( numSamples <= 0 )
|
||||
break;
|
||||
|
||||
// doesn't work for nonlinear scales
|
||||
|
||||
const QRectF br = dataRect();
|
||||
double spacing = 0.0;
|
||||
double sampleWidthS = 1.0;
|
||||
|
||||
if ( layoutPolicy() == ScaleSamplesToAxes )
|
||||
{
|
||||
sampleWidthS = qMax( d_data->layoutHint, 0.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
spacing = d_data->spacing;
|
||||
|
||||
if ( numSamples > 1 )
|
||||
{
|
||||
sampleWidthS = qAbs( br.width() / ( numSamples - 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
double ds, w;
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
ds = qAbs( xMap.sDist() );
|
||||
w = canvasRect.width();
|
||||
}
|
||||
else
|
||||
{
|
||||
ds = qAbs( yMap.sDist() );
|
||||
w = canvasRect.height();
|
||||
}
|
||||
|
||||
const double sampleWidthP = ( w - spacing * ( numSamples - 1 ) )
|
||||
* sampleWidthS / ( ds + sampleWidthS );
|
||||
|
||||
hint = 0.5 * sampleWidthP;
|
||||
hint += qMax( d_data->margin, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
left = right = hint;
|
||||
top = bottom = -1.0; // no hint
|
||||
}
|
||||
else
|
||||
{
|
||||
left = right = -1.0; // no hint
|
||||
top = bottom = hint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_ABSTRACT_BAR_CHART_H
|
||||
#define QWT_PLOT_ABSTRACT_BAR_CHART_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_seriesitem.h"
|
||||
#include "qwt_series_data.h"
|
||||
|
||||
/*!
|
||||
\brief Abstract base class for bar chart items
|
||||
|
||||
In opposite to almost all other plot items bar charts can't be
|
||||
displayed inside of their bounding rectangle and need a special
|
||||
API how to calculate the width of the bars and how they affect
|
||||
the layout of the attached plot.
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotAbstractBarChart: public QwtPlotSeriesItem
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Mode how to calculate the bar width
|
||||
|
||||
setLayoutPolicy(), setLayoutHint(), barWidthHint()
|
||||
*/
|
||||
enum LayoutPolicy
|
||||
{
|
||||
/*!
|
||||
The sample width is calculated by dividing the bounding rectangle
|
||||
by the number of samples. The layoutHint() is used as a minimum width
|
||||
in paint device coordinates.
|
||||
|
||||
\sa boundingRectangle()
|
||||
*/
|
||||
AutoAdjustSamples,
|
||||
|
||||
/*!
|
||||
layoutHint() defines an interval in axis coordinates
|
||||
*/
|
||||
ScaleSamplesToAxes,
|
||||
|
||||
/*!
|
||||
The bar width is calculated by multiplying layoutHint()
|
||||
with the height or width of the canvas.
|
||||
|
||||
\sa boundingRectangle()
|
||||
*/
|
||||
ScaleSampleToCanvas,
|
||||
|
||||
/*!
|
||||
layoutHint() defines a fixed width in paint device coordinates.
|
||||
*/
|
||||
FixedSampleSize
|
||||
};
|
||||
|
||||
explicit QwtPlotAbstractBarChart( const QwtText &title );
|
||||
virtual ~QwtPlotAbstractBarChart();
|
||||
|
||||
void setLayoutPolicy( LayoutPolicy );
|
||||
LayoutPolicy layoutPolicy() const;
|
||||
|
||||
void setLayoutHint( double );
|
||||
double layoutHint() const;
|
||||
|
||||
void setSpacing( int );
|
||||
int spacing() const;
|
||||
|
||||
void setMargin( int );
|
||||
int margin() const;
|
||||
|
||||
void setBaseline( double );
|
||||
double baseline() const;
|
||||
|
||||
virtual void getCanvasMarginHint(
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect,
|
||||
double &left, double &top, double &right, double &bottom) const;
|
||||
|
||||
|
||||
protected:
|
||||
double sampleWidth( const QwtScaleMap &map,
|
||||
double canvasSize, double dataSize,
|
||||
double value ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,719 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot.h"
|
||||
#include "qwt_math.h"
|
||||
#include "qwt_scale_widget.h"
|
||||
#include "qwt_scale_div.h"
|
||||
#include "qwt_scale_engine.h"
|
||||
|
||||
class QwtPlot::AxisData
|
||||
{
|
||||
public:
|
||||
bool isEnabled;
|
||||
bool doAutoScale;
|
||||
|
||||
double minValue;
|
||||
double maxValue;
|
||||
double stepSize;
|
||||
|
||||
int maxMajor;
|
||||
int maxMinor;
|
||||
|
||||
bool isValid;
|
||||
|
||||
QwtScaleDiv scaleDiv;
|
||||
QwtScaleEngine *scaleEngine;
|
||||
QwtScaleWidget *scaleWidget;
|
||||
};
|
||||
|
||||
//! Initialize axes
|
||||
void QwtPlot::initAxesData()
|
||||
{
|
||||
int axisId;
|
||||
|
||||
for ( axisId = 0; axisId < axisCnt; axisId++ )
|
||||
d_axisData[axisId] = new AxisData;
|
||||
|
||||
d_axisData[yLeft]->scaleWidget =
|
||||
new QwtScaleWidget( QwtScaleDraw::LeftScale, this );
|
||||
d_axisData[yRight]->scaleWidget =
|
||||
new QwtScaleWidget( QwtScaleDraw::RightScale, this );
|
||||
d_axisData[xTop]->scaleWidget =
|
||||
new QwtScaleWidget( QwtScaleDraw::TopScale, this );
|
||||
d_axisData[xBottom]->scaleWidget =
|
||||
new QwtScaleWidget( QwtScaleDraw::BottomScale, this );
|
||||
|
||||
d_axisData[yLeft]->scaleWidget->setObjectName( "QwtPlotAxisYLeft" );
|
||||
d_axisData[yRight]->scaleWidget->setObjectName( "QwtPlotAxisYRight" );
|
||||
d_axisData[xTop]->scaleWidget->setObjectName( "QwtPlotAxisXTop" );
|
||||
d_axisData[xBottom]->scaleWidget->setObjectName( "QwtPlotAxisXBottom" );
|
||||
|
||||
#if 1
|
||||
// better find the font sizes from the application font
|
||||
QFont fscl( fontInfo().family(), 10 );
|
||||
QFont fttl( fontInfo().family(), 12, QFont::Bold );
|
||||
#endif
|
||||
|
||||
for ( axisId = 0; axisId < axisCnt; axisId++ )
|
||||
{
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
|
||||
d.scaleEngine = new QwtLinearScaleEngine;
|
||||
|
||||
d.scaleWidget->setTransformation(
|
||||
d.scaleEngine->transformation() );
|
||||
|
||||
d.scaleWidget->setFont( fscl );
|
||||
d.scaleWidget->setMargin( 2 );
|
||||
|
||||
QwtText text = d.scaleWidget->title();
|
||||
text.setFont( fttl );
|
||||
d.scaleWidget->setTitle( text );
|
||||
|
||||
d.doAutoScale = true;
|
||||
|
||||
d.minValue = 0.0;
|
||||
d.maxValue = 1000.0;
|
||||
d.stepSize = 0.0;
|
||||
|
||||
d.maxMinor = 5;
|
||||
d.maxMajor = 8;
|
||||
|
||||
|
||||
d.isValid = false;
|
||||
}
|
||||
|
||||
d_axisData[yLeft]->isEnabled = true;
|
||||
d_axisData[yRight]->isEnabled = false;
|
||||
d_axisData[xBottom]->isEnabled = true;
|
||||
d_axisData[xTop]->isEnabled = false;
|
||||
}
|
||||
|
||||
void QwtPlot::deleteAxesData()
|
||||
{
|
||||
for ( int axisId = 0; axisId < axisCnt; axisId++ )
|
||||
{
|
||||
delete d_axisData[axisId]->scaleEngine;
|
||||
delete d_axisData[axisId];
|
||||
d_axisData[axisId] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Scale widget of the specified axis, or NULL if axisId is invalid.
|
||||
\param axisId Axis index
|
||||
*/
|
||||
const QwtScaleWidget *QwtPlot::axisWidget( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->scaleWidget;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Scale widget of the specified axis, or NULL if axisId is invalid.
|
||||
\param axisId Axis index
|
||||
*/
|
||||
QwtScaleWidget *QwtPlot::axisWidget( int axisId )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->scaleWidget;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the scale engine for an axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param scaleEngine Scale engine
|
||||
|
||||
\sa axisScaleEngine()
|
||||
*/
|
||||
void QwtPlot::setAxisScaleEngine( int axisId, QwtScaleEngine *scaleEngine )
|
||||
{
|
||||
if ( axisValid( axisId ) && scaleEngine != NULL )
|
||||
{
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
|
||||
delete d.scaleEngine;
|
||||
d.scaleEngine = scaleEngine;
|
||||
|
||||
d_axisData[axisId]->scaleWidget->setTransformation(
|
||||
scaleEngine->transformation() );
|
||||
|
||||
d.isValid = false;
|
||||
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\param axisId Axis index
|
||||
\return Scale engine for a specific axis
|
||||
*/
|
||||
QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->scaleEngine;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\param axisId Axis index
|
||||
\return Scale engine for a specific axis
|
||||
*/
|
||||
const QwtScaleEngine *QwtPlot::axisScaleEngine( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->scaleEngine;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
/*!
|
||||
\return \c True, if autoscaling is enabled
|
||||
\param axisId Axis index
|
||||
*/
|
||||
bool QwtPlot::axisAutoScale( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->doAutoScale;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\return \c True, if a specified axis is enabled
|
||||
\param axisId Axis index
|
||||
*/
|
||||
bool QwtPlot::axisEnabled( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->isEnabled;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The font of the scale labels for a specified axis
|
||||
\param axisId Axis index
|
||||
*/
|
||||
QFont QwtPlot::axisFont( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return axisWidget( axisId )->font();
|
||||
else
|
||||
return QFont();
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The maximum number of major ticks for a specified axis
|
||||
\param axisId Axis index
|
||||
\sa setAxisMaxMajor(), QwtScaleEngine::divideScale()
|
||||
*/
|
||||
int QwtPlot::axisMaxMajor( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->maxMajor;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the maximum number of minor ticks for a specified axis
|
||||
\param axisId Axis index
|
||||
\sa setAxisMaxMinor(), QwtScaleEngine::divideScale()
|
||||
*/
|
||||
int QwtPlot::axisMaxMinor( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return d_axisData[axisId]->maxMinor;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the scale division of a specified axis
|
||||
|
||||
axisScaleDiv(axisId).lowerBound(), axisScaleDiv(axisId).upperBound()
|
||||
are the current limits of the axis scale.
|
||||
|
||||
\param axisId Axis index
|
||||
\return Scale division
|
||||
|
||||
\sa QwtScaleDiv, setAxisScaleDiv(), QwtScaleEngine::divideScale()
|
||||
*/
|
||||
const QwtScaleDiv &QwtPlot::axisScaleDiv( int axisId ) const
|
||||
{
|
||||
return d_axisData[axisId]->scaleDiv;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the scale draw of a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\return Specified scaleDraw for axis, or NULL if axis is invalid.
|
||||
*/
|
||||
const QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId ) const
|
||||
{
|
||||
if ( !axisValid( axisId ) )
|
||||
return NULL;
|
||||
|
||||
return axisWidget( axisId )->scaleDraw();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the scale draw of a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\return Specified scaleDraw for axis, or NULL if axis is invalid.
|
||||
*/
|
||||
QwtScaleDraw *QwtPlot::axisScaleDraw( int axisId )
|
||||
{
|
||||
if ( !axisValid( axisId ) )
|
||||
return NULL;
|
||||
|
||||
return axisWidget( axisId )->scaleDraw();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the step size parameter that has been set in setAxisScale.
|
||||
|
||||
This doesn't need to be the step size of the current scale.
|
||||
|
||||
\param axisId Axis index
|
||||
\return step size parameter value
|
||||
|
||||
\sa setAxisScale(), QwtScaleEngine::divideScale()
|
||||
*/
|
||||
double QwtPlot::axisStepSize( int axisId ) const
|
||||
{
|
||||
if ( !axisValid( axisId ) )
|
||||
return 0;
|
||||
|
||||
return d_axisData[axisId]->stepSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the current interval of the specified axis
|
||||
|
||||
This is only a convenience function for axisScaleDiv( axisId )->interval();
|
||||
|
||||
\param axisId Axis index
|
||||
\return Scale interval
|
||||
|
||||
\sa QwtScaleDiv, axisScaleDiv()
|
||||
*/
|
||||
QwtInterval QwtPlot::axisInterval( int axisId ) const
|
||||
{
|
||||
if ( !axisValid( axisId ) )
|
||||
return QwtInterval();
|
||||
|
||||
return d_axisData[axisId]->scaleDiv.interval();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Title of a specified axis
|
||||
\param axisId Axis index
|
||||
*/
|
||||
QwtText QwtPlot::axisTitle( int axisId ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return axisWidget( axisId )->title();
|
||||
else
|
||||
return QwtText();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable or disable a specified axis
|
||||
|
||||
When an axis is disabled, this only means that it is not
|
||||
visible on the screen. Curves, markers and can be attached
|
||||
to disabled axes, and transformation of screen coordinates
|
||||
into values works as normal.
|
||||
|
||||
Only xBottom and yLeft are enabled by default.
|
||||
|
||||
\param axisId Axis index
|
||||
\param tf \c true (enabled) or \c false (disabled)
|
||||
*/
|
||||
void QwtPlot::enableAxis( int axisId, bool tf )
|
||||
{
|
||||
if ( axisValid( axisId ) && tf != d_axisData[axisId]->isEnabled )
|
||||
{
|
||||
d_axisData[axisId]->isEnabled = tf;
|
||||
updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Transform the x or y coordinate of a position in the
|
||||
drawing region into a value.
|
||||
|
||||
\param axisId Axis index
|
||||
\param pos position
|
||||
|
||||
\return Position as axis coordinate
|
||||
|
||||
\warning The position can be an x or a y coordinate,
|
||||
depending on the specified axis.
|
||||
*/
|
||||
double QwtPlot::invTransform( int axisId, int pos ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return( canvasMap( axisId ).invTransform( pos ) );
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Transform a value into a coordinate in the plotting region
|
||||
|
||||
\param axisId Axis index
|
||||
\param value value
|
||||
\return X or Y coordinate in the plotting region corresponding
|
||||
to the value.
|
||||
*/
|
||||
double QwtPlot::transform( int axisId, double value ) const
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
return( canvasMap( axisId ).transform( value ) );
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the font of an axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param font Font
|
||||
\warning This function changes the font of the tick labels,
|
||||
not of the axis title.
|
||||
*/
|
||||
void QwtPlot::setAxisFont( int axisId, const QFont &font )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
axisWidget( axisId )->setFont( font );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable autoscaling for a specified axis
|
||||
|
||||
This member function is used to switch back to autoscaling mode
|
||||
after a fixed scale has been set. Autoscaling is enabled by default.
|
||||
|
||||
\param axisId Axis index
|
||||
\param on On/Off
|
||||
\sa setAxisScale(), setAxisScaleDiv(), updateAxes()
|
||||
|
||||
\note The autoscaling flag has no effect until updateAxes() is executed
|
||||
( called by replot() ).
|
||||
*/
|
||||
void QwtPlot::setAxisAutoScale( int axisId, bool on )
|
||||
{
|
||||
if ( axisValid( axisId ) && ( d_axisData[axisId]->doAutoScale != on ) )
|
||||
{
|
||||
d_axisData[axisId]->doAutoScale = on;
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Disable autoscaling and specify a fixed scale for a selected axis.
|
||||
|
||||
In updateAxes() the scale engine calculates a scale division from the
|
||||
specified parameters, that will be assigned to the scale widget. So
|
||||
updates of the scale widget usually happen delayed with the next replot.
|
||||
|
||||
\param axisId Axis index
|
||||
\param min Minimum of the scale
|
||||
\param max Maximum of the scale
|
||||
\param stepSize Major step size. If <code>step == 0</code>, the step size is
|
||||
calculated automatically using the maxMajor setting.
|
||||
|
||||
\sa setAxisMaxMajor(), setAxisAutoScale(), axisStepSize(), QwtScaleEngine::divideScale()
|
||||
*/
|
||||
void QwtPlot::setAxisScale( int axisId, double min, double max, double stepSize )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
{
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
|
||||
d.doAutoScale = false;
|
||||
d.isValid = false;
|
||||
|
||||
d.minValue = min;
|
||||
d.maxValue = max;
|
||||
d.stepSize = stepSize;
|
||||
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Disable autoscaling and specify a fixed scale for a selected axis.
|
||||
|
||||
The scale division will be stored locally only until the next call
|
||||
of updateAxes(). So updates of the scale widget usually happen delayed with
|
||||
the next replot.
|
||||
|
||||
\param axisId Axis index
|
||||
\param scaleDiv Scale division
|
||||
|
||||
\sa setAxisScale(), setAxisAutoScale()
|
||||
*/
|
||||
void QwtPlot::setAxisScaleDiv( int axisId, const QwtScaleDiv &scaleDiv )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
{
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
|
||||
d.doAutoScale = false;
|
||||
d.scaleDiv = scaleDiv;
|
||||
d.isValid = true;
|
||||
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set a scale draw
|
||||
|
||||
\param axisId Axis index
|
||||
\param scaleDraw Object responsible for drawing scales.
|
||||
|
||||
By passing scaleDraw it is possible to extend QwtScaleDraw
|
||||
functionality and let it take place in QwtPlot. Please note
|
||||
that scaleDraw has to be created with new and will be deleted
|
||||
by the corresponding QwtScale member ( like a child object ).
|
||||
|
||||
\sa QwtScaleDraw, QwtScaleWidget
|
||||
\warning The attributes of scaleDraw will be overwritten by those of the
|
||||
previous QwtScaleDraw.
|
||||
*/
|
||||
|
||||
void QwtPlot::setAxisScaleDraw( int axisId, QwtScaleDraw *scaleDraw )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
{
|
||||
axisWidget( axisId )->setScaleDraw( scaleDraw );
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Change the alignment of the tick labels
|
||||
|
||||
\param axisId Axis index
|
||||
\param alignment Or'd Qt::AlignmentFlags see <qnamespace.h>
|
||||
|
||||
\sa QwtScaleDraw::setLabelAlignment()
|
||||
*/
|
||||
void QwtPlot::setAxisLabelAlignment( int axisId, Qt::Alignment alignment )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
axisWidget( axisId )->setLabelAlignment( alignment );
|
||||
}
|
||||
|
||||
/*!
|
||||
Rotate all tick labels
|
||||
|
||||
\param axisId Axis index
|
||||
\param rotation Angle in degrees. When changing the label rotation,
|
||||
the label alignment might be adjusted too.
|
||||
|
||||
\sa QwtScaleDraw::setLabelRotation(), setAxisLabelAlignment()
|
||||
*/
|
||||
void QwtPlot::setAxisLabelRotation( int axisId, double rotation )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
axisWidget( axisId )->setLabelRotation( rotation );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the maximum number of minor scale intervals for a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param maxMinor Maximum number of minor steps
|
||||
|
||||
\sa axisMaxMinor()
|
||||
*/
|
||||
void QwtPlot::setAxisMaxMinor( int axisId, int maxMinor )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
{
|
||||
maxMinor = qBound( 0, maxMinor, 100 );
|
||||
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
if ( maxMinor != d.maxMinor )
|
||||
{
|
||||
d.maxMinor = maxMinor;
|
||||
d.isValid = false;
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the maximum number of major scale intervals for a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param maxMajor Maximum number of major steps
|
||||
|
||||
\sa axisMaxMajor()
|
||||
*/
|
||||
void QwtPlot::setAxisMaxMajor( int axisId, int maxMajor )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
{
|
||||
maxMajor = qBound( 1, maxMajor, 10000 );
|
||||
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
if ( maxMajor != d.maxMajor )
|
||||
{
|
||||
d.maxMajor = maxMajor;
|
||||
d.isValid = false;
|
||||
autoRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the title of a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param title axis title
|
||||
*/
|
||||
void QwtPlot::setAxisTitle( int axisId, const QString &title )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
axisWidget( axisId )->setTitle( title );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Change the title of a specified axis
|
||||
|
||||
\param axisId Axis index
|
||||
\param title Axis title
|
||||
*/
|
||||
void QwtPlot::setAxisTitle( int axisId, const QwtText &title )
|
||||
{
|
||||
if ( axisValid( axisId ) )
|
||||
axisWidget( axisId )->setTitle( title );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Rebuild the axes scales
|
||||
|
||||
In case of autoscaling the boundaries of a scale are calculated
|
||||
from the bounding rectangles of all plot items, having the
|
||||
QwtPlotItem::AutoScale flag enabled ( QwtScaleEngine::autoScale() ).
|
||||
Then a scale division is calculated ( QwtScaleEngine::didvideScale() )
|
||||
and assigned to scale widget.
|
||||
|
||||
When the scale boundaries have been assigned with setAxisScale() a
|
||||
scale division is calculated ( QwtScaleEngine::didvideScale() )
|
||||
for this interval and assigned to the scale widget.
|
||||
|
||||
When the scale has been set explicitly by setAxisScaleDiv() the
|
||||
locally stored scale division gets assigned to the scale widget.
|
||||
|
||||
The scale widget indicates modifications by emitting a
|
||||
QwtScaleWidget::scaleDivChanged() signal.
|
||||
|
||||
updateAxes() is usually called by replot().
|
||||
|
||||
\sa setAxisAutoScale(), setAxisScale(), setAxisScaleDiv(), replot()
|
||||
QwtPlotItem::boundingRect()
|
||||
*/
|
||||
void QwtPlot::updateAxes()
|
||||
{
|
||||
// Find bounding interval of the item data
|
||||
// for all axes, where autoscaling is enabled
|
||||
|
||||
QwtInterval intv[axisCnt];
|
||||
|
||||
const QwtPlotItemList& itmList = itemList();
|
||||
|
||||
QwtPlotItemIterator it;
|
||||
for ( it = itmList.begin(); it != itmList.end(); ++it )
|
||||
{
|
||||
const QwtPlotItem *item = *it;
|
||||
|
||||
if ( !item->testItemAttribute( QwtPlotItem::AutoScale ) )
|
||||
continue;
|
||||
|
||||
if ( !item->isVisible() )
|
||||
continue;
|
||||
|
||||
if ( axisAutoScale( item->xAxis() ) || axisAutoScale( item->yAxis() ) )
|
||||
{
|
||||
const QRectF rect = item->boundingRect();
|
||||
|
||||
if ( rect.width() >= 0.0 )
|
||||
intv[item->xAxis()] |= QwtInterval( rect.left(), rect.right() );
|
||||
|
||||
if ( rect.height() >= 0.0 )
|
||||
intv[item->yAxis()] |= QwtInterval( rect.top(), rect.bottom() );
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust scales
|
||||
|
||||
for ( int axisId = 0; axisId < axisCnt; axisId++ )
|
||||
{
|
||||
AxisData &d = *d_axisData[axisId];
|
||||
|
||||
double minValue = d.minValue;
|
||||
double maxValue = d.maxValue;
|
||||
double stepSize = d.stepSize;
|
||||
|
||||
if ( d.doAutoScale && intv[axisId].isValid() )
|
||||
{
|
||||
d.isValid = false;
|
||||
|
||||
minValue = intv[axisId].minValue();
|
||||
maxValue = intv[axisId].maxValue();
|
||||
|
||||
d.scaleEngine->autoScale( d.maxMajor,
|
||||
minValue, maxValue, stepSize );
|
||||
}
|
||||
if ( !d.isValid )
|
||||
{
|
||||
d.scaleDiv = d.scaleEngine->divideScale(
|
||||
minValue, maxValue,
|
||||
d.maxMajor, d.maxMinor, stepSize );
|
||||
d.isValid = true;
|
||||
}
|
||||
|
||||
QwtScaleWidget *scaleWidget = axisWidget( axisId );
|
||||
scaleWidget->setScaleDiv( d.scaleDiv );
|
||||
|
||||
int startDist, endDist;
|
||||
scaleWidget->getBorderDistHint( startDist, endDist );
|
||||
scaleWidget->setBorderDist( startDist, endDist );
|
||||
}
|
||||
|
||||
for ( it = itmList.begin(); it != itmList.end(); ++it )
|
||||
{
|
||||
QwtPlotItem *item = *it;
|
||||
if ( item->testItemInterest( QwtPlotItem::ScaleInterest ) )
|
||||
{
|
||||
item->updateScaleDiv( axisScaleDiv( item->xAxis() ),
|
||||
axisScaleDiv( item->yAxis() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_barchart.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_column_symbol.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qpainter.h>
|
||||
|
||||
class QwtPlotBarChart::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
symbol( NULL ),
|
||||
legendMode( QwtPlotBarChart::LegendChartTitle )
|
||||
{
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
delete symbol;
|
||||
}
|
||||
|
||||
QwtColumnSymbol *symbol;
|
||||
QwtPlotBarChart::LegendMode legendMode;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the curve
|
||||
*/
|
||||
QwtPlotBarChart::QwtPlotBarChart( const QwtText &title ):
|
||||
QwtPlotAbstractBarChart( title )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the curve
|
||||
*/
|
||||
QwtPlotBarChart::QwtPlotBarChart( const QString &title ):
|
||||
QwtPlotAbstractBarChart( QwtText( title ) )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotBarChart::~QwtPlotBarChart()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
void QwtPlotBarChart::init()
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
setData( new QwtPointSeriesData() );
|
||||
}
|
||||
|
||||
//! \return QwtPlotItem::Rtti_PlotBarChart
|
||||
int QwtPlotBarChart::rtti() const
|
||||
{
|
||||
return QwtPlotItem::Rtti_PlotBarChart;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize data with an array of points
|
||||
|
||||
\param samples Vector of points
|
||||
\note QVector is implicitly shared
|
||||
\note QPolygonF is derived from QVector<QPointF>
|
||||
*/
|
||||
void QwtPlotBarChart::setSamples(
|
||||
const QVector<QPointF> &samples )
|
||||
{
|
||||
setData( new QwtPointSeriesData( samples ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize data with an array of doubles
|
||||
|
||||
The indices in the array are taken as x coordinate,
|
||||
while the doubles are interpreted as y values.
|
||||
|
||||
\param samples Vector of y coordinates
|
||||
\note QVector is implicitly shared
|
||||
*/
|
||||
void QwtPlotBarChart::setSamples(
|
||||
const QVector<double> &samples )
|
||||
{
|
||||
QVector<QPointF> points;
|
||||
for ( int i = 0; i < samples.size(); i++ )
|
||||
points += QPointF( i, samples[ i ] );
|
||||
|
||||
setData( new QwtPointSeriesData( points ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a series of samples
|
||||
|
||||
setSamples() is just a wrapper for setData() without any additional
|
||||
value - beside that it is easier to find for the developer.
|
||||
|
||||
\param data Data
|
||||
\warning The item takes ownership of the data object, deleting
|
||||
it when its not used anymore.
|
||||
*/
|
||||
void QwtPlotBarChart::setSamples( QwtSeriesData<QPointF> *data )
|
||||
{
|
||||
setData( data );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a symbol
|
||||
|
||||
The bar chart will take the ownership of the symbol, hence the previously
|
||||
set symbol will be delete by setting a new one. If \p symbol is
|
||||
\c NULL no symbol will be drawn.
|
||||
|
||||
\param symbol Symbol
|
||||
\sa symbol()
|
||||
*/
|
||||
void QwtPlotBarChart::setSymbol( QwtColumnSymbol *symbol )
|
||||
{
|
||||
if ( symbol != d_data->symbol )
|
||||
{
|
||||
delete d_data->symbol;
|
||||
d_data->symbol = symbol;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Current symbol or NULL, when no symbol has been assigned
|
||||
\sa setSymbol()
|
||||
*/
|
||||
const QwtColumnSymbol *QwtPlotBarChart::symbol() const
|
||||
{
|
||||
return d_data->symbol;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the mode that decides what to display on the legend
|
||||
|
||||
In case of LegendBarTitles barTitle() needs to be overloaded
|
||||
to return individual titles for each bar.
|
||||
|
||||
\param mode New mode
|
||||
\sa legendMode(), legendData(), barTitle(), QwtPlotItem::ItemAttribute
|
||||
*/
|
||||
void QwtPlotBarChart::setLegendMode( LegendMode mode )
|
||||
{
|
||||
if ( mode != d_data->legendMode )
|
||||
{
|
||||
d_data->legendMode = mode;
|
||||
legendChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Legend mode
|
||||
\sa setLegendMode()
|
||||
*/
|
||||
QwtPlotBarChart::LegendMode QwtPlotBarChart::legendMode() const
|
||||
{
|
||||
return d_data->legendMode;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Bounding rectangle of all samples.
|
||||
For an empty series the rectangle is invalid.
|
||||
*/
|
||||
QRectF QwtPlotBarChart::boundingRect() const
|
||||
{
|
||||
const size_t numSamples = dataSize();
|
||||
if ( numSamples == 0 )
|
||||
return QwtPlotSeriesItem::boundingRect();
|
||||
|
||||
QRectF rect = QwtPlotSeriesItem::boundingRect();
|
||||
if ( rect.height() >= 0 )
|
||||
{
|
||||
const double baseLine = baseline();
|
||||
|
||||
if ( rect.bottom() < baseLine )
|
||||
rect.setBottom( baseLine );
|
||||
|
||||
if ( rect.top() > baseLine )
|
||||
rect.setTop( baseLine );
|
||||
}
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw an interval of the bar chart
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param canvasRect Contents rect of the canvas
|
||||
\param from Index of the first point to be painted
|
||||
\param to Index of the last point to be painted. If to < 0 the
|
||||
curve will be painted to its last point.
|
||||
|
||||
\sa drawSymbols()
|
||||
*/
|
||||
void QwtPlotBarChart::drawSeries( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const
|
||||
{
|
||||
if ( to < 0 )
|
||||
to = dataSize() - 1;
|
||||
|
||||
if ( from < 0 )
|
||||
from = 0;
|
||||
|
||||
if ( from > to )
|
||||
return;
|
||||
|
||||
|
||||
const QRectF br = data()->boundingRect();
|
||||
const QwtInterval interval( br.left(), br.right() );
|
||||
|
||||
painter->save();
|
||||
|
||||
for ( int i = from; i <= to; i++ )
|
||||
{
|
||||
drawSample( painter, xMap, yMap,
|
||||
canvasRect, interval, i, sample( i ) );
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a sample
|
||||
|
||||
\param painter Painter
|
||||
\param xMap x map
|
||||
\param yMap y map
|
||||
\param canvasRect Contents rect of the canvas
|
||||
\param boundingInterval Bounding interval of sample values
|
||||
\param index Index of the sample
|
||||
\param sample Value of the sample
|
||||
|
||||
\sa drawSeries()
|
||||
*/
|
||||
void QwtPlotBarChart::drawSample( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, const QwtInterval &boundingInterval,
|
||||
int index, const QPointF &sample ) const
|
||||
{
|
||||
QwtColumnRect barRect;
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
{
|
||||
const double barHeight = sampleWidth( yMap, canvasRect.height(),
|
||||
boundingInterval.width(), sample.y() );
|
||||
|
||||
const double x1 = xMap.transform( baseline() );
|
||||
const double x2 = xMap.transform( sample.y() );
|
||||
|
||||
const double y = yMap.transform( sample.x() );
|
||||
const double y1 = y - 0.5 * barHeight;
|
||||
const double y2 = y + 0.5 * barHeight;
|
||||
|
||||
barRect.direction = ( x1 < x2 ) ?
|
||||
QwtColumnRect::LeftToRight : QwtColumnRect::RightToLeft;
|
||||
|
||||
barRect.hInterval = QwtInterval( x1, x2 ).normalized();
|
||||
barRect.vInterval = QwtInterval( y1, y2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
const double barWidth = sampleWidth( xMap, canvasRect.width(),
|
||||
boundingInterval.width(), sample.y() );
|
||||
|
||||
const double x = xMap.transform( sample.x() );
|
||||
const double x1 = x - 0.5 * barWidth;
|
||||
const double x2 = x + 0.5 * barWidth;
|
||||
|
||||
const double y1 = yMap.transform( baseline() );
|
||||
const double y2 = yMap.transform( sample.y() );
|
||||
|
||||
barRect.direction = ( y1 < y2 ) ?
|
||||
QwtColumnRect::TopToBottom : QwtColumnRect::BottomToTop;
|
||||
|
||||
barRect.hInterval = QwtInterval( x1, x2 );
|
||||
barRect.vInterval = QwtInterval( y1, y2 ).normalized();
|
||||
}
|
||||
|
||||
drawBar( painter, index, sample, barRect );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a bar
|
||||
|
||||
\param painter Painter
|
||||
\param sampleIndex Index of the sample represented by the bar
|
||||
\param sample Value of the sample
|
||||
\param rect Bounding rectangle of the bar
|
||||
*/
|
||||
void QwtPlotBarChart::drawBar( QPainter *painter,
|
||||
int sampleIndex, const QPointF &sample,
|
||||
const QwtColumnRect &rect ) const
|
||||
{
|
||||
const QwtColumnSymbol *specialSym =
|
||||
specialSymbol( sampleIndex, sample );
|
||||
|
||||
const QwtColumnSymbol *sym = specialSym;
|
||||
if ( sym == NULL )
|
||||
sym = d_data->symbol;
|
||||
|
||||
if ( sym )
|
||||
{
|
||||
sym->draw( painter, rect );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we build a temporary default symbol
|
||||
QwtColumnSymbol sym( QwtColumnSymbol::Box );
|
||||
sym.setLineWidth( 1 );
|
||||
sym.setFrameStyle( QwtColumnSymbol::Plain );
|
||||
sym.draw( painter, rect );
|
||||
}
|
||||
|
||||
delete specialSym;
|
||||
}
|
||||
|
||||
/*!
|
||||
Needs to be overloaded to return a
|
||||
non default symbol for a specific sample
|
||||
|
||||
\param sampleIndex Index of the sample represented by the bar
|
||||
\param sample Value of the sample
|
||||
|
||||
\return NULL, indicating to use the default symbol
|
||||
*/
|
||||
QwtColumnSymbol *QwtPlotBarChart::specialSymbol(
|
||||
int sampleIndex, const QPointF &sample ) const
|
||||
{
|
||||
Q_UNUSED( sampleIndex );
|
||||
Q_UNUSED( sample );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return the title of a bar
|
||||
|
||||
In LegendBarTitles mode the title is displayed on
|
||||
the legend entry corresponding to a bar.
|
||||
|
||||
The default implementation is a dummy, that is intended
|
||||
to be overloaded.
|
||||
|
||||
\param sampleIndex Index of the bar
|
||||
\return An empty text
|
||||
\sa LegendBarTitles
|
||||
*/
|
||||
QwtText QwtPlotBarChart::barTitle( int sampleIndex ) const
|
||||
{
|
||||
Q_UNUSED( sampleIndex );
|
||||
return QwtText();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Return all information, that is needed to represent
|
||||
the item on the legend
|
||||
|
||||
In case of LegendBarTitles an entry for each bar is returned,
|
||||
otherwise the chart is represented like any other plot item
|
||||
from its title() and the legendIcon().
|
||||
|
||||
\return Information, that is needed to represent the item on the legend
|
||||
\sa title(), setLegendMode(), barTitle(), QwtLegend, QwtPlotLegendItem
|
||||
*/
|
||||
QList<QwtLegendData> QwtPlotBarChart::legendData() const
|
||||
{
|
||||
QList<QwtLegendData> list;
|
||||
|
||||
if ( d_data->legendMode == LegendBarTitles )
|
||||
{
|
||||
const size_t numSamples = dataSize();
|
||||
for ( size_t i = 0; i < numSamples; i++ )
|
||||
{
|
||||
QwtLegendData data;
|
||||
|
||||
QVariant titleValue;
|
||||
qVariantSetValue( titleValue, barTitle( i ) );
|
||||
data.setValue( QwtLegendData::TitleRole, titleValue );
|
||||
|
||||
if ( !legendIconSize().isEmpty() )
|
||||
{
|
||||
QVariant iconValue;
|
||||
qVariantSetValue( iconValue,
|
||||
legendIcon( i, legendIconSize() ) );
|
||||
|
||||
data.setValue( QwtLegendData::IconRole, iconValue );
|
||||
}
|
||||
|
||||
list += data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return QwtPlotAbstractBarChart::legendData();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Icon representing a bar or the chart on the legend
|
||||
|
||||
When the legendMode() is LegendBarTitles the icon shows
|
||||
the bar corresponding to index - otherwise the bar
|
||||
displays the default symbol.
|
||||
|
||||
\param index Index of the legend entry
|
||||
\param size Icon size
|
||||
|
||||
\sa setLegendMode(), drawBar(),
|
||||
QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
|
||||
*/
|
||||
QwtGraphic QwtPlotBarChart::legendIcon(
|
||||
int index, const QSizeF &size ) const
|
||||
{
|
||||
QwtColumnRect column;
|
||||
column.hInterval = QwtInterval( 0.0, size.width() - 1.0 );
|
||||
column.vInterval = QwtInterval( 0.0, size.height() - 1.0 );
|
||||
|
||||
QwtGraphic icon;
|
||||
icon.setDefaultSize( size );
|
||||
icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
|
||||
|
||||
QPainter painter( &icon );
|
||||
painter.setRenderHint( QPainter::Antialiasing,
|
||||
testRenderHint( QwtPlotItem::RenderAntialiased ) );
|
||||
|
||||
int barIndex = -1;
|
||||
if ( d_data->legendMode == QwtPlotBarChart::LegendBarTitles )
|
||||
barIndex = index;
|
||||
|
||||
drawBar( &painter, barIndex, QPointF(), column );
|
||||
|
||||
return icon;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_BAR_CHART_H
|
||||
#define QWT_PLOT_BAR_CHART_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_abstract_barchart.h"
|
||||
#include "qwt_series_data.h"
|
||||
|
||||
class QwtColumnRect;
|
||||
class QwtColumnSymbol;
|
||||
|
||||
/*!
|
||||
\brief QwtPlotBarChart displays a series of a values as bars.
|
||||
|
||||
Each bar might be customized individually by implementing
|
||||
a specialSymbol(). Otherwise it is rendered using a default symbol.
|
||||
|
||||
Depending on its orientation() the bars are displayed horizontally
|
||||
or vertically. The bars cover the interval between the baseline()
|
||||
and the value.
|
||||
|
||||
By activating the LegendBarTitles mode each sample will have
|
||||
its own entry on the legend.
|
||||
|
||||
The most common use case of a bar chart is to display a
|
||||
list of y coordinates, where the x coordinate is simply the index
|
||||
in the list. But for other situations ( f.e. when values are related
|
||||
to dates ) it is also possible to set x coordinates explicitly.
|
||||
|
||||
\sa QwtPlotMultiBarChart, QwtPlotHistogram, QwtPlotCurve::Sticks,
|
||||
QwtPlotSeriesItem::orientation(), QwtPlotAbstractBarChart::baseline()
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotBarChart:
|
||||
public QwtPlotAbstractBarChart, public QwtSeriesStore<QPointF>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Legend modes.
|
||||
|
||||
The default setting is QwtPlotBarChart::LegendChartTitle.
|
||||
\sa setLegendMode(), legendMode()
|
||||
*/
|
||||
enum LegendMode
|
||||
{
|
||||
/*!
|
||||
One entry on the legend showing the default symbol
|
||||
and the title() of the chart
|
||||
|
||||
\sa QwtPlotItem::title()
|
||||
*/
|
||||
LegendChartTitle,
|
||||
|
||||
/*!
|
||||
One entry for each value showing the individual symbol
|
||||
of the corresponding bar and the bar title.
|
||||
|
||||
\sa specialSymbol(), barTitle()
|
||||
*/
|
||||
LegendBarTitles
|
||||
};
|
||||
|
||||
explicit QwtPlotBarChart( const QString &title = QString::null );
|
||||
explicit QwtPlotBarChart( const QwtText &title );
|
||||
|
||||
virtual ~QwtPlotBarChart();
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
void setSamples( const QVector<QPointF> & );
|
||||
void setSamples( const QVector<double> & );
|
||||
void setSamples( QwtSeriesData<QPointF> *series );
|
||||
|
||||
void setSymbol( QwtColumnSymbol * );
|
||||
const QwtColumnSymbol *symbol() const;
|
||||
|
||||
void setLegendMode( LegendMode );
|
||||
LegendMode legendMode() const;
|
||||
|
||||
virtual void drawSeries( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
virtual QwtColumnSymbol *specialSymbol(
|
||||
int sampleIndex, const QPointF& ) const;
|
||||
|
||||
virtual QwtText barTitle( int sampleIndex ) const;
|
||||
|
||||
protected:
|
||||
virtual void drawSample( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, const QwtInterval &boundingInterval,
|
||||
int index, const QPointF& sample ) const;
|
||||
|
||||
virtual void drawBar( QPainter *,
|
||||
int sampleIndex, const QPointF& point,
|
||||
const QwtColumnRect & ) const;
|
||||
|
||||
QList<QwtLegendData> legendData() const;
|
||||
QwtGraphic legendIcon( int index, const QSizeF & ) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,171 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_CANVAS_H
|
||||
#define QWT_PLOT_CANVAS_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qframe.h>
|
||||
#include <qpainterpath.h>
|
||||
|
||||
class QwtPlot;
|
||||
class QPixmap;
|
||||
|
||||
/*!
|
||||
\brief Canvas of a QwtPlot.
|
||||
|
||||
Canvas is the widget where all plot items are displayed
|
||||
|
||||
\sa QwtPlot::setCanvas(), QwtPlotGLCanvas
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotCanvas : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( double borderRadius READ borderRadius WRITE setBorderRadius )
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
\brief Paint attributes
|
||||
|
||||
The default setting enables BackingStore and Opaque.
|
||||
|
||||
\sa setPaintAttribute(), testPaintAttribute()
|
||||
*/
|
||||
enum PaintAttribute
|
||||
{
|
||||
/*!
|
||||
\brief Paint double buffered reusing the content
|
||||
of the pixmap buffer when possible.
|
||||
|
||||
Using a backing store might improve the performance
|
||||
significantly, when working with widget overlays ( like rubber bands ).
|
||||
Disabling the cache might improve the performance for
|
||||
incremental paints (using QwtPlotDirectPainter ).
|
||||
|
||||
\sa backingStore(), invalidateBackingStore()
|
||||
*/
|
||||
BackingStore = 1,
|
||||
|
||||
/*!
|
||||
\brief Try to fill the complete contents rectangle
|
||||
of the plot canvas
|
||||
|
||||
When using styled backgrounds Qt assumes, that the
|
||||
canvas doesn't fill its area completely
|
||||
( f.e because of rounded borders ) and fills the area
|
||||
below the canvas. When this is done with gradients it might
|
||||
result in a serious performance bottleneck - depending on the size.
|
||||
|
||||
When the Opaque attribute is enabled the canvas tries to
|
||||
identify the gaps with some heuristics and to fill those only.
|
||||
|
||||
\warning Will not work for semitransparent backgrounds
|
||||
*/
|
||||
Opaque = 2,
|
||||
|
||||
/*!
|
||||
\brief Try to improve painting of styled backgrounds
|
||||
|
||||
QwtPlotCanvas supports the box model attributes for
|
||||
customizing the layout with style sheets. Unfortunately
|
||||
the design of Qt style sheets has no concept how to
|
||||
handle backgrounds with rounded corners - beside of padding.
|
||||
|
||||
When HackStyledBackground is enabled the plot canvas tries
|
||||
to separate the background from the background border
|
||||
by reverse engineering to paint the background before and
|
||||
the border after the plot items. In this order the border
|
||||
gets perfectly antialiased and you can avoid some pixel
|
||||
artifacts in the corners.
|
||||
*/
|
||||
HackStyledBackground = 4,
|
||||
|
||||
/*!
|
||||
When ImmediatePaint is set replot() calls repaint()
|
||||
instead of update().
|
||||
|
||||
\sa replot(), QWidget::repaint(), QWidget::update()
|
||||
*/
|
||||
ImmediatePaint = 8
|
||||
};
|
||||
|
||||
//! Paint attributes
|
||||
typedef QFlags<PaintAttribute> PaintAttributes;
|
||||
|
||||
/*!
|
||||
\brief Focus indicator
|
||||
The default setting is NoFocusIndicator
|
||||
\sa setFocusIndicator(), focusIndicator(), drawFocusIndicator()
|
||||
*/
|
||||
|
||||
enum FocusIndicator
|
||||
{
|
||||
//! Don't paint a focus indicator
|
||||
NoFocusIndicator,
|
||||
|
||||
/*!
|
||||
The focus is related to the complete canvas.
|
||||
Paint the focus indicator using drawFocusIndicator()
|
||||
*/
|
||||
CanvasFocusIndicator,
|
||||
|
||||
/*!
|
||||
The focus is related to an item (curve, point, ...) on
|
||||
the canvas. It is up to the application to display a
|
||||
focus indication using f.e. highlighting.
|
||||
*/
|
||||
ItemFocusIndicator
|
||||
};
|
||||
|
||||
explicit QwtPlotCanvas( QwtPlot * = NULL );
|
||||
virtual ~QwtPlotCanvas();
|
||||
|
||||
QwtPlot *plot();
|
||||
const QwtPlot *plot() const;
|
||||
|
||||
void setFocusIndicator( FocusIndicator );
|
||||
FocusIndicator focusIndicator() const;
|
||||
|
||||
void setBorderRadius( double );
|
||||
double borderRadius() const;
|
||||
|
||||
void setPaintAttribute( PaintAttribute, bool on = true );
|
||||
bool testPaintAttribute( PaintAttribute ) const;
|
||||
|
||||
const QPixmap *backingStore() const;
|
||||
void invalidateBackingStore();
|
||||
|
||||
virtual bool event( QEvent * );
|
||||
|
||||
Q_INVOKABLE QPainterPath borderPath( const QRect & ) const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void replot();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
virtual void resizeEvent( QResizeEvent * );
|
||||
|
||||
virtual void drawFocusIndicator( QPainter * );
|
||||
virtual void drawBorder( QPainter * );
|
||||
|
||||
void updateStyleSheetInfo();
|
||||
|
||||
private:
|
||||
void drawCanvas( QPainter *, bool withBackground );
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCanvas::PaintAttributes )
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,337 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_CURVE_H
|
||||
#define QWT_PLOT_CURVE_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_seriesitem.h"
|
||||
#include "qwt_series_data.h"
|
||||
#include "qwt_text.h"
|
||||
#include <qpen.h>
|
||||
#include <qstring.h>
|
||||
|
||||
class QPainter;
|
||||
class QPolygonF;
|
||||
class QwtScaleMap;
|
||||
class QwtSymbol;
|
||||
class QwtCurveFitter;
|
||||
|
||||
/*!
|
||||
\brief A plot item, that represents a series of points
|
||||
|
||||
A curve is the representation of a series of points in the x-y plane.
|
||||
It supports different display styles, interpolation ( f.e. spline )
|
||||
and symbols.
|
||||
|
||||
\par Usage
|
||||
<dl><dt>a) Assign curve properties</dt>
|
||||
<dd>When a curve is created, it is configured to draw black solid lines
|
||||
with in QwtPlotCurve::Lines style and no symbols.
|
||||
You can change this by calling
|
||||
setPen(), setStyle() and setSymbol().</dd>
|
||||
<dt>b) Connect/Assign data.</dt>
|
||||
<dd>QwtPlotCurve gets its points using a QwtSeriesData object offering
|
||||
a bridge to the real storage of the points ( like QAbstractItemModel ).
|
||||
There are several convenience classes derived from QwtSeriesData, that also store
|
||||
the points inside ( like QStandardItemModel ). QwtPlotCurve also offers
|
||||
a couple of variations of setSamples(), that build QwtSeriesData objects from
|
||||
arrays internally.</dd>
|
||||
<dt>c) Attach the curve to a plot</dt>
|
||||
<dd>See QwtPlotItem::attach()
|
||||
</dd></dl>
|
||||
|
||||
\par Example:
|
||||
see examples/bode
|
||||
|
||||
\sa QwtPointSeriesData, QwtSymbol, QwtScaleMap
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotCurve:
|
||||
public QwtPlotSeriesItem, public QwtSeriesStore<QPointF>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Curve styles.
|
||||
\sa setStyle(), style()
|
||||
*/
|
||||
enum CurveStyle
|
||||
{
|
||||
/*!
|
||||
Don't draw a curve. Note: This doesn't affect the symbols.
|
||||
*/
|
||||
NoCurve = -1,
|
||||
|
||||
/*!
|
||||
Connect the points with straight lines. The lines might
|
||||
be interpolated depending on the 'Fitted' attribute. Curve
|
||||
fitting can be configured using setCurveFitter().
|
||||
*/
|
||||
Lines,
|
||||
|
||||
/*!
|
||||
Draw vertical or horizontal sticks ( depending on the
|
||||
orientation() ) from a baseline which is defined by setBaseline().
|
||||
*/
|
||||
Sticks,
|
||||
|
||||
/*!
|
||||
Connect the points with a step function. The step function
|
||||
is drawn from the left to the right or vice versa,
|
||||
depending on the QwtPlotCurve::Inverted attribute.
|
||||
*/
|
||||
Steps,
|
||||
|
||||
/*!
|
||||
Draw dots at the locations of the data points. Note:
|
||||
This is different from a dotted line (see setPen()), and faster
|
||||
as a curve in QwtPlotCurve::NoStyle style and a symbol
|
||||
painting a point.
|
||||
*/
|
||||
Dots,
|
||||
|
||||
/*!
|
||||
Styles >= QwtPlotCurve::UserCurve are reserved for derived
|
||||
classes of QwtPlotCurve that overload drawCurve() with
|
||||
additional application specific curve types.
|
||||
*/
|
||||
UserCurve = 100
|
||||
};
|
||||
|
||||
/*!
|
||||
Attribute for drawing the curve
|
||||
\sa setCurveAttribute(), testCurveAttribute(), curveFitter()
|
||||
*/
|
||||
enum CurveAttribute
|
||||
{
|
||||
/*!
|
||||
For QwtPlotCurve::Steps only.
|
||||
Draws a step function from the right to the left.
|
||||
*/
|
||||
Inverted = 0x01,
|
||||
|
||||
/*!
|
||||
Only in combination with QwtPlotCurve::Lines
|
||||
A QwtCurveFitter tries to
|
||||
interpolate/smooth the curve, before it is painted.
|
||||
|
||||
\note Curve fitting requires temporary memory
|
||||
for calculating coefficients and additional points.
|
||||
If painting in QwtPlotCurve::Fitted mode is slow it might be better
|
||||
to fit the points, before they are passed to QwtPlotCurve.
|
||||
*/
|
||||
Fitted = 0x02
|
||||
};
|
||||
|
||||
//! Curve attributes
|
||||
typedef QFlags<CurveAttribute> CurveAttributes;
|
||||
|
||||
/*!
|
||||
Attributes how to represent the curve on the legend
|
||||
|
||||
\sa setLegendAttribute(), testLegendAttribute(),
|
||||
QwtPlotItem::legendData(), legendIcon()
|
||||
*/
|
||||
|
||||
enum LegendAttribute
|
||||
{
|
||||
/*!
|
||||
QwtPlotCurve tries to find a color representing the curve
|
||||
and paints a rectangle with it.
|
||||
*/
|
||||
LegendNoAttribute = 0x00,
|
||||
|
||||
/*!
|
||||
If the style() is not QwtPlotCurve::NoCurve a line
|
||||
is painted with the curve pen().
|
||||
*/
|
||||
LegendShowLine = 0x01,
|
||||
|
||||
/*!
|
||||
If the curve has a valid symbol it is painted.
|
||||
*/
|
||||
LegendShowSymbol = 0x02,
|
||||
|
||||
/*!
|
||||
If the curve has a brush a rectangle filled with the
|
||||
curve brush() is painted.
|
||||
*/
|
||||
LegendShowBrush = 0x04
|
||||
};
|
||||
|
||||
//! Legend attributes
|
||||
typedef QFlags<LegendAttribute> LegendAttributes;
|
||||
|
||||
/*!
|
||||
Attributes to modify the drawing algorithm.
|
||||
The default setting enables ClipPolygons | FilterPoints
|
||||
|
||||
\sa setPaintAttribute(), testPaintAttribute()
|
||||
*/
|
||||
enum PaintAttribute
|
||||
{
|
||||
/*!
|
||||
Clip polygons before painting them. In situations, where points
|
||||
are far outside the visible area (f.e when zooming deep) this
|
||||
might be a substantial improvement for the painting performance
|
||||
*/
|
||||
ClipPolygons = 0x01,
|
||||
|
||||
/*!
|
||||
Tries to reduce the data that has to be painted, by sorting out
|
||||
duplicates, or paintings outside the visible area. Might have a
|
||||
notable impact on curves with many close points.
|
||||
Only a couple of very basic filtering algorithms are implemented.
|
||||
*/
|
||||
FilterPoints = 0x02,
|
||||
|
||||
/*!
|
||||
Minimize memory usage that is temporarily needed for the
|
||||
translated points, before they get painted.
|
||||
This might slow down the performance of painting
|
||||
*/
|
||||
MinimizeMemory = 0x04,
|
||||
|
||||
/*!
|
||||
Render the points to a temporary image and paint the image.
|
||||
This is a very special optimization for Dots style, when
|
||||
having a huge amount of points.
|
||||
With a reasonable number of points QPainter::drawPoints()
|
||||
will be faster.
|
||||
*/
|
||||
ImageBuffer = 0x08
|
||||
};
|
||||
|
||||
//! Paint attributes
|
||||
typedef QFlags<PaintAttribute> PaintAttributes;
|
||||
|
||||
explicit QwtPlotCurve( const QString &title = QString::null );
|
||||
explicit QwtPlotCurve( const QwtText &title );
|
||||
|
||||
virtual ~QwtPlotCurve();
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
void setPaintAttribute( PaintAttribute, bool on = true );
|
||||
bool testPaintAttribute( PaintAttribute ) const;
|
||||
|
||||
void setLegendAttribute( LegendAttribute, bool on = true );
|
||||
bool testLegendAttribute( LegendAttribute ) const;
|
||||
|
||||
#ifndef QWT_NO_COMPAT
|
||||
void setRawSamples( const double *xData, const double *yData, int size );
|
||||
void setSamples( const double *xData, const double *yData, int size );
|
||||
void setSamples( const QVector<double> &xData, const QVector<double> &yData );
|
||||
#endif
|
||||
void setSamples( const QVector<QPointF> & );
|
||||
void setSamples( QwtSeriesData<QPointF> * );
|
||||
|
||||
int closestPoint( const QPoint &pos, double *dist = NULL ) const;
|
||||
|
||||
double minXValue() const;
|
||||
double maxXValue() const;
|
||||
double minYValue() const;
|
||||
double maxYValue() const;
|
||||
|
||||
void setCurveAttribute( CurveAttribute, bool on = true );
|
||||
bool testCurveAttribute( CurveAttribute ) const;
|
||||
|
||||
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setPen( const QPen & );
|
||||
const QPen &pen() const;
|
||||
|
||||
void setBrush( const QBrush & );
|
||||
const QBrush &brush() const;
|
||||
|
||||
void setBaseline( double );
|
||||
double baseline() const;
|
||||
|
||||
void setStyle( CurveStyle style );
|
||||
CurveStyle style() const;
|
||||
|
||||
void setSymbol( QwtSymbol * );
|
||||
const QwtSymbol *symbol() const;
|
||||
|
||||
void setCurveFitter( QwtCurveFitter * );
|
||||
QwtCurveFitter *curveFitter() const;
|
||||
|
||||
virtual void drawSeries( QPainter *,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
|
||||
|
||||
protected:
|
||||
|
||||
void init();
|
||||
|
||||
virtual void drawCurve( QPainter *p, int style,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawSymbols( QPainter *p, const QwtSymbol &,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawLines( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawSticks( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawDots( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawSteps( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void fillCurve( QPainter *,
|
||||
const QwtScaleMap &, const QwtScaleMap &,
|
||||
const QRectF &canvasRect, QPolygonF & ) const;
|
||||
|
||||
void closePolyline( QPainter *,
|
||||
const QwtScaleMap &, const QwtScaleMap &, QPolygonF & ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
//! boundingRect().left()
|
||||
inline double QwtPlotCurve::minXValue() const
|
||||
{
|
||||
return boundingRect().left();
|
||||
}
|
||||
|
||||
//! boundingRect().right()
|
||||
inline double QwtPlotCurve::maxXValue() const
|
||||
{
|
||||
return boundingRect().right();
|
||||
}
|
||||
|
||||
//! boundingRect().top()
|
||||
inline double QwtPlotCurve::minYValue() const
|
||||
{
|
||||
return boundingRect().top();
|
||||
}
|
||||
|
||||
//! boundingRect().bottom()
|
||||
inline double QwtPlotCurve::maxYValue() const
|
||||
{
|
||||
return boundingRect().bottom();
|
||||
}
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::PaintAttributes )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::LegendAttributes )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotCurve::CurveAttributes )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,191 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_dict.h"
|
||||
|
||||
class QwtPlotDict::PrivateData
|
||||
{
|
||||
public:
|
||||
|
||||
class ItemList: public QList<QwtPlotItem *>
|
||||
{
|
||||
public:
|
||||
void insertItem( QwtPlotItem *item )
|
||||
{
|
||||
if ( item == NULL )
|
||||
return;
|
||||
|
||||
QList<QwtPlotItem *>::iterator it =
|
||||
qUpperBound( begin(), end(), item, LessZThan() );
|
||||
insert( it, item );
|
||||
}
|
||||
|
||||
void removeItem( QwtPlotItem *item )
|
||||
{
|
||||
if ( item == NULL )
|
||||
return;
|
||||
|
||||
QList<QwtPlotItem *>::iterator it =
|
||||
qLowerBound( begin(), end(), item, LessZThan() );
|
||||
|
||||
for ( ; it != end(); ++it )
|
||||
{
|
||||
if ( item == *it )
|
||||
{
|
||||
erase( it );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
class LessZThan
|
||||
{
|
||||
public:
|
||||
inline bool operator()( const QwtPlotItem *item1,
|
||||
const QwtPlotItem *item2 ) const
|
||||
{
|
||||
return item1->z() < item2->z();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ItemList itemList;
|
||||
bool autoDelete;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
|
||||
Auto deletion is enabled.
|
||||
\sa setAutoDelete(), QwtPlotItem::attach()
|
||||
*/
|
||||
QwtPlotDict::QwtPlotDict()
|
||||
{
|
||||
d_data = new QwtPlotDict::PrivateData;
|
||||
d_data->autoDelete = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destructor
|
||||
|
||||
If autoDelete() is on, all attached items will be deleted
|
||||
\sa setAutoDelete(), autoDelete(), QwtPlotItem::attach()
|
||||
*/
|
||||
QwtPlotDict::~QwtPlotDict()
|
||||
{
|
||||
detachItems( QwtPlotItem::Rtti_PlotItem, d_data->autoDelete );
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
En/Disable Auto deletion
|
||||
|
||||
If Auto deletion is on all attached plot items will be deleted
|
||||
in the destructor of QwtPlotDict. The default value is on.
|
||||
|
||||
\sa autoDelete(), insertItem()
|
||||
*/
|
||||
void QwtPlotDict::setAutoDelete( bool autoDelete )
|
||||
{
|
||||
d_data->autoDelete = autoDelete;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if auto deletion is enabled
|
||||
\sa setAutoDelete(), insertItem()
|
||||
*/
|
||||
bool QwtPlotDict::autoDelete() const
|
||||
{
|
||||
return d_data->autoDelete;
|
||||
}
|
||||
|
||||
/*!
|
||||
Insert a plot item
|
||||
|
||||
\param item PlotItem
|
||||
\sa removeItem()
|
||||
*/
|
||||
void QwtPlotDict::insertItem( QwtPlotItem *item )
|
||||
{
|
||||
d_data->itemList.insertItem( item );
|
||||
}
|
||||
|
||||
/*!
|
||||
Remove a plot item
|
||||
|
||||
\param item PlotItem
|
||||
\sa insertItem()
|
||||
*/
|
||||
void QwtPlotDict::removeItem( QwtPlotItem *item )
|
||||
{
|
||||
d_data->itemList.removeItem( item );
|
||||
}
|
||||
|
||||
/*!
|
||||
Detach items from the dictionary
|
||||
|
||||
\param rtti In case of QwtPlotItem::Rtti_PlotItem detach all items
|
||||
otherwise only those items of the type rtti.
|
||||
\param autoDelete If true, delete all detached items
|
||||
*/
|
||||
void QwtPlotDict::detachItems( int rtti, bool autoDelete )
|
||||
{
|
||||
PrivateData::ItemList list = d_data->itemList;
|
||||
QwtPlotItemIterator it = list.begin();
|
||||
while ( it != list.end() )
|
||||
{
|
||||
QwtPlotItem *item = *it;
|
||||
|
||||
++it; // increment before removing item from the list
|
||||
|
||||
if ( rtti == QwtPlotItem::Rtti_PlotItem || item->rtti() == rtti )
|
||||
{
|
||||
item->attach( NULL );
|
||||
if ( autoDelete )
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief A QwtPlotItemList of all attached plot items.
|
||||
|
||||
Use caution when iterating these lists, as removing/detaching an item will
|
||||
invalidate the iterator. Instead you can place pointers to objects to be
|
||||
removed in a removal list, and traverse that list later.
|
||||
|
||||
\return List of all attached plot items.
|
||||
*/
|
||||
const QwtPlotItemList &QwtPlotDict::itemList() const
|
||||
{
|
||||
return d_data->itemList;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return List of all attached plot items of a specific type.
|
||||
\param rtti See QwtPlotItem::RttiValues
|
||||
\sa QwtPlotItem::rtti()
|
||||
*/
|
||||
QwtPlotItemList QwtPlotDict::itemList( int rtti ) const
|
||||
{
|
||||
if ( rtti == QwtPlotItem::Rtti_PlotItem )
|
||||
return d_data->itemList;
|
||||
|
||||
QwtPlotItemList items;
|
||||
|
||||
PrivateData::ItemList list = d_data->itemList;
|
||||
for ( QwtPlotItemIterator it = list.begin(); it != list.end(); ++it )
|
||||
{
|
||||
QwtPlotItem *item = *it;
|
||||
if ( item->rtti() == rtti )
|
||||
items += item;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
/*! \file !*/
|
||||
#ifndef QWT_PLOT_DICT
|
||||
#define QWT_PLOT_DICT
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_item.h"
|
||||
#include <qlist.h>
|
||||
|
||||
/// \var typedef QList< QwtPlotItem *> QwtPlotItemList
|
||||
/// \brief See QT 4.x assistant documentation for QList
|
||||
typedef QList<QwtPlotItem *> QwtPlotItemList;
|
||||
typedef QList<QwtPlotItem *>::ConstIterator QwtPlotItemIterator;
|
||||
|
||||
/*!
|
||||
\brief A dictionary for plot items
|
||||
|
||||
QwtPlotDict organizes plot items in increasing z-order.
|
||||
If autoDelete() is enabled, all attached items will be deleted
|
||||
in the destructor of the dictionary.
|
||||
QwtPlotDict can be used to get access to all QwtPlotItem items - or all
|
||||
items of a specific type - that are currently on the plot.
|
||||
|
||||
\sa QwtPlotItem::attach(), QwtPlotItem::detach(), QwtPlotItem::z()
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotDict
|
||||
{
|
||||
public:
|
||||
explicit QwtPlotDict();
|
||||
virtual ~QwtPlotDict();
|
||||
|
||||
void setAutoDelete( bool );
|
||||
bool autoDelete() const;
|
||||
|
||||
const QwtPlotItemList& itemList() const;
|
||||
QwtPlotItemList itemList( int rtti ) const;
|
||||
|
||||
void detachItems( int rtti = QwtPlotItem::Rtti_PlotItem,
|
||||
bool autoDelete = true );
|
||||
|
||||
protected:
|
||||
void insertItem( QwtPlotItem * );
|
||||
void removeItem( QwtPlotItem * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,321 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_directpainter.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_plot.h"
|
||||
#include "qwt_plot_canvas.h"
|
||||
#include "qwt_plot_seriesitem.h"
|
||||
#include <qpainter.h>
|
||||
#include <qevent.h>
|
||||
#include <qapplication.h>
|
||||
#include <qpixmap.h>
|
||||
|
||||
static inline void qwtRenderItem(
|
||||
QPainter *painter, const QRect &canvasRect,
|
||||
QwtPlotSeriesItem *seriesItem, int from, int to )
|
||||
{
|
||||
// A minor performance improvement is possible
|
||||
// with caching the maps. TODO ...
|
||||
|
||||
QwtPlot *plot = seriesItem->plot();
|
||||
const QwtScaleMap xMap = plot->canvasMap( seriesItem->xAxis() );
|
||||
const QwtScaleMap yMap = plot->canvasMap( seriesItem->yAxis() );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing,
|
||||
seriesItem->testRenderHint( QwtPlotItem::RenderAntialiased ) );
|
||||
seriesItem->drawSeries( painter, xMap, yMap, canvasRect, from, to );
|
||||
}
|
||||
|
||||
static inline bool qwtHasBackingStore( const QwtPlotCanvas *canvas )
|
||||
{
|
||||
return canvas->testPaintAttribute( QwtPlotCanvas::BackingStore )
|
||||
&& canvas->backingStore() && !canvas->backingStore()->isNull();
|
||||
}
|
||||
|
||||
class QwtPlotDirectPainter::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
attributes( 0 ),
|
||||
hasClipping(false),
|
||||
seriesItem( NULL ),
|
||||
from( 0 ),
|
||||
to( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
QwtPlotDirectPainter::Attributes attributes;
|
||||
|
||||
bool hasClipping;
|
||||
QRegion clipRegion;
|
||||
|
||||
QPainter painter;
|
||||
|
||||
QwtPlotSeriesItem *seriesItem;
|
||||
int from;
|
||||
int to;
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
QwtPlotDirectPainter::QwtPlotDirectPainter( QObject *parent ):
|
||||
QObject( parent )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotDirectPainter::~QwtPlotDirectPainter()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Change an attribute
|
||||
|
||||
\param attribute Attribute to change
|
||||
\param on On/Off
|
||||
|
||||
\sa Attribute, testAttribute()
|
||||
*/
|
||||
void QwtPlotDirectPainter::setAttribute( Attribute attribute, bool on )
|
||||
{
|
||||
if ( bool( d_data->attributes & attribute ) != on )
|
||||
{
|
||||
if ( on )
|
||||
d_data->attributes |= attribute;
|
||||
else
|
||||
d_data->attributes &= ~attribute;
|
||||
|
||||
if ( ( attribute == AtomicPainter ) && on )
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, when attribute is enabled
|
||||
\param attribute Attribute to be tested
|
||||
\sa Attribute, setAttribute()
|
||||
*/
|
||||
bool QwtPlotDirectPainter::testAttribute( Attribute attribute ) const
|
||||
{
|
||||
return d_data->attributes & attribute;
|
||||
}
|
||||
|
||||
/*!
|
||||
En/Disables clipping
|
||||
|
||||
\param enable Enables clipping is true, disable it otherwise
|
||||
\sa hasClipping(), clipRegion(), setClipRegion()
|
||||
*/
|
||||
void QwtPlotDirectPainter::setClipping( bool enable )
|
||||
{
|
||||
d_data->hasClipping = enable;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true, when clipping is enabled
|
||||
\sa setClipping(), clipRegion(), setClipRegion()
|
||||
*/
|
||||
bool QwtPlotDirectPainter::hasClipping() const
|
||||
{
|
||||
return d_data->hasClipping;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a clip region and enable clipping
|
||||
|
||||
Depending on the environment setting a proper clip region might improve
|
||||
the performance heavily. F.e. on Qt embedded only the clipped part of
|
||||
the backing store will be copied to a ( maybe unaccelerated ) frame buffer
|
||||
device.
|
||||
|
||||
\param region Clip region
|
||||
\sa clipRegion(), hasClipping(), setClipping()
|
||||
*/
|
||||
void QwtPlotDirectPainter::setClipRegion( const QRegion ®ion )
|
||||
{
|
||||
d_data->clipRegion = region;
|
||||
d_data->hasClipping = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Currently set clip region.
|
||||
\sa setClipRegion(), setClipping(), hasClipping()
|
||||
*/
|
||||
QRegion QwtPlotDirectPainter::clipRegion() const
|
||||
{
|
||||
return d_data->clipRegion;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Draw a set of points of a seriesItem.
|
||||
|
||||
When observing an measurement while it is running, new points have to be
|
||||
added to an existing seriesItem. drawSeries() can be used to display them avoiding
|
||||
a complete redraw of the canvas.
|
||||
|
||||
Setting plot()->canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, true);
|
||||
will result in faster painting, if the paint engine of the canvas widget
|
||||
supports this feature.
|
||||
|
||||
\param seriesItem Item to be painted
|
||||
\param from Index of the first point to be painted
|
||||
\param to Index of the last point to be painted. If to < 0 the
|
||||
series will be painted to its last point.
|
||||
*/
|
||||
void QwtPlotDirectPainter::drawSeries(
|
||||
QwtPlotSeriesItem *seriesItem, int from, int to )
|
||||
{
|
||||
if ( seriesItem == NULL || seriesItem->plot() == NULL )
|
||||
return;
|
||||
|
||||
QWidget *canvas = seriesItem->plot()->canvas();
|
||||
const QRect canvasRect = canvas->contentsRect();
|
||||
|
||||
QwtPlotCanvas *plotCanvas = qobject_cast<QwtPlotCanvas *>( canvas );
|
||||
|
||||
if ( plotCanvas && qwtHasBackingStore( plotCanvas ) )
|
||||
{
|
||||
QPainter painter( const_cast<QPixmap *>( plotCanvas->backingStore() ) );
|
||||
|
||||
if ( d_data->hasClipping )
|
||||
painter.setClipRegion( d_data->clipRegion );
|
||||
|
||||
qwtRenderItem( &painter, canvasRect, seriesItem, from, to );
|
||||
|
||||
painter.end();
|
||||
|
||||
if ( testAttribute( QwtPlotDirectPainter::FullRepaint ) )
|
||||
{
|
||||
plotCanvas->repaint();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool immediatePaint = true;
|
||||
if ( !canvas->testAttribute( Qt::WA_WState_InPaintEvent ) )
|
||||
{
|
||||
#if QT_VERSION < 0x050000
|
||||
if ( !canvas->testAttribute( Qt::WA_PaintOutsidePaintEvent ) )
|
||||
#endif
|
||||
immediatePaint = false;
|
||||
}
|
||||
|
||||
if ( immediatePaint )
|
||||
{
|
||||
if ( !d_data->painter.isActive() )
|
||||
{
|
||||
reset();
|
||||
|
||||
d_data->painter.begin( canvas );
|
||||
canvas->installEventFilter( this );
|
||||
}
|
||||
|
||||
if ( d_data->hasClipping )
|
||||
{
|
||||
d_data->painter.setClipRegion(
|
||||
QRegion( canvasRect ) & d_data->clipRegion );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !d_data->painter.hasClipping() )
|
||||
d_data->painter.setClipRect( canvasRect );
|
||||
}
|
||||
|
||||
qwtRenderItem( &d_data->painter, canvasRect, seriesItem, from, to );
|
||||
|
||||
if ( d_data->attributes & QwtPlotDirectPainter::AtomicPainter )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( d_data->hasClipping )
|
||||
d_data->painter.setClipping( false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reset();
|
||||
|
||||
d_data->seriesItem = seriesItem;
|
||||
d_data->from = from;
|
||||
d_data->to = to;
|
||||
|
||||
QRegion clipRegion = canvasRect;
|
||||
if ( d_data->hasClipping )
|
||||
clipRegion &= d_data->clipRegion;
|
||||
|
||||
canvas->installEventFilter( this );
|
||||
canvas->repaint(clipRegion);
|
||||
canvas->removeEventFilter( this );
|
||||
|
||||
d_data->seriesItem = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//! Close the internal QPainter
|
||||
void QwtPlotDirectPainter::reset()
|
||||
{
|
||||
if ( d_data->painter.isActive() )
|
||||
{
|
||||
QWidget *w = static_cast<QWidget *>( d_data->painter.device() );
|
||||
if ( w )
|
||||
w->removeEventFilter( this );
|
||||
|
||||
d_data->painter.end();
|
||||
}
|
||||
}
|
||||
|
||||
//! Event filter
|
||||
bool QwtPlotDirectPainter::eventFilter( QObject *, QEvent *event )
|
||||
{
|
||||
if ( event->type() == QEvent::Paint )
|
||||
{
|
||||
reset();
|
||||
|
||||
if ( d_data->seriesItem )
|
||||
{
|
||||
const QPaintEvent *pe = static_cast< QPaintEvent *>( event );
|
||||
|
||||
QWidget *canvas = d_data->seriesItem->plot()->canvas();
|
||||
|
||||
QPainter painter( canvas );
|
||||
painter.setClipRegion( pe->region() );
|
||||
|
||||
bool doCopyCache = testAttribute( CopyBackingStore );
|
||||
|
||||
if ( doCopyCache )
|
||||
{
|
||||
QwtPlotCanvas *plotCanvas =
|
||||
qobject_cast<QwtPlotCanvas *>( canvas );
|
||||
if ( plotCanvas )
|
||||
{
|
||||
doCopyCache = qwtHasBackingStore( plotCanvas );
|
||||
if ( doCopyCache )
|
||||
{
|
||||
painter.drawPixmap( plotCanvas->contentsRect().topLeft(),
|
||||
*plotCanvas->backingStore() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !doCopyCache )
|
||||
{
|
||||
qwtRenderItem( &painter, canvas->contentsRect(),
|
||||
d_data->seriesItem, d_data->from, d_data->to );
|
||||
}
|
||||
|
||||
return true; // don't call QwtPlotCanvas::paintEvent()
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_DIRECT_PAINTER_H
|
||||
#define QWT_PLOT_DIRECT_PAINTER_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qobject.h>
|
||||
|
||||
class QRegion;
|
||||
class QwtPlotSeriesItem;
|
||||
|
||||
/*!
|
||||
\brief Painter object trying to paint incrementally
|
||||
|
||||
Often applications want to display samples while they are
|
||||
collected. When there are too many samples complete replots
|
||||
will be expensive to be processed in a collection cycle.
|
||||
|
||||
QwtPlotDirectPainter offers an API to paint
|
||||
subsets ( f.e all additions points ) without erasing/repainting
|
||||
the plot canvas.
|
||||
|
||||
On certain environments it might be important to calculate a proper
|
||||
clip region before painting. F.e. for Qt Embedded only the clipped part
|
||||
of the backing store will be copied to a ( maybe unaccelerated )
|
||||
frame buffer.
|
||||
|
||||
\warning Incremental painting will only help when no replot is triggered
|
||||
by another operation ( like changing scales ) and nothing needs
|
||||
to be erased.
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotDirectPainter: public QObject
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Paint attributes
|
||||
\sa setAttribute(), testAttribute(), drawSeries()
|
||||
*/
|
||||
enum Attribute
|
||||
{
|
||||
/*!
|
||||
Initializing a QPainter is an expensive operation.
|
||||
When AtomicPainter is set each call of drawSeries() opens/closes
|
||||
a temporary QPainter. Otherwise QwtPlotDirectPainter tries to
|
||||
use the same QPainter as long as possible.
|
||||
*/
|
||||
AtomicPainter = 0x01,
|
||||
|
||||
/*!
|
||||
When FullRepaint is set the plot canvas is explicitly repainted
|
||||
after the samples have been rendered.
|
||||
*/
|
||||
FullRepaint = 0x02,
|
||||
|
||||
/*!
|
||||
When QwtPlotCanvas::BackingStore is enabled the painter
|
||||
has to paint to the backing store and the widget. In certain
|
||||
situations/environments it might be faster to paint to
|
||||
the backing store only and then copy the backing store to the canvas.
|
||||
This flag can also be useful for settings, where Qt fills the
|
||||
the clip region with the widget background.
|
||||
*/
|
||||
CopyBackingStore = 0x04
|
||||
};
|
||||
|
||||
//! Paint attributes
|
||||
typedef QFlags<Attribute> Attributes;
|
||||
|
||||
QwtPlotDirectPainter( QObject *parent = NULL );
|
||||
virtual ~QwtPlotDirectPainter();
|
||||
|
||||
void setAttribute( Attribute, bool on );
|
||||
bool testAttribute( Attribute ) const;
|
||||
|
||||
void setClipping( bool );
|
||||
bool hasClipping() const;
|
||||
|
||||
void setClipRegion( const QRegion & );
|
||||
QRegion clipRegion() const;
|
||||
|
||||
void drawSeries( QwtPlotSeriesItem *, int from, int to );
|
||||
void reset();
|
||||
|
||||
virtual bool eventFilter( QObject *, QEvent * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotDirectPainter::Attributes )
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,377 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_glcanvas.h"
|
||||
#include "qwt_plot.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <qevent.h>
|
||||
#include <qpainter.h>
|
||||
#include <qdrawutil.h>
|
||||
#include <qstyle.h>
|
||||
#include <qstyleoption.h>
|
||||
|
||||
#define FIX_GL_TRANSLATION 0
|
||||
|
||||
static QWidget *qwtBGWidget( QWidget *widget )
|
||||
{
|
||||
QWidget *w = widget;
|
||||
|
||||
for ( ; w->parentWidget() != NULL; w = w->parentWidget() )
|
||||
{
|
||||
if ( w->autoFillBackground() ||
|
||||
w->testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
static void qwtUpdateContentsRect( QwtPlotGLCanvas *canvas )
|
||||
{
|
||||
const int fw = canvas->frameWidth();
|
||||
canvas->setContentsMargins( fw, fw, fw, fw );
|
||||
}
|
||||
|
||||
class QwtPlotGLCanvas::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
frameStyle( QFrame::Panel | QFrame::Sunken),
|
||||
lineWidth( 2 ),
|
||||
midLineWidth( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
int frameStyle;
|
||||
int lineWidth;
|
||||
int midLineWidth;
|
||||
};
|
||||
|
||||
class QwtPlotGLCanvasFormat: public QGLFormat
|
||||
{
|
||||
public:
|
||||
QwtPlotGLCanvasFormat():
|
||||
QGLFormat( QGLFormat::defaultFormat() )
|
||||
{
|
||||
setSampleBuffers( true );
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Constructor
|
||||
|
||||
\param plot Parent plot widget
|
||||
\sa QwtPlot::setCanvas()
|
||||
*/
|
||||
QwtPlotGLCanvas::QwtPlotGLCanvas( QwtPlot *plot ):
|
||||
QGLWidget( QwtPlotGLCanvasFormat(), plot )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
setCursor( Qt::CrossCursor );
|
||||
#endif
|
||||
|
||||
setAutoFillBackground( true );
|
||||
qwtUpdateContentsRect( this );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotGLCanvas::~QwtPlotGLCanvas()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the frame style
|
||||
|
||||
\param style The bitwise OR between a shape and a shadow.
|
||||
|
||||
\sa frameStyle(), QFrame::setFrameStyle(),
|
||||
setFrameShadow(), setFrameShape()
|
||||
*/
|
||||
void QwtPlotGLCanvas::setFrameStyle( int style )
|
||||
{
|
||||
if ( style != d_data->frameStyle )
|
||||
{
|
||||
d_data->frameStyle = style;
|
||||
qwtUpdateContentsRect( this );
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return The bitwise OR between a frameShape() and a frameShadow()
|
||||
\sa setFrameStyle(), QFrame::frameStyle()
|
||||
*/
|
||||
int QwtPlotGLCanvas::frameStyle() const
|
||||
{
|
||||
return d_data->frameStyle;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the frame shadow
|
||||
|
||||
\param shadow Frame shadow
|
||||
\sa frameShadow(), setFrameShape(), QFrame::setFrameShadow()
|
||||
*/
|
||||
void QwtPlotGLCanvas::setFrameShadow( Shadow shadow )
|
||||
{
|
||||
setFrameStyle(( d_data->frameStyle & QFrame::Shape_Mask ) | shadow );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Frame shadow
|
||||
\sa setFrameShadow(), QFrame::setFrameShadow()
|
||||
*/
|
||||
QwtPlotGLCanvas::Shadow QwtPlotGLCanvas::frameShadow() const
|
||||
{
|
||||
return (Shadow) ( d_data->frameStyle & QFrame::Shadow_Mask );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the frame shape
|
||||
|
||||
\param shape Frame shape
|
||||
\sa frameShape(), setFrameShadow(), QFrame::frameShape()
|
||||
*/
|
||||
void QwtPlotGLCanvas::setFrameShape( Shape shape )
|
||||
{
|
||||
setFrameStyle( ( d_data->frameStyle & QFrame::Shadow_Mask ) | shape );
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Frame shape
|
||||
\sa setFrameShape(), QFrame::frameShape()
|
||||
*/
|
||||
QwtPlotGLCanvas::Shape QwtPlotGLCanvas::frameShape() const
|
||||
{
|
||||
return (Shape) ( d_data->frameStyle & QFrame::Shape_Mask );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the frame line width
|
||||
|
||||
The default line width is 2 pixels.
|
||||
|
||||
\param width Line width of the frame
|
||||
\sa lineWidth(), setMidLineWidth()
|
||||
*/
|
||||
void QwtPlotGLCanvas::setLineWidth( int width )
|
||||
{
|
||||
width = qMax( width, 0 );
|
||||
if ( width != d_data->lineWidth )
|
||||
{
|
||||
d_data->lineWidth = qMax( width, 0 );
|
||||
qwtUpdateContentsRect( this );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Line width of the frame
|
||||
\sa setLineWidth(), midLineWidth()
|
||||
*/
|
||||
int QwtPlotGLCanvas::lineWidth() const
|
||||
{
|
||||
return d_data->lineWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the frame mid line width
|
||||
|
||||
The default midline width is 0 pixels.
|
||||
|
||||
\param width Midline width of the frame
|
||||
\sa midLineWidth(), setLineWidth()
|
||||
*/
|
||||
void QwtPlotGLCanvas::setMidLineWidth( int width )
|
||||
{
|
||||
width = qMax( width, 0 );
|
||||
if ( width != d_data->midLineWidth )
|
||||
{
|
||||
d_data->midLineWidth = width;
|
||||
qwtUpdateContentsRect( this );
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Midline width of the frame
|
||||
\sa setMidLineWidth(), lineWidth()
|
||||
*/
|
||||
int QwtPlotGLCanvas::midLineWidth() const
|
||||
{
|
||||
return d_data->midLineWidth;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Frame width depending on the style, line width and midline width.
|
||||
*/
|
||||
int QwtPlotGLCanvas::frameWidth() const
|
||||
{
|
||||
return ( frameStyle() != NoFrame ) ? d_data->lineWidth : 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Paint event
|
||||
|
||||
\param event Paint event
|
||||
\sa QwtPlot::drawCanvas()
|
||||
*/
|
||||
void QwtPlotGLCanvas::paintEvent( QPaintEvent *event )
|
||||
{
|
||||
Q_UNUSED( event );
|
||||
|
||||
QPainter painter( this );
|
||||
|
||||
#if FIX_GL_TRANSLATION
|
||||
if ( painter.paintEngine()->type() == QPaintEngine::OpenGL2 )
|
||||
{
|
||||
// work around a translation bug of QPaintEngine::OpenGL2
|
||||
painter.translate( 1, 1 );
|
||||
}
|
||||
#endif
|
||||
|
||||
drawBackground( &painter );
|
||||
drawItems( &painter );
|
||||
|
||||
if ( !testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
if ( frameWidth() > 0 )
|
||||
drawBorder( &painter );
|
||||
}
|
||||
}
|
||||
/*!
|
||||
Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
|
||||
\param event Qt Event
|
||||
\return See QGLWidget::event()
|
||||
*/
|
||||
bool QwtPlotGLCanvas::event( QEvent *event )
|
||||
{
|
||||
const bool ok = QGLWidget::event( event );
|
||||
|
||||
if ( event->type() == QEvent::PolishRequest ||
|
||||
event->type() == QEvent::StyleChange )
|
||||
{
|
||||
// assuming, that we always have a styled background
|
||||
// when we have a style sheet
|
||||
|
||||
setAttribute( Qt::WA_StyledBackground,
|
||||
testAttribute( Qt::WA_StyleSheet ) );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the plot items
|
||||
\param painter Painter
|
||||
|
||||
\sa QwtPlot::drawCanvas()
|
||||
*/
|
||||
void QwtPlotGLCanvas::drawItems( QPainter *painter )
|
||||
{
|
||||
painter->save();
|
||||
|
||||
painter->setClipRect( contentsRect(), Qt::IntersectClip );
|
||||
|
||||
QwtPlot *plot = qobject_cast< QwtPlot *>( parent() );
|
||||
if ( plot )
|
||||
plot->drawCanvas( painter );
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the background of the canvas
|
||||
\param painter Painter
|
||||
*/
|
||||
void QwtPlotGLCanvas::drawBackground( QPainter *painter )
|
||||
{
|
||||
painter->save();
|
||||
|
||||
QWidget *w = qwtBGWidget( this );
|
||||
|
||||
const QPoint off = mapTo( w, QPoint() );
|
||||
painter->translate( -off );
|
||||
|
||||
const QRect fillRect = rect().translated( off );
|
||||
|
||||
if ( w->testAttribute( Qt::WA_StyledBackground ) )
|
||||
{
|
||||
painter->setClipRect( fillRect );
|
||||
|
||||
QStyleOption opt;
|
||||
opt.initFrom( w );
|
||||
w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
painter->fillRect( fillRect,
|
||||
w->palette().brush( w->backgroundRole() ) );
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw the border of the canvas
|
||||
\param painter Painter
|
||||
*/
|
||||
void QwtPlotGLCanvas::drawBorder( QPainter *painter )
|
||||
{
|
||||
const int fw = frameWidth();
|
||||
if ( fw <= 0 )
|
||||
return;
|
||||
|
||||
if ( frameShadow() == QwtPlotGLCanvas::Plain )
|
||||
{
|
||||
qDrawPlainRect( painter, frameRect(),
|
||||
palette().shadow().color(), lineWidth() );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( frameShape() == QwtPlotGLCanvas::Box )
|
||||
{
|
||||
qDrawShadeRect( painter, frameRect(), palette(),
|
||||
frameShadow() == Sunken, lineWidth(), midLineWidth() );
|
||||
}
|
||||
else
|
||||
{
|
||||
qDrawShadePanel( painter, frameRect(), palette(),
|
||||
frameShadow() == Sunken, lineWidth() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Calls repaint()
|
||||
void QwtPlotGLCanvas::replot()
|
||||
{
|
||||
repaint();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Empty path
|
||||
*/
|
||||
QPainterPath QwtPlotGLCanvas::borderPath( const QRect &rect ) const
|
||||
{
|
||||
Q_UNUSED( rect );
|
||||
return QPainterPath();
|
||||
}
|
||||
|
||||
//! \return The rectangle where the frame is drawn in.
|
||||
QRect QwtPlotGLCanvas::frameRect() const
|
||||
{
|
||||
const int fw = frameWidth();
|
||||
return contentsRect().adjusted( -fw, -fw, fw, fw );
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_GLCANVAS_H
|
||||
#define QWT_PLOT_GLCANVAS_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include <qframe.h>
|
||||
#include <qgl.h>
|
||||
|
||||
class QwtPlot;
|
||||
|
||||
/*!
|
||||
\brief An alternative canvas for a QwtPlot derived from QGLWidget
|
||||
|
||||
QwtPlotGLCanvas implements the very basics to act as canvas
|
||||
inside of a QwtPlot widget. It might be extended to a full
|
||||
featured alternative to QwtPlotCanvas in a future version of Qwt.
|
||||
|
||||
Even if QwtPlotGLCanvas is not derived from QFrame it imitates
|
||||
its API. When using style sheets it supports the box model - beside
|
||||
backgrounds with rounded borders.
|
||||
|
||||
\sa QwtPlot::setCanvas(), QwtPlotCanvas
|
||||
|
||||
\note With Qt4 you might want to use the QPaintEngine::OpenGL paint engine
|
||||
( see QGL::setPreferredPaintEngine() ). On a Linux test system
|
||||
QPaintEngine::OpenGL2 shows very basic problems like translated
|
||||
geometries.
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotGLCanvas: public QGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_ENUMS( Shape Shadow )
|
||||
|
||||
Q_PROPERTY( Shadow frameShadow READ frameShadow WRITE setFrameShadow )
|
||||
Q_PROPERTY( Shape frameShape READ frameShape WRITE setFrameShape )
|
||||
Q_PROPERTY( int lineWidth READ lineWidth WRITE setLineWidth )
|
||||
Q_PROPERTY( int midLineWidth READ midLineWidth WRITE setMidLineWidth )
|
||||
Q_PROPERTY( int frameWidth READ frameWidth )
|
||||
Q_PROPERTY( QRect frameRect READ frameRect DESIGNABLE false )
|
||||
|
||||
public:
|
||||
/*!
|
||||
\brief Frame shadow
|
||||
|
||||
Unfortunately it is not possible to use QFrame::Shadow
|
||||
as a property of a widget that is not derived from QFrame.
|
||||
The following enum is made for the designer only. It is safe
|
||||
to use QFrame::Shadow instead.
|
||||
*/
|
||||
enum Shadow
|
||||
{
|
||||
//! QFrame::Plain
|
||||
Plain = QFrame::Plain,
|
||||
|
||||
//! QFrame::Raised
|
||||
Raised = QFrame::Raised,
|
||||
|
||||
//! QFrame::Sunken
|
||||
Sunken = QFrame::Sunken
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Frame shape
|
||||
|
||||
Unfortunately it is not possible to use QFrame::Shape
|
||||
as a property of a widget that is not derived from QFrame.
|
||||
The following enum is made for the designer only. It is safe
|
||||
to use QFrame::Shadow instead.
|
||||
|
||||
\note QFrame::StyledPanel and QFrame::WinPanel are unsuported
|
||||
and will be displayed as QFrame::Panel.
|
||||
*/
|
||||
enum Shape
|
||||
{
|
||||
NoFrame = QFrame::NoFrame,
|
||||
|
||||
Box = QFrame::Box,
|
||||
Panel = QFrame::Panel
|
||||
};
|
||||
|
||||
explicit QwtPlotGLCanvas( QwtPlot * = NULL );
|
||||
virtual ~QwtPlotGLCanvas();
|
||||
|
||||
void setFrameStyle( int style );
|
||||
int frameStyle() const;
|
||||
|
||||
void setFrameShadow( Shadow );
|
||||
Shadow frameShadow() const;
|
||||
|
||||
void setFrameShape( Shape );
|
||||
Shape frameShape() const;
|
||||
|
||||
void setLineWidth( int );
|
||||
int lineWidth() const;
|
||||
|
||||
void setMidLineWidth( int );
|
||||
int midLineWidth() const;
|
||||
|
||||
int frameWidth() const;
|
||||
QRect frameRect() const;
|
||||
|
||||
Q_INVOKABLE QPainterPath borderPath( const QRect & ) const;
|
||||
|
||||
virtual bool event( QEvent * );
|
||||
|
||||
public Q_SLOTS:
|
||||
void replot();
|
||||
|
||||
protected:
|
||||
virtual void paintEvent( QPaintEvent * );
|
||||
|
||||
virtual void drawBackground( QPainter * );
|
||||
virtual void drawBorder( QPainter * );
|
||||
virtual void drawItems( QPainter * );
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,438 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_grid.h"
|
||||
#include "qwt_painter.h"
|
||||
#include "qwt_text.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_scale_div.h"
|
||||
#include "qwt_math.h"
|
||||
#include <qpainter.h>
|
||||
#include <qpen.h>
|
||||
|
||||
class QwtPlotGrid::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
xEnabled( true ),
|
||||
yEnabled( true ),
|
||||
xMinEnabled( false ),
|
||||
yMinEnabled( false )
|
||||
{
|
||||
}
|
||||
|
||||
bool xEnabled;
|
||||
bool yEnabled;
|
||||
bool xMinEnabled;
|
||||
bool yMinEnabled;
|
||||
|
||||
QwtScaleDiv xScaleDiv;
|
||||
QwtScaleDiv yScaleDiv;
|
||||
|
||||
QPen majorPen;
|
||||
QPen minorPen;
|
||||
};
|
||||
|
||||
//! Enables major grid, disables minor grid
|
||||
QwtPlotGrid::QwtPlotGrid():
|
||||
QwtPlotItem( QwtText( "Grid" ) )
|
||||
{
|
||||
d_data = new PrivateData;
|
||||
|
||||
setItemInterest( QwtPlotItem::ScaleInterest, true );
|
||||
setZ( 10.0 );
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotGrid::~QwtPlotGrid()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
//! \return QwtPlotItem::Rtti_PlotGrid
|
||||
int QwtPlotGrid::rtti() const
|
||||
{
|
||||
return QwtPlotItem::Rtti_PlotGrid;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable or disable vertical grid lines
|
||||
\param on Enable (true) or disable
|
||||
|
||||
\sa Minor grid lines can be enabled or disabled with
|
||||
enableXMin()
|
||||
*/
|
||||
void QwtPlotGrid::enableX( bool on )
|
||||
{
|
||||
if ( d_data->xEnabled != on )
|
||||
{
|
||||
d_data->xEnabled = on;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable or disable horizontal grid lines
|
||||
\param on Enable (true) or disable
|
||||
\sa Minor grid lines can be enabled or disabled with enableYMin()
|
||||
*/
|
||||
void QwtPlotGrid::enableY( bool on )
|
||||
{
|
||||
if ( d_data->yEnabled != on )
|
||||
{
|
||||
d_data->yEnabled = on;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable or disable minor vertical grid lines.
|
||||
\param on Enable (true) or disable
|
||||
\sa enableX()
|
||||
*/
|
||||
void QwtPlotGrid::enableXMin( bool on )
|
||||
{
|
||||
if ( d_data->xMinEnabled != on )
|
||||
{
|
||||
d_data->xMinEnabled = on;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Enable or disable minor horizontal grid lines
|
||||
\param on Enable (true) or disable
|
||||
\sa enableY()
|
||||
*/
|
||||
void QwtPlotGrid::enableYMin( bool on )
|
||||
{
|
||||
if ( d_data->yMinEnabled != on )
|
||||
{
|
||||
d_data->yMinEnabled = on;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign an x axis scale division
|
||||
|
||||
\param scaleDiv Scale division
|
||||
*/
|
||||
void QwtPlotGrid::setXDiv( const QwtScaleDiv &scaleDiv )
|
||||
{
|
||||
if ( d_data->xScaleDiv != scaleDiv )
|
||||
{
|
||||
d_data->xScaleDiv = scaleDiv;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a y axis division
|
||||
|
||||
\param scaleDiv Scale division
|
||||
*/
|
||||
void QwtPlotGrid::setYDiv( const QwtScaleDiv &scaleDiv )
|
||||
{
|
||||
if ( d_data->yScaleDiv != scaleDiv )
|
||||
{
|
||||
d_data->yScaleDiv = scaleDiv;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen for both major and minor grid lines
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotGrid::setPen( const QColor &color, qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a pen for both major and minor grid lines
|
||||
|
||||
\param pen Pen
|
||||
\sa setMajorPen(), setMinorPen()
|
||||
*/
|
||||
void QwtPlotGrid::setPen( const QPen &pen )
|
||||
{
|
||||
if ( d_data->majorPen != pen || d_data->minorPen != pen )
|
||||
{
|
||||
d_data->majorPen = pen;
|
||||
d_data->minorPen = pen;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen for both major grid lines
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotGrid::setMajorPen( const QColor &color, qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setMajorPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a pen for the major grid lines
|
||||
|
||||
\param pen Pen
|
||||
\sa majorPen(), setMinorPen(), setPen()
|
||||
*/
|
||||
void QwtPlotGrid::setMajorPen( const QPen &pen )
|
||||
{
|
||||
if ( d_data->majorPen != pen )
|
||||
{
|
||||
d_data->majorPen = pen;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen for the minor grid lines
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotGrid::setMinorPen( const QColor &color, qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setMinorPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a pen for the minor grid lines
|
||||
|
||||
\param pen Pen
|
||||
\sa minorPen(), setMajorPen(), setPen()
|
||||
*/
|
||||
void QwtPlotGrid::setMinorPen( const QPen &pen )
|
||||
{
|
||||
if ( d_data->minorPen != pen )
|
||||
{
|
||||
d_data->minorPen = pen;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Draw the grid
|
||||
|
||||
The grid is drawn into the bounding rectangle such that
|
||||
grid lines begin and end at the rectangle's borders. The X and Y
|
||||
maps are used to map the scale divisions into the drawing region
|
||||
screen.
|
||||
|
||||
\param painter Painter
|
||||
\param xMap X axis map
|
||||
\param yMap Y axis
|
||||
\param canvasRect Contents rectangle of the plot canvas
|
||||
*/
|
||||
void QwtPlotGrid::draw( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect ) const
|
||||
{
|
||||
// draw minor grid lines
|
||||
QPen minorPen = d_data->minorPen;
|
||||
minorPen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
painter->setPen( minorPen );
|
||||
|
||||
if ( d_data->xEnabled && d_data->xMinEnabled )
|
||||
{
|
||||
drawLines( painter, canvasRect, Qt::Vertical, xMap,
|
||||
d_data->xScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
|
||||
drawLines( painter, canvasRect, Qt::Vertical, xMap,
|
||||
d_data->xScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
|
||||
}
|
||||
|
||||
if ( d_data->yEnabled && d_data->yMinEnabled )
|
||||
{
|
||||
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
|
||||
d_data->yScaleDiv.ticks( QwtScaleDiv::MinorTick ) );
|
||||
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
|
||||
d_data->yScaleDiv.ticks( QwtScaleDiv::MediumTick ) );
|
||||
}
|
||||
|
||||
// draw major grid lines
|
||||
QPen majorPen = d_data->majorPen;
|
||||
majorPen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
painter->setPen( majorPen );
|
||||
|
||||
if ( d_data->xEnabled )
|
||||
{
|
||||
drawLines( painter, canvasRect, Qt::Vertical, xMap,
|
||||
d_data->xScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
|
||||
}
|
||||
|
||||
if ( d_data->yEnabled )
|
||||
{
|
||||
drawLines( painter, canvasRect, Qt::Horizontal, yMap,
|
||||
d_data->yScaleDiv.ticks( QwtScaleDiv::MajorTick ) );
|
||||
}
|
||||
}
|
||||
|
||||
void QwtPlotGrid::drawLines( QPainter *painter, const QRectF &canvasRect,
|
||||
Qt::Orientation orientation, const QwtScaleMap &scaleMap,
|
||||
const QList<double> &values ) const
|
||||
{
|
||||
const double x1 = canvasRect.left();
|
||||
const double x2 = canvasRect.right() - 1.0;
|
||||
const double y1 = canvasRect.top();
|
||||
const double y2 = canvasRect.bottom() - 1.0;
|
||||
|
||||
const bool doAlign = QwtPainter::roundingAlignment( painter );
|
||||
|
||||
for ( int i = 0; i < values.count(); i++ )
|
||||
{
|
||||
double value = scaleMap.transform( values[i] );
|
||||
if ( doAlign )
|
||||
value = qRound( value );
|
||||
|
||||
if ( orientation == Qt::Horizontal )
|
||||
{
|
||||
if ( qwtFuzzyGreaterOrEqual( value, y1 ) &&
|
||||
qwtFuzzyLessOrEqual( value, y2 ) )
|
||||
{
|
||||
QwtPainter::drawLine( painter, x1, value, x2, value );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( qwtFuzzyGreaterOrEqual( value, x1 ) &&
|
||||
qwtFuzzyLessOrEqual( value, x2 ) )
|
||||
{
|
||||
QwtPainter::drawLine( painter, value, y1, value, y2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the pen for the major grid lines
|
||||
\sa setMajorPen(), setMinorPen(), setPen()
|
||||
*/
|
||||
const QPen &QwtPlotGrid::majorPen() const
|
||||
{
|
||||
return d_data->majorPen;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return the pen for the minor grid lines
|
||||
\sa setMinorPen(), setMajorPen(), setPen()
|
||||
*/
|
||||
const QPen &QwtPlotGrid::minorPen() const
|
||||
{
|
||||
return d_data->minorPen;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if vertical grid lines are enabled
|
||||
\sa enableX()
|
||||
*/
|
||||
bool QwtPlotGrid::xEnabled() const
|
||||
{
|
||||
return d_data->xEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if minor vertical grid lines are enabled
|
||||
\sa enableXMin()
|
||||
*/
|
||||
bool QwtPlotGrid::xMinEnabled() const
|
||||
{
|
||||
return d_data->xMinEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if horizontal grid lines are enabled
|
||||
\sa enableY()
|
||||
*/
|
||||
bool QwtPlotGrid::yEnabled() const
|
||||
{
|
||||
return d_data->yEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return true if minor horizontal grid lines are enabled
|
||||
\sa enableYMin()
|
||||
*/
|
||||
bool QwtPlotGrid::yMinEnabled() const
|
||||
{
|
||||
return d_data->yMinEnabled;
|
||||
}
|
||||
|
||||
|
||||
/*! \return the scale division of the x axis */
|
||||
const QwtScaleDiv &QwtPlotGrid::xScaleDiv() const
|
||||
{
|
||||
return d_data->xScaleDiv;
|
||||
}
|
||||
|
||||
/*! \return the scale division of the y axis */
|
||||
const QwtScaleDiv &QwtPlotGrid::yScaleDiv() const
|
||||
{
|
||||
return d_data->yScaleDiv;
|
||||
}
|
||||
|
||||
/*!
|
||||
Update the grid to changes of the axes scale division
|
||||
|
||||
\param xScaleDiv Scale division of the x-axis
|
||||
\param yScaleDiv Scale division of the y-axis
|
||||
|
||||
\sa QwtPlot::updateAxes()
|
||||
*/
|
||||
void QwtPlotGrid::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
|
||||
const QwtScaleDiv& yScaleDiv )
|
||||
{
|
||||
setXDiv( xScaleDiv );
|
||||
setYDiv( yScaleDiv );
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_GRID_H
|
||||
#define QWT_PLOT_GRID_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_item.h"
|
||||
#include "qwt_scale_div.h"
|
||||
|
||||
class QPainter;
|
||||
class QPen;
|
||||
class QwtScaleMap;
|
||||
class QwtScaleDiv;
|
||||
|
||||
/*!
|
||||
\brief A class which draws a coordinate grid
|
||||
|
||||
The QwtPlotGrid class can be used to draw a coordinate grid.
|
||||
A coordinate grid consists of major and minor vertical
|
||||
and horizontal grid lines. The locations of the grid lines
|
||||
are determined by the X and Y scale divisions which can
|
||||
be assigned with setXDiv() and setYDiv().
|
||||
The draw() member draws the grid within a bounding
|
||||
rectangle.
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPlotGrid: public QwtPlotItem
|
||||
{
|
||||
public:
|
||||
explicit QwtPlotGrid();
|
||||
virtual ~QwtPlotGrid();
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
void enableX( bool tf );
|
||||
bool xEnabled() const;
|
||||
|
||||
void enableY( bool tf );
|
||||
bool yEnabled() const;
|
||||
|
||||
void enableXMin( bool tf );
|
||||
bool xMinEnabled() const;
|
||||
|
||||
void enableYMin( bool tf );
|
||||
bool yMinEnabled() const;
|
||||
|
||||
void setXDiv( const QwtScaleDiv &sx );
|
||||
const QwtScaleDiv &xScaleDiv() const;
|
||||
|
||||
void setYDiv( const QwtScaleDiv &sy );
|
||||
const QwtScaleDiv &yScaleDiv() const;
|
||||
|
||||
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setPen( const QPen & );
|
||||
|
||||
void setMajorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setMajorPen( const QPen & );
|
||||
const QPen& majorPen() const;
|
||||
|
||||
void setMinorPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setMinorPen( const QPen &p );
|
||||
const QPen& minorPen() const;
|
||||
|
||||
virtual void draw( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &rect ) const;
|
||||
|
||||
virtual void updateScaleDiv(
|
||||
const QwtScaleDiv &xMap, const QwtScaleDiv &yMap );
|
||||
|
||||
private:
|
||||
void drawLines( QPainter *painter, const QRectF &,
|
||||
Qt::Orientation orientation, const QwtScaleMap &,
|
||||
const QList<double> & ) const;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,690 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_histogram.h"
|
||||
#include "qwt_plot.h"
|
||||
#include "qwt_painter.h"
|
||||
#include "qwt_column_symbol.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include <qstring.h>
|
||||
#include <qpainter.h>
|
||||
|
||||
static inline bool qwtIsCombinable( const QwtInterval &d1,
|
||||
const QwtInterval &d2 )
|
||||
{
|
||||
if ( d1.isValid() && d2.isValid() )
|
||||
{
|
||||
if ( d1.maxValue() == d2.minValue() )
|
||||
{
|
||||
if ( !( d1.borderFlags() & QwtInterval::ExcludeMaximum
|
||||
&& d2.borderFlags() & QwtInterval::ExcludeMinimum ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class QwtPlotHistogram::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
baseline( 0.0 ),
|
||||
style( Columns ),
|
||||
symbol( NULL )
|
||||
{
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
delete symbol;
|
||||
}
|
||||
|
||||
double baseline;
|
||||
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
QwtPlotHistogram::HistogramStyle style;
|
||||
const QwtColumnSymbol *symbol;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the histogram.
|
||||
*/
|
||||
QwtPlotHistogram::QwtPlotHistogram( const QwtText &title ):
|
||||
QwtPlotSeriesItem( title )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the histogram.
|
||||
*/
|
||||
QwtPlotHistogram::QwtPlotHistogram( const QString &title ):
|
||||
QwtPlotSeriesItem( title )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotHistogram::~QwtPlotHistogram()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
//! Initialize data members
|
||||
void QwtPlotHistogram::init()
|
||||
{
|
||||
d_data = new PrivateData();
|
||||
setData( new QwtIntervalSeriesData() );
|
||||
|
||||
setItemAttribute( QwtPlotItem::AutoScale, true );
|
||||
setItemAttribute( QwtPlotItem::Legend, true );
|
||||
|
||||
setZ( 20.0 );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the histogram's drawing style
|
||||
|
||||
\param style Histogram style
|
||||
\sa HistogramStyle, style()
|
||||
*/
|
||||
void QwtPlotHistogram::setStyle( HistogramStyle style )
|
||||
{
|
||||
if ( style != d_data->style )
|
||||
{
|
||||
d_data->style = style;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Style of the histogram
|
||||
\sa HistogramStyle, setStyle()
|
||||
*/
|
||||
QwtPlotHistogram::HistogramStyle QwtPlotHistogram::style() const
|
||||
{
|
||||
return d_data->style;
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotHistogram::setPen( const QColor &color, qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a pen, that is used in a style() depending way.
|
||||
|
||||
\param pen New pen
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotHistogram::setPen( const QPen &pen )
|
||||
{
|
||||
if ( pen != d_data->pen )
|
||||
{
|
||||
d_data->pen = pen;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Pen used in a style() depending way.
|
||||
\sa setPen(), brush()
|
||||
*/
|
||||
const QPen &QwtPlotHistogram::pen() const
|
||||
{
|
||||
return d_data->pen;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a brush, that is used in a style() depending way.
|
||||
|
||||
\param brush New brush
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotHistogram::setBrush( const QBrush &brush )
|
||||
{
|
||||
if ( brush != d_data->brush )
|
||||
{
|
||||
d_data->brush = brush;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Brush used in a style() depending way.
|
||||
\sa setPen(), brush()
|
||||
*/
|
||||
const QBrush &QwtPlotHistogram::brush() const
|
||||
{
|
||||
return d_data->brush;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a symbol
|
||||
|
||||
In Column style an optional symbol can be assigned, that is responsible
|
||||
for displaying the rectangle that is defined by the interval and
|
||||
the distance between baseline() and value. When no symbol has been
|
||||
defined the area is displayed as plain rectangle using pen() and brush().
|
||||
|
||||
\sa style(), symbol(), drawColumn(), pen(), brush()
|
||||
|
||||
\note In applications, where different intervals need to be displayed
|
||||
in a different way ( f.e different colors or even using different symbols)
|
||||
it is recommended to overload drawColumn().
|
||||
*/
|
||||
void QwtPlotHistogram::setSymbol( const QwtColumnSymbol *symbol )
|
||||
{
|
||||
if ( symbol != d_data->symbol )
|
||||
{
|
||||
delete d_data->symbol;
|
||||
d_data->symbol = symbol;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Current symbol or NULL, when no symbol has been assigned
|
||||
\sa setSymbol()
|
||||
*/
|
||||
const QwtColumnSymbol *QwtPlotHistogram::symbol() const
|
||||
{
|
||||
return d_data->symbol;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set the value of the baseline
|
||||
|
||||
Each column representing an QwtIntervalSample is defined by its
|
||||
interval and the interval between baseline and the value of the sample.
|
||||
|
||||
The default value of the baseline is 0.0.
|
||||
|
||||
\param value Value of the baseline
|
||||
\sa baseline()
|
||||
*/
|
||||
void QwtPlotHistogram::setBaseline( double value )
|
||||
{
|
||||
if ( d_data->baseline != value )
|
||||
{
|
||||
d_data->baseline = value;
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Value of the baseline
|
||||
\sa setBaseline()
|
||||
*/
|
||||
double QwtPlotHistogram::baseline() const
|
||||
{
|
||||
return d_data->baseline;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Bounding rectangle of all samples.
|
||||
For an empty series the rectangle is invalid.
|
||||
*/
|
||||
QRectF QwtPlotHistogram::boundingRect() const
|
||||
{
|
||||
QRectF rect = data()->boundingRect();
|
||||
if ( !rect.isValid() )
|
||||
return rect;
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
{
|
||||
rect = QRectF( rect.y(), rect.x(),
|
||||
rect.height(), rect.width() );
|
||||
|
||||
if ( rect.left() > d_data->baseline )
|
||||
rect.setLeft( d_data->baseline );
|
||||
else if ( rect.right() < d_data->baseline )
|
||||
rect.setRight( d_data->baseline );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( rect.bottom() < d_data->baseline )
|
||||
rect.setBottom( d_data->baseline );
|
||||
else if ( rect.top() > d_data->baseline )
|
||||
rect.setTop( d_data->baseline );
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
//! \return QwtPlotItem::Rtti_PlotHistogram
|
||||
int QwtPlotHistogram::rtti() const
|
||||
{
|
||||
return QwtPlotItem::Rtti_PlotHistogram;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize data with an array of samples.
|
||||
\param samples Vector of points
|
||||
*/
|
||||
void QwtPlotHistogram::setSamples(
|
||||
const QVector<QwtIntervalSample> &samples )
|
||||
{
|
||||
setData( new QwtIntervalSeriesData( samples ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a series of samples
|
||||
|
||||
setSamples() is just a wrapper for setData() without any additional
|
||||
value - beside that it is easier to find for the developer.
|
||||
|
||||
\param data Data
|
||||
\warning The item takes ownership of the data object, deleting
|
||||
it when its not used anymore.
|
||||
*/
|
||||
void QwtPlotHistogram::setSamples(
|
||||
QwtSeriesData<QwtIntervalSample> *data )
|
||||
{
|
||||
setData( data );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a subset of the histogram samples
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param canvasRect Contents rectangle of the canvas
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
series will be painted to its last sample.
|
||||
|
||||
\sa drawOutline(), drawLines(), drawColumns
|
||||
*/
|
||||
void QwtPlotHistogram::drawSeries( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &, int from, int to ) const
|
||||
{
|
||||
if ( !painter || dataSize() <= 0 )
|
||||
return;
|
||||
|
||||
if ( to < 0 )
|
||||
to = dataSize() - 1;
|
||||
|
||||
switch ( d_data->style )
|
||||
{
|
||||
case Outline:
|
||||
drawOutline( painter, xMap, yMap, from, to );
|
||||
break;
|
||||
case Lines:
|
||||
drawLines( painter, xMap, yMap, from, to );
|
||||
break;
|
||||
case Columns:
|
||||
drawColumns( painter, xMap, yMap, from, to );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a histogram in Outline style()
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
histogram will be painted to its last point.
|
||||
|
||||
\sa setStyle(), style()
|
||||
\warning The outline style requires, that the intervals are in increasing
|
||||
order and not overlapping.
|
||||
*/
|
||||
void QwtPlotHistogram::drawOutline( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const
|
||||
{
|
||||
const bool doAlign = QwtPainter::roundingAlignment( painter );
|
||||
|
||||
double v0 = ( orientation() == Qt::Horizontal ) ?
|
||||
xMap.transform( baseline() ) : yMap.transform( baseline() );
|
||||
if ( doAlign )
|
||||
v0 = qRound( v0 );
|
||||
|
||||
QwtIntervalSample previous;
|
||||
|
||||
QPolygonF polygon;
|
||||
for ( int i = from; i <= to; i++ )
|
||||
{
|
||||
const QwtIntervalSample sample = this->sample( i );
|
||||
|
||||
if ( !sample.interval.isValid() )
|
||||
{
|
||||
flushPolygon( painter, v0, polygon );
|
||||
previous = sample;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( previous.interval.isValid() )
|
||||
{
|
||||
if ( !qwtIsCombinable( previous.interval, sample.interval ) )
|
||||
flushPolygon( painter, v0, polygon );
|
||||
}
|
||||
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
double x1 = xMap.transform( sample.interval.minValue() );
|
||||
double x2 = xMap.transform( sample.interval.maxValue() );
|
||||
double y = yMap.transform( sample.value );
|
||||
if ( doAlign )
|
||||
{
|
||||
x1 = qRound( x1 );
|
||||
x2 = qRound( x2 );
|
||||
y = qRound( y );
|
||||
}
|
||||
|
||||
if ( polygon.size() == 0 )
|
||||
polygon += QPointF( x1, v0 );
|
||||
|
||||
polygon += QPointF( x1, y );
|
||||
polygon += QPointF( x2, y );
|
||||
}
|
||||
else
|
||||
{
|
||||
double y1 = yMap.transform( sample.interval.minValue() );
|
||||
double y2 = yMap.transform( sample.interval.maxValue() );
|
||||
double x = xMap.transform( sample.value );
|
||||
if ( doAlign )
|
||||
{
|
||||
y1 = qRound( y1 );
|
||||
y2 = qRound( y2 );
|
||||
x = qRound( x );
|
||||
}
|
||||
|
||||
if ( polygon.size() == 0 )
|
||||
polygon += QPointF( v0, y1 );
|
||||
|
||||
polygon += QPointF( x, y1 );
|
||||
polygon += QPointF( x, y2 );
|
||||
}
|
||||
previous = sample;
|
||||
}
|
||||
|
||||
flushPolygon( painter, v0, polygon );
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a histogram in Columns style()
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
histogram will be painted to its last point.
|
||||
|
||||
\sa setStyle(), style(), setSymbol(), drawColumn()
|
||||
*/
|
||||
void QwtPlotHistogram::drawColumns( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const
|
||||
{
|
||||
painter->setPen( d_data->pen );
|
||||
painter->setBrush( d_data->brush );
|
||||
|
||||
const QwtSeriesData<QwtIntervalSample> *series = data();
|
||||
|
||||
for ( int i = from; i <= to; i++ )
|
||||
{
|
||||
const QwtIntervalSample sample = series->sample( i );
|
||||
if ( !sample.interval.isNull() )
|
||||
{
|
||||
const QwtColumnRect rect = columnRect( sample, xMap, yMap );
|
||||
drawColumn( painter, rect, sample );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a histogram in Lines style()
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
histogram will be painted to its last point.
|
||||
|
||||
\sa setStyle(), style(), setPen()
|
||||
*/
|
||||
void QwtPlotHistogram::drawLines( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const
|
||||
{
|
||||
const bool doAlign = QwtPainter::roundingAlignment( painter );
|
||||
|
||||
painter->setPen( d_data->pen );
|
||||
painter->setBrush( Qt::NoBrush );
|
||||
|
||||
const QwtSeriesData<QwtIntervalSample> *series = data();
|
||||
|
||||
for ( int i = from; i <= to; i++ )
|
||||
{
|
||||
const QwtIntervalSample sample = series->sample( i );
|
||||
if ( !sample.interval.isNull() )
|
||||
{
|
||||
const QwtColumnRect rect = columnRect( sample, xMap, yMap );
|
||||
|
||||
QRectF r = rect.toRect();
|
||||
if ( doAlign )
|
||||
{
|
||||
r.setLeft( qRound( r.left() ) );
|
||||
r.setRight( qRound( r.right() ) );
|
||||
r.setTop( qRound( r.top() ) );
|
||||
r.setBottom( qRound( r.bottom() ) );
|
||||
}
|
||||
|
||||
switch ( rect.direction )
|
||||
{
|
||||
case QwtColumnRect::LeftToRight:
|
||||
{
|
||||
QwtPainter::drawLine( painter,
|
||||
r.topRight(), r.bottomRight() );
|
||||
break;
|
||||
}
|
||||
case QwtColumnRect::RightToLeft:
|
||||
{
|
||||
QwtPainter::drawLine( painter,
|
||||
r.topLeft(), r.bottomLeft() );
|
||||
break;
|
||||
}
|
||||
case QwtColumnRect::TopToBottom:
|
||||
{
|
||||
QwtPainter::drawLine( painter,
|
||||
r.bottomRight(), r.bottomLeft() );
|
||||
break;
|
||||
}
|
||||
case QwtColumnRect::BottomToTop:
|
||||
{
|
||||
QwtPainter::drawLine( painter,
|
||||
r.topRight(), r.topLeft() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Internal, used by the Outline style.
|
||||
void QwtPlotHistogram::flushPolygon( QPainter *painter,
|
||||
double baseLine, QPolygonF &polygon ) const
|
||||
{
|
||||
if ( polygon.size() == 0 )
|
||||
return;
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
polygon += QPointF( baseLine, polygon.last().y() );
|
||||
else
|
||||
polygon += QPointF( polygon.last().x(), baseLine );
|
||||
|
||||
if ( d_data->brush.style() != Qt::NoBrush )
|
||||
{
|
||||
painter->setPen( Qt::NoPen );
|
||||
painter->setBrush( d_data->brush );
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
{
|
||||
polygon += QPointF( polygon.last().x(), baseLine );
|
||||
polygon += QPointF( polygon.first().x(), baseLine );
|
||||
}
|
||||
else
|
||||
{
|
||||
polygon += QPointF( baseLine, polygon.last().y() );
|
||||
polygon += QPointF( baseLine, polygon.first().y() );
|
||||
}
|
||||
|
||||
QwtPainter::drawPolygon( painter, polygon );
|
||||
|
||||
polygon.pop_back();
|
||||
polygon.pop_back();
|
||||
}
|
||||
if ( d_data->pen.style() != Qt::NoPen )
|
||||
{
|
||||
painter->setBrush( Qt::NoBrush );
|
||||
painter->setPen( d_data->pen );
|
||||
QwtPainter::drawPolyline( painter, polygon );
|
||||
}
|
||||
polygon.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
Calculate the area that is covered by a sample
|
||||
|
||||
\param sample Sample
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
|
||||
\return Rectangle, that is covered by a sample
|
||||
*/
|
||||
QwtColumnRect QwtPlotHistogram::columnRect( const QwtIntervalSample &sample,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap ) const
|
||||
{
|
||||
QwtColumnRect rect;
|
||||
|
||||
const QwtInterval &iv = sample.interval;
|
||||
if ( !iv.isValid() )
|
||||
return rect;
|
||||
|
||||
if ( orientation() == Qt::Horizontal )
|
||||
{
|
||||
const double x0 = xMap.transform( baseline() );
|
||||
const double x = xMap.transform( sample.value );
|
||||
const double y1 = yMap.transform( iv.minValue() );
|
||||
const double y2 = yMap.transform( iv.maxValue() );
|
||||
|
||||
rect.hInterval.setInterval( x0, x );
|
||||
rect.vInterval.setInterval( y1, y2, iv.borderFlags() );
|
||||
rect.direction = ( x < x0 ) ? QwtColumnRect::RightToLeft :
|
||||
QwtColumnRect::LeftToRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
const double x1 = xMap.transform( iv.minValue() );
|
||||
const double x2 = xMap.transform( iv.maxValue() );
|
||||
const double y0 = yMap.transform( baseline() );
|
||||
const double y = yMap.transform( sample.value );
|
||||
|
||||
rect.hInterval.setInterval( x1, x2, iv.borderFlags() );
|
||||
rect.vInterval.setInterval( y0, y );
|
||||
rect.direction = ( y < y0 ) ? QwtColumnRect::BottomToTop :
|
||||
QwtColumnRect::TopToBottom;
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a column for a sample in Columns style().
|
||||
|
||||
When a symbol() has been set the symbol is used otherwise the
|
||||
column is displayed as plain rectangle using pen() and brush().
|
||||
|
||||
\param painter Painter
|
||||
\param rect Rectangle where to paint the column in paint device coordinates
|
||||
\param sample Sample to be displayed
|
||||
|
||||
\note In applications, where different intervals need to be displayed
|
||||
in a different way ( f.e different colors or even using different symbols)
|
||||
it is recommended to overload drawColumn().
|
||||
*/
|
||||
void QwtPlotHistogram::drawColumn( QPainter *painter,
|
||||
const QwtColumnRect &rect, const QwtIntervalSample &sample ) const
|
||||
{
|
||||
Q_UNUSED( sample );
|
||||
|
||||
if ( d_data->symbol &&
|
||||
( d_data->symbol->style() != QwtColumnSymbol::NoStyle ) )
|
||||
{
|
||||
d_data->symbol->draw( painter, rect );
|
||||
}
|
||||
else
|
||||
{
|
||||
QRectF r = rect.toRect();
|
||||
if ( QwtPainter::roundingAlignment( painter ) )
|
||||
{
|
||||
r.setLeft( qRound( r.left() ) );
|
||||
r.setRight( qRound( r.right() ) );
|
||||
r.setTop( qRound( r.top() ) );
|
||||
r.setBottom( qRound( r.bottom() ) );
|
||||
}
|
||||
|
||||
QwtPainter::drawRect( painter, r );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
A plain rectangle without pen using the brush()
|
||||
|
||||
\param index Index of the legend entry
|
||||
( ignored as there is only one )
|
||||
\param size Icon size
|
||||
\return A graphic displaying the icon
|
||||
|
||||
\sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
|
||||
*/
|
||||
QwtGraphic QwtPlotHistogram::legendIcon( int index,
|
||||
const QSizeF &size ) const
|
||||
{
|
||||
Q_UNUSED( index );
|
||||
return defaultIcon( d_data->brush, size );
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_HISTOGRAM_H
|
||||
#define QWT_PLOT_HISTOGRAM_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_seriesitem.h"
|
||||
#include "qwt_column_symbol.h"
|
||||
#include <qcolor.h>
|
||||
#include <qvector.h>
|
||||
|
||||
class QwtIntervalData;
|
||||
class QString;
|
||||
class QPolygonF;
|
||||
|
||||
/*!
|
||||
\brief QwtPlotHistogram represents a series of samples, where an interval
|
||||
is associated with a value ( \f$y = f([x1,x2])\f$ ).
|
||||
|
||||
The representation depends on the style() and an optional symbol()
|
||||
that is displayed for each interval.
|
||||
|
||||
\note The term "histogram" is used in a different way in the areas of
|
||||
digital image processing and statistics. Wikipedia introduces the
|
||||
terms "image histogram" and "color histogram" to avoid confusions.
|
||||
While "image histograms" can be displayed by a QwtPlotCurve there
|
||||
is no applicable plot item for a "color histogram" yet.
|
||||
|
||||
\sa QwtPlotBarChart, QwtPlotMultiBarChart
|
||||
*/
|
||||
|
||||
class QWT_EXPORT QwtPlotHistogram:
|
||||
public QwtPlotSeriesItem, public QwtSeriesStore<QwtIntervalSample>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
Histogram styles.
|
||||
The default style is QwtPlotHistogram::Columns.
|
||||
|
||||
\sa setStyle(), style(), setSymbol(), symbol(), setBaseline()
|
||||
*/
|
||||
enum HistogramStyle
|
||||
{
|
||||
/*!
|
||||
Draw an outline around the area, that is build by all intervals
|
||||
using the pen() and fill it with the brush(). The outline style
|
||||
requires, that the intervals are in increasing order and
|
||||
not overlapping.
|
||||
*/
|
||||
Outline,
|
||||
|
||||
/*!
|
||||
Draw a column for each interval. When a symbol() has been set
|
||||
the symbol is used otherwise the column is displayed as
|
||||
plain rectangle using pen() and brush().
|
||||
*/
|
||||
Columns,
|
||||
|
||||
/*!
|
||||
Draw a simple line using the pen() for each interval.
|
||||
*/
|
||||
Lines,
|
||||
|
||||
/*!
|
||||
Styles >= UserStyle are reserved for derived
|
||||
classes that overload drawSeries() with
|
||||
additional application specific ways to display a histogram.
|
||||
*/
|
||||
UserStyle = 100
|
||||
};
|
||||
|
||||
explicit QwtPlotHistogram( const QString &title = QString::null );
|
||||
explicit QwtPlotHistogram( const QwtText &title );
|
||||
virtual ~QwtPlotHistogram();
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setPen( const QPen & );
|
||||
const QPen &pen() const;
|
||||
|
||||
void setBrush( const QBrush & );
|
||||
const QBrush &brush() const;
|
||||
|
||||
void setSamples( const QVector<QwtIntervalSample> & );
|
||||
void setSamples( QwtSeriesData<QwtIntervalSample> * );
|
||||
|
||||
void setBaseline( double reference );
|
||||
double baseline() const;
|
||||
|
||||
void setStyle( HistogramStyle style );
|
||||
HistogramStyle style() const;
|
||||
|
||||
void setSymbol( const QwtColumnSymbol * );
|
||||
const QwtColumnSymbol *symbol() const;
|
||||
|
||||
virtual void drawSeries( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
|
||||
|
||||
protected:
|
||||
virtual QwtColumnRect columnRect( const QwtIntervalSample &,
|
||||
const QwtScaleMap &, const QwtScaleMap & ) const;
|
||||
|
||||
virtual void drawColumn( QPainter *, const QwtColumnRect &,
|
||||
const QwtIntervalSample & ) const;
|
||||
|
||||
void drawColumns( QPainter *,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const;
|
||||
|
||||
void drawOutline( QPainter *,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const;
|
||||
|
||||
void drawLines( QPainter *,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
int from, int to ) const;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void flushPolygon( QPainter *, double baseLine, QPolygonF & ) const;
|
||||
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,603 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#include "qwt_plot_intervalcurve.h"
|
||||
#include "qwt_interval_symbol.h"
|
||||
#include "qwt_scale_map.h"
|
||||
#include "qwt_clipper.h"
|
||||
#include "qwt_painter.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <qpainter.h>
|
||||
|
||||
static inline bool qwtIsHSampleInside( const QwtIntervalSample &sample,
|
||||
double xMin, double xMax, double yMin, double yMax )
|
||||
{
|
||||
const double y = sample.value;
|
||||
const double x1 = sample.interval.minValue();
|
||||
const double x2 = sample.interval.maxValue();
|
||||
|
||||
const bool isOffScreen = ( y < yMin ) || ( y > yMax )
|
||||
|| ( x1 < xMin && x2 < xMin ) || ( x1 > xMax && x2 > xMax );
|
||||
|
||||
return !isOffScreen;
|
||||
}
|
||||
|
||||
static inline bool qwtIsVSampleInside( const QwtIntervalSample &sample,
|
||||
double xMin, double xMax, double yMin, double yMax )
|
||||
{
|
||||
const double x = sample.value;
|
||||
const double y1 = sample.interval.minValue();
|
||||
const double y2 = sample.interval.maxValue();
|
||||
|
||||
const bool isOffScreen = ( x < xMin ) || ( x > xMax )
|
||||
|| ( y1 < yMin && y2 < yMin ) || ( y1 > yMax && y2 > yMax );
|
||||
|
||||
return !isOffScreen;
|
||||
}
|
||||
|
||||
class QwtPlotIntervalCurve::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
style( QwtPlotIntervalCurve::Tube ),
|
||||
symbol( NULL ),
|
||||
pen( Qt::black ),
|
||||
brush( Qt::white )
|
||||
{
|
||||
paintAttributes = QwtPlotIntervalCurve::ClipPolygons;
|
||||
paintAttributes |= QwtPlotIntervalCurve::ClipSymbol;
|
||||
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
}
|
||||
|
||||
~PrivateData()
|
||||
{
|
||||
delete symbol;
|
||||
}
|
||||
|
||||
QwtPlotIntervalCurve::CurveStyle style;
|
||||
const QwtIntervalSymbol *symbol;
|
||||
|
||||
QPen pen;
|
||||
QBrush brush;
|
||||
|
||||
QwtPlotIntervalCurve::PaintAttributes paintAttributes;
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the curve
|
||||
*/
|
||||
QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QwtText &title ):
|
||||
QwtPlotSeriesItem( title )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructor
|
||||
\param title Title of the curve
|
||||
*/
|
||||
QwtPlotIntervalCurve::QwtPlotIntervalCurve( const QString &title ):
|
||||
QwtPlotSeriesItem( QwtText( title ) )
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
QwtPlotIntervalCurve::~QwtPlotIntervalCurve()
|
||||
{
|
||||
delete d_data;
|
||||
}
|
||||
|
||||
//! Initialize internal members
|
||||
void QwtPlotIntervalCurve::init()
|
||||
{
|
||||
setItemAttribute( QwtPlotItem::Legend, true );
|
||||
setItemAttribute( QwtPlotItem::AutoScale, true );
|
||||
|
||||
d_data = new PrivateData;
|
||||
setData( new QwtIntervalSeriesData() );
|
||||
|
||||
setZ( 19.0 );
|
||||
}
|
||||
|
||||
//! \return QwtPlotItem::Rtti_PlotIntervalCurve
|
||||
int QwtPlotIntervalCurve::rtti() const
|
||||
{
|
||||
return QwtPlotIntervalCurve::Rtti_PlotIntervalCurve;
|
||||
}
|
||||
|
||||
/*!
|
||||
Specify an attribute how to draw the curve
|
||||
|
||||
\param attribute Paint attribute
|
||||
\param on On/Off
|
||||
\sa testPaintAttribute()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setPaintAttribute(
|
||||
PaintAttribute attribute, bool on )
|
||||
{
|
||||
if ( on )
|
||||
d_data->paintAttributes |= attribute;
|
||||
else
|
||||
d_data->paintAttributes &= ~attribute;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return True, when attribute is enabled
|
||||
\sa PaintAttribute, setPaintAttribute()
|
||||
*/
|
||||
bool QwtPlotIntervalCurve::testPaintAttribute(
|
||||
PaintAttribute attribute ) const
|
||||
{
|
||||
return ( d_data->paintAttributes & attribute );
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialize data with an array of samples.
|
||||
\param samples Vector of samples
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setSamples(
|
||||
const QVector<QwtIntervalSample> &samples )
|
||||
{
|
||||
setData( new QwtIntervalSeriesData( samples ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a series of samples
|
||||
|
||||
setSamples() is just a wrapper for setData() without any additional
|
||||
value - beside that it is easier to find for the developer.
|
||||
|
||||
\param data Data
|
||||
\warning The item takes ownership of the data object, deleting
|
||||
it when its not used anymore.
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setSamples(
|
||||
QwtSeriesData<QwtIntervalSample> *data )
|
||||
{
|
||||
setData( data );
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the curve's drawing style
|
||||
|
||||
\param style Curve style
|
||||
\sa CurveStyle, style()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setStyle( CurveStyle style )
|
||||
{
|
||||
if ( style != d_data->style )
|
||||
{
|
||||
d_data->style = style;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Style of the curve
|
||||
\sa setStyle()
|
||||
*/
|
||||
QwtPlotIntervalCurve::CurveStyle QwtPlotIntervalCurve::style() const
|
||||
{
|
||||
return d_data->style;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a symbol.
|
||||
|
||||
\param symbol Symbol
|
||||
\sa symbol()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setSymbol( const QwtIntervalSymbol *symbol )
|
||||
{
|
||||
if ( symbol != d_data->symbol )
|
||||
{
|
||||
delete d_data->symbol;
|
||||
d_data->symbol = symbol;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Current symbol or NULL, when no symbol has been assigned
|
||||
\sa setSymbol()
|
||||
*/
|
||||
const QwtIntervalSymbol *QwtPlotIntervalCurve::symbol() const
|
||||
{
|
||||
return d_data->symbol;
|
||||
}
|
||||
|
||||
/*!
|
||||
Build and assign a pen
|
||||
|
||||
In Qt5 the default pen width is 1.0 ( 0.0 in Qt4 ) what makes it
|
||||
non cosmetic ( see QPen::isCosmetic() ). This method has been introduced
|
||||
to hide this incompatibility.
|
||||
|
||||
\param color Pen color
|
||||
\param width Pen width
|
||||
\param style Pen style
|
||||
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setPen( const QColor &color, qreal width, Qt::PenStyle style )
|
||||
{
|
||||
setPen( QPen( color, width, style ) );
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Assign a pen
|
||||
\param pen New pen
|
||||
\sa pen(), brush()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setPen( const QPen &pen )
|
||||
{
|
||||
if ( pen != d_data->pen )
|
||||
{
|
||||
d_data->pen = pen;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Pen used to draw the lines
|
||||
\sa setPen(), brush()
|
||||
*/
|
||||
const QPen& QwtPlotIntervalCurve::pen() const
|
||||
{
|
||||
return d_data->pen;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assign a brush.
|
||||
|
||||
The brush is used to fill the area in Tube style().
|
||||
|
||||
\param brush Brush
|
||||
\sa brush(), pen(), setStyle(), CurveStyle
|
||||
*/
|
||||
void QwtPlotIntervalCurve::setBrush( const QBrush &brush )
|
||||
{
|
||||
if ( brush != d_data->brush )
|
||||
{
|
||||
d_data->brush = brush;
|
||||
|
||||
legendChanged();
|
||||
itemChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Brush used to fill the area in Tube style()
|
||||
\sa setBrush(), setStyle(), CurveStyle
|
||||
*/
|
||||
const QBrush& QwtPlotIntervalCurve::brush() const
|
||||
{
|
||||
return d_data->brush;
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Bounding rectangle of all samples.
|
||||
For an empty series the rectangle is invalid.
|
||||
*/
|
||||
QRectF QwtPlotIntervalCurve::boundingRect() const
|
||||
{
|
||||
QRectF rect = QwtPlotSeriesItem::boundingRect();
|
||||
if ( rect.isValid() && orientation() == Qt::Vertical )
|
||||
rect.setRect( rect.y(), rect.x(), rect.height(), rect.width() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a subset of the samples
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param canvasRect Contents rectangle of the canvas
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
series will be painted to its last sample.
|
||||
|
||||
\sa drawTube(), drawSymbols()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::drawSeries( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const
|
||||
{
|
||||
if ( to < 0 )
|
||||
to = dataSize() - 1;
|
||||
|
||||
if ( from < 0 )
|
||||
from = 0;
|
||||
|
||||
if ( from > to )
|
||||
return;
|
||||
|
||||
switch ( d_data->style )
|
||||
{
|
||||
case Tube:
|
||||
drawTube( painter, xMap, yMap, canvasRect, from, to );
|
||||
break;
|
||||
|
||||
case NoCurve:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( d_data->symbol &&
|
||||
( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
|
||||
{
|
||||
drawSymbols( painter, *d_data->symbol,
|
||||
xMap, yMap, canvasRect, from, to );
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw a tube
|
||||
|
||||
Builds 2 curves from the upper and lower limits of the intervals
|
||||
and draws them with the pen(). The area between the curves is
|
||||
filled with the brush().
|
||||
|
||||
\param painter Painter
|
||||
\param xMap Maps x-values into pixel coordinates.
|
||||
\param yMap Maps y-values into pixel coordinates.
|
||||
\param canvasRect Contents rectangle of the canvas
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted. If to < 0 the
|
||||
series will be painted to its last sample.
|
||||
|
||||
\sa drawSeries(), drawSymbols()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::drawTube( QPainter *painter,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const
|
||||
{
|
||||
const bool doAlign = QwtPainter::roundingAlignment( painter );
|
||||
|
||||
painter->save();
|
||||
|
||||
const size_t size = to - from + 1;
|
||||
QPolygonF polygon( 2 * size );
|
||||
QPointF *points = polygon.data();
|
||||
|
||||
for ( uint i = 0; i < size; i++ )
|
||||
{
|
||||
QPointF &minValue = points[i];
|
||||
QPointF &maxValue = points[2 * size - 1 - i];
|
||||
|
||||
const QwtIntervalSample intervalSample = sample( from + i );
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
double x = xMap.transform( intervalSample.value );
|
||||
double y1 = yMap.transform( intervalSample.interval.minValue() );
|
||||
double y2 = yMap.transform( intervalSample.interval.maxValue() );
|
||||
if ( doAlign )
|
||||
{
|
||||
x = qRound( x );
|
||||
y1 = qRound( y1 );
|
||||
y2 = qRound( y2 );
|
||||
}
|
||||
|
||||
minValue.rx() = x;
|
||||
minValue.ry() = y1;
|
||||
maxValue.rx() = x;
|
||||
maxValue.ry() = y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
double y = yMap.transform( intervalSample.value );
|
||||
double x1 = xMap.transform( intervalSample.interval.minValue() );
|
||||
double x2 = xMap.transform( intervalSample.interval.maxValue() );
|
||||
if ( doAlign )
|
||||
{
|
||||
y = qRound( y );
|
||||
x1 = qRound( x1 );
|
||||
x2 = qRound( x2 );
|
||||
}
|
||||
|
||||
minValue.rx() = x1;
|
||||
minValue.ry() = y;
|
||||
maxValue.rx() = x2;
|
||||
maxValue.ry() = y;
|
||||
}
|
||||
}
|
||||
|
||||
if ( d_data->brush.style() != Qt::NoBrush )
|
||||
{
|
||||
painter->setPen( QPen( Qt::NoPen ) );
|
||||
painter->setBrush( d_data->brush );
|
||||
|
||||
if ( d_data->paintAttributes & ClipPolygons )
|
||||
{
|
||||
const qreal m = 1.0;
|
||||
const QPolygonF p = QwtClipper::clipPolygonF(
|
||||
canvasRect.adjusted( -m, -m, m, m ), polygon, true );
|
||||
|
||||
QwtPainter::drawPolygon( painter, p );
|
||||
}
|
||||
else
|
||||
{
|
||||
QwtPainter::drawPolygon( painter, polygon );
|
||||
}
|
||||
}
|
||||
|
||||
if ( d_data->pen.style() != Qt::NoPen )
|
||||
{
|
||||
painter->setPen( d_data->pen );
|
||||
painter->setBrush( Qt::NoBrush );
|
||||
|
||||
if ( d_data->paintAttributes & ClipPolygons )
|
||||
{
|
||||
qreal pw = qMax( qreal( 1.0 ), painter->pen().widthF() );
|
||||
const QRectF clipRect = canvasRect.adjusted( -pw, -pw, pw, pw );
|
||||
|
||||
QPolygonF p;
|
||||
|
||||
p.resize( size );
|
||||
::memcpy( p.data(), points, size * sizeof( QPointF ) );
|
||||
p = QwtClipper::clipPolygonF( clipRect, p );
|
||||
QwtPainter::drawPolyline( painter, p );
|
||||
|
||||
p.resize( size );
|
||||
::memcpy( p.data(), points + size, size * sizeof( QPointF ) );
|
||||
p = QwtClipper::clipPolygonF( clipRect, p );
|
||||
QwtPainter::drawPolyline( painter, p );
|
||||
}
|
||||
else
|
||||
{
|
||||
QwtPainter::drawPolyline( painter, points, size );
|
||||
QwtPainter::drawPolyline( painter, points + size, size );
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
Draw symbols for a subset of the samples
|
||||
|
||||
\param painter Painter
|
||||
\param symbol Interval symbol
|
||||
\param xMap x map
|
||||
\param yMap y map
|
||||
\param canvasRect Contents rectangle of the canvas
|
||||
\param from Index of the first sample to be painted
|
||||
\param to Index of the last sample to be painted
|
||||
|
||||
\sa setSymbol(), drawSeries(), drawTube()
|
||||
*/
|
||||
void QwtPlotIntervalCurve::drawSymbols(
|
||||
QPainter *painter, const QwtIntervalSymbol &symbol,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
QPen pen = symbol.pen();
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
painter->setPen( pen );
|
||||
painter->setBrush( symbol.brush() );
|
||||
|
||||
const QRectF tr = QwtScaleMap::invTransform( xMap, yMap, canvasRect );
|
||||
|
||||
const double xMin = tr.left();
|
||||
const double xMax = tr.right();
|
||||
const double yMin = tr.top();
|
||||
const double yMax = tr.bottom();
|
||||
|
||||
const bool doClip = d_data->paintAttributes & ClipSymbol;
|
||||
|
||||
for ( int i = from; i <= to; i++ )
|
||||
{
|
||||
const QwtIntervalSample s = sample( i );
|
||||
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
if ( !doClip || qwtIsVSampleInside( s, xMin, xMax, yMin, yMax ) )
|
||||
{
|
||||
const double x = xMap.transform( s.value );
|
||||
const double y1 = yMap.transform( s.interval.minValue() );
|
||||
const double y2 = yMap.transform( s.interval.maxValue() );
|
||||
|
||||
symbol.draw( painter, orientation(),
|
||||
QPointF( x, y1 ), QPointF( x, y2 ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !doClip || qwtIsHSampleInside( s, xMin, xMax, yMin, yMax ) )
|
||||
{
|
||||
const double y = yMap.transform( s.value );
|
||||
const double x1 = xMap.transform( s.interval.minValue() );
|
||||
const double x2 = xMap.transform( s.interval.maxValue() );
|
||||
|
||||
symbol.draw( painter, orientation(),
|
||||
QPointF( x1, y ), QPointF( x2, y ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
/*!
|
||||
\return Icon for the legend
|
||||
|
||||
In case of Tube style() the icon is a plain rectangle filled with the brush().
|
||||
If a symbol is assigned it is scaled to size.
|
||||
|
||||
\param index Index of the legend entry
|
||||
( ignored as there is only one )
|
||||
\param size Icon size
|
||||
|
||||
\sa QwtPlotItem::setLegendIconSize(), QwtPlotItem::legendData()
|
||||
*/
|
||||
QwtGraphic QwtPlotIntervalCurve::legendIcon(
|
||||
int index, const QSizeF &size ) const
|
||||
{
|
||||
Q_UNUSED( index );
|
||||
|
||||
if ( size.isEmpty() )
|
||||
return QwtGraphic();
|
||||
|
||||
QwtGraphic icon;
|
||||
icon.setDefaultSize( size );
|
||||
icon.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
|
||||
|
||||
QPainter painter( &icon );
|
||||
painter.setRenderHint( QPainter::Antialiasing,
|
||||
testRenderHint( QwtPlotItem::RenderAntialiased ) );
|
||||
|
||||
if ( d_data->style == Tube )
|
||||
{
|
||||
QRectF r( 0, 0, size.width(), size.height() );
|
||||
painter.fillRect( r, d_data->brush );
|
||||
}
|
||||
|
||||
if ( d_data->symbol &&
|
||||
( d_data->symbol->style() != QwtIntervalSymbol::NoSymbol ) )
|
||||
{
|
||||
QPen pen = d_data->symbol->pen();
|
||||
pen.setWidthF( pen.widthF() );
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
|
||||
painter.setPen( pen );
|
||||
painter.setBrush( d_data->symbol->brush() );
|
||||
|
||||
if ( orientation() == Qt::Vertical )
|
||||
{
|
||||
const double x = 0.5 * size.width();
|
||||
|
||||
d_data->symbol->draw( &painter, orientation(),
|
||||
QPointF( x, 0 ), QPointF( x, size.height() - 1.0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
const double y = 0.5 * size.height();
|
||||
|
||||
d_data->symbol->draw( &painter, orientation(),
|
||||
QPointF( 0.0, y ), QPointF( size.width() - 1.0, y ) );
|
||||
}
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
|
||||
* Qwt Widget Library
|
||||
* Copyright (C) 1997 Josef Wilgen
|
||||
* Copyright (C) 2002 Uwe Rathmann
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the Qwt License, Version 1.0
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef QWT_PLOT_INTERVAL_CURVE_H
|
||||
#define QWT_PLOT_INTERVAL_CURVE_H
|
||||
|
||||
#include "qwt_global.h"
|
||||
#include "qwt_plot_seriesitem.h"
|
||||
#include "qwt_series_data.h"
|
||||
|
||||
class QwtIntervalSymbol;
|
||||
|
||||
/*!
|
||||
\brief QwtPlotIntervalCurve represents a series of samples, where each value
|
||||
is associated with an interval ( \f$[y1,y2] = f(x)\f$ ).
|
||||
|
||||
The representation depends on the style() and an optional symbol()
|
||||
that is displayed for each interval. QwtPlotIntervalCurve might be used
|
||||
to display error bars or the area between 2 curves.
|
||||
*/
|
||||
class QWT_EXPORT QwtPlotIntervalCurve:
|
||||
public QwtPlotSeriesItem, public QwtSeriesStore<QwtIntervalSample>
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
\brief Curve styles.
|
||||
The default setting is QwtPlotIntervalCurve::Tube.
|
||||
|
||||
\sa setStyle(), style()
|
||||
*/
|
||||
enum CurveStyle
|
||||
{
|
||||
/*!
|
||||
Don't draw a curve. Note: This doesn't affect the symbols.
|
||||
*/
|
||||
NoCurve,
|
||||
|
||||
/*!
|
||||
Build 2 curves from the upper and lower limits of the intervals
|
||||
and draw them with the pen(). The area between the curves is
|
||||
filled with the brush().
|
||||
*/
|
||||
Tube,
|
||||
|
||||
/*!
|
||||
Styles >= QwtPlotIntervalCurve::UserCurve are reserved for derived
|
||||
classes that overload drawSeries() with
|
||||
additional application specific curve types.
|
||||
*/
|
||||
UserCurve = 100
|
||||
};
|
||||
|
||||
/*!
|
||||
Attributes to modify the drawing algorithm.
|
||||
\sa setPaintAttribute(), testPaintAttribute()
|
||||
*/
|
||||
enum PaintAttribute
|
||||
{
|
||||
/*!
|
||||
Clip polygons before painting them. In situations, where points
|
||||
are far outside the visible area (f.e when zooming deep) this
|
||||
might be a substantial improvement for the painting performance.
|
||||
*/
|
||||
ClipPolygons = 0x01,
|
||||
|
||||
//! Check if a symbol is on the plot canvas before painting it.
|
||||
ClipSymbol = 0x02
|
||||
};
|
||||
|
||||
//! Paint attributes
|
||||
typedef QFlags<PaintAttribute> PaintAttributes;
|
||||
|
||||
explicit QwtPlotIntervalCurve( const QString &title = QString::null );
|
||||
explicit QwtPlotIntervalCurve( const QwtText &title );
|
||||
|
||||
virtual ~QwtPlotIntervalCurve();
|
||||
|
||||
virtual int rtti() const;
|
||||
|
||||
void setPaintAttribute( PaintAttribute, bool on = true );
|
||||
bool testPaintAttribute( PaintAttribute ) const;
|
||||
|
||||
void setSamples( const QVector<QwtIntervalSample> & );
|
||||
void setSamples( QwtSeriesData<QwtIntervalSample> * );
|
||||
|
||||
void setPen( const QColor &, qreal width = 0.0, Qt::PenStyle = Qt::SolidLine );
|
||||
void setPen( const QPen & );
|
||||
const QPen &pen() const;
|
||||
|
||||
void setBrush( const QBrush & );
|
||||
const QBrush &brush() const;
|
||||
|
||||
void setStyle( CurveStyle style );
|
||||
CurveStyle style() const;
|
||||
|
||||
void setSymbol( const QwtIntervalSymbol * );
|
||||
const QwtIntervalSymbol *symbol() const;
|
||||
|
||||
virtual void drawSeries( QPainter *p,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual QRectF boundingRect() const;
|
||||
|
||||
virtual QwtGraphic legendIcon( int index, const QSizeF & ) const;
|
||||
|
||||
protected:
|
||||
|
||||
void init();
|
||||
|
||||
virtual void drawTube( QPainter *,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
virtual void drawSymbols( QPainter *, const QwtIntervalSymbol &,
|
||||
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
|
||||
const QRectF &canvasRect, int from, int to ) const;
|
||||
|
||||
private:
|
||||
class PrivateData;
|
||||
PrivateData *d_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QwtPlotIntervalCurve::PaintAttributes )
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user