qt_demoe/third/3rd_qwt/qwt_plot_marker.cpp

623 lines
14 KiB
C++
Raw Normal View History

2019-11-07 02:55:57 +00:00
/* -*- 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_marker.h"
#include "qwt_painter.h"
#include "qwt_scale_map.h"
#include "qwt_symbol.h"
#include "qwt_text.h"
#include "qwt_math.h"
#include <qpainter.h>
class QwtPlotMarker::PrivateData
{
public:
PrivateData():
labelAlignment( Qt::AlignCenter ),
labelOrientation( Qt::Horizontal ),
spacing( 2 ),
symbol( NULL ),
style( QwtPlotMarker::NoLine ),
xValue( 0.0 ),
yValue( 0.0 )
{
}
~PrivateData()
{
delete symbol;
}
QwtText label;
Qt::Alignment labelAlignment;
Qt::Orientation labelOrientation;
int spacing;
QPen pen;
const QwtSymbol *symbol;
LineStyle style;
double xValue;
double yValue;
};
//! Sets alignment to Qt::AlignCenter, and style to QwtPlotMarker::NoLine
QwtPlotMarker::QwtPlotMarker( const QString &title ):
QwtPlotItem( QwtText( title ) )
{
d_data = new PrivateData;
setZ( 30.0 );
}
//! Sets alignment to Qt::AlignCenter, and style to QwtPlotMarker::NoLine
QwtPlotMarker::QwtPlotMarker( const QwtText &title ):
QwtPlotItem( title )
{
d_data = new PrivateData;
setZ( 30.0 );
}
//! Destructor
QwtPlotMarker::~QwtPlotMarker()
{
delete d_data;
}
//! \return QwtPlotItem::Rtti_PlotMarker
int QwtPlotMarker::rtti() const
{
return QwtPlotItem::Rtti_PlotMarker;
}
//! Return Value
QPointF QwtPlotMarker::value() const
{
return QPointF( d_data->xValue, d_data->yValue );
}
//! Return x Value
double QwtPlotMarker::xValue() const
{
return d_data->xValue;
}
//! Return y Value
double QwtPlotMarker::yValue() const
{
return d_data->yValue;
}
//! Set Value
void QwtPlotMarker::setValue( const QPointF& pos )
{
setValue( pos.x(), pos.y() );
}
//! Set Value
void QwtPlotMarker::setValue( double x, double y )
{
if ( x != d_data->xValue || y != d_data->yValue )
{
d_data->xValue = x;
d_data->yValue = y;
itemChanged();
}
}
//! Set X Value
void QwtPlotMarker::setXValue( double x )
{
setValue( x, d_data->yValue );
}
//! Set Y Value
void QwtPlotMarker::setYValue( double y )
{
setValue( d_data->xValue, y );
}
/*!
Draw the marker
\param painter Painter
\param xMap x Scale Map
\param yMap y Scale Map
\param canvasRect Contents rectangle of the canvas in painter coordinates
*/
void QwtPlotMarker::draw( QPainter *painter,
const QwtScaleMap &xMap, const QwtScaleMap &yMap,
const QRectF &canvasRect ) const
{
2021-10-08 02:51:37 +00:00
const QPointF pos( xMap.transform( d_data->xValue ),
2019-11-07 02:55:57 +00:00
yMap.transform( d_data->yValue ) );
// draw lines
drawLines( painter, canvasRect, pos );
// draw symbol
if ( d_data->symbol &&
( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
{
const QSizeF sz = d_data->symbol->size();
2021-10-08 02:51:37 +00:00
const QRectF clipRect = canvasRect.adjusted(
2019-11-07 02:55:57 +00:00
-sz.width(), -sz.height(), sz.width(), sz.height() );
if ( clipRect.contains( pos ) )
d_data->symbol->drawSymbol( painter, pos );
}
drawLabel( painter, canvasRect, pos );
}
/*!
Draw the lines marker
\param painter Painter
\param canvasRect Contents rectangle of the canvas in painter coordinates
\param pos Position of the marker, translated into widget coordinates
\sa drawLabel(), QwtSymbol::drawSymbol()
*/
void QwtPlotMarker::drawLines( QPainter *painter,
const QRectF &canvasRect, const QPointF &pos ) const
{
if ( d_data->style == NoLine )
return;
const bool doAlign = QwtPainter::roundingAlignment( painter );
painter->setPen( d_data->pen );
if ( d_data->style == QwtPlotMarker::HLine ||
d_data->style == QwtPlotMarker::Cross )
{
double y = pos.y();
if ( doAlign )
y = qRound( y );
QwtPainter::drawLine( painter, canvasRect.left(),
y, canvasRect.right() - 1.0, y );
}
if ( d_data->style == QwtPlotMarker::VLine ||
d_data->style == QwtPlotMarker::Cross )
{
double x = pos.x();
if ( doAlign )
x = qRound( x );
QwtPainter::drawLine( painter, x,
canvasRect.top(), x, canvasRect.bottom() - 1.0 );
}
}
/*!
Align and draw the text label of the marker
\param painter Painter
\param canvasRect Contents rectangle of the canvas in painter coordinates
\param pos Position of the marker, translated into widget coordinates
\sa drawLabel(), QwtSymbol::drawSymbol()
*/
void QwtPlotMarker::drawLabel( QPainter *painter,
const QRectF &canvasRect, const QPointF &pos ) const
{
if ( d_data->label.isEmpty() )
return;
Qt::Alignment align = d_data->labelAlignment;
QPointF alignPos = pos;
QSizeF symbolOff( 0, 0 );
switch ( d_data->style )
{
case QwtPlotMarker::VLine:
{
// In VLine-style the y-position is pointless and
// the alignment flags are relative to the canvas
if ( d_data->labelAlignment & Qt::AlignTop )
{
alignPos.setY( canvasRect.top() );
align &= ~Qt::AlignTop;
align |= Qt::AlignBottom;
}
else if ( d_data->labelAlignment & Qt::AlignBottom )
{
// In HLine-style the x-position is pointless and
// the alignment flags are relative to the canvas
alignPos.setY( canvasRect.bottom() - 1 );
align &= ~Qt::AlignBottom;
align |= Qt::AlignTop;
}
else
{
alignPos.setY( canvasRect.center().y() );
}
break;
}
case QwtPlotMarker::HLine:
{
if ( d_data->labelAlignment & Qt::AlignLeft )
{
alignPos.setX( canvasRect.left() );
align &= ~Qt::AlignLeft;
align |= Qt::AlignRight;
}
else if ( d_data->labelAlignment & Qt::AlignRight )
{
alignPos.setX( canvasRect.right() - 1 );
align &= ~Qt::AlignRight;
align |= Qt::AlignLeft;
}
else
{
alignPos.setX( canvasRect.center().x() );
}
break;
}
default:
{
if ( d_data->symbol &&
( d_data->symbol->style() != QwtSymbol::NoSymbol ) )
{
symbolOff = d_data->symbol->size() + QSizeF( 1, 1 );
symbolOff /= 2;
}
}
}
qreal pw2 = d_data->pen.widthF() / 2.0;
if ( pw2 == 0.0 )
pw2 = 0.5;
const int spacing = d_data->spacing;
const qreal xOff = qMax( pw2, symbolOff.width() );
const qreal yOff = qMax( pw2, symbolOff.height() );
const QSizeF textSize = d_data->label.textSize( painter->font() );
if ( align & Qt::AlignLeft )
{
alignPos.rx() -= xOff + spacing;
if ( d_data->labelOrientation == Qt::Vertical )
alignPos.rx() -= textSize.height();
else
alignPos.rx() -= textSize.width();
}
else if ( align & Qt::AlignRight )
{
alignPos.rx() += xOff + spacing;
}
else
{
if ( d_data->labelOrientation == Qt::Vertical )
alignPos.rx() -= textSize.height() / 2;
else
alignPos.rx() -= textSize.width() / 2;
}
if ( align & Qt::AlignTop )
{
alignPos.ry() -= yOff + spacing;
if ( d_data->labelOrientation != Qt::Vertical )
alignPos.ry() -= textSize.height();
}
else if ( align & Qt::AlignBottom )
{
alignPos.ry() += yOff + spacing;
if ( d_data->labelOrientation == Qt::Vertical )
alignPos.ry() += textSize.width();
}
else
{
if ( d_data->labelOrientation == Qt::Vertical )
alignPos.ry() += textSize.width() / 2;
else
alignPos.ry() -= textSize.height() / 2;
}
painter->translate( alignPos.x(), alignPos.y() );
if ( d_data->labelOrientation == Qt::Vertical )
painter->rotate( -90.0 );
const QRectF textRect( 0, 0, textSize.width(), textSize.height() );
d_data->label.draw( painter, textRect );
}
/*!
\brief Set the line style
2021-10-08 02:51:37 +00:00
\param style Line style.
2019-11-07 02:55:57 +00:00
\sa lineStyle()
*/
void QwtPlotMarker::setLineStyle( LineStyle style )
{
if ( style != d_data->style )
{
d_data->style = style;
legendChanged();
itemChanged();
}
}
/*!
\return the line style
\sa setLineStyle()
*/
QwtPlotMarker::LineStyle QwtPlotMarker::lineStyle() const
{
return d_data->style;
}
/*!
\brief Assign a symbol
\param symbol New symbol
\sa symbol()
*/
void QwtPlotMarker::setSymbol( const QwtSymbol *symbol )
{
if ( symbol != d_data->symbol )
{
delete d_data->symbol;
d_data->symbol = symbol;
if ( symbol )
setLegendIconSize( symbol->boundingRect().size() );
legendChanged();
itemChanged();
}
}
/*!
\return the symbol
\sa setSymbol(), QwtSymbol
*/
const QwtSymbol *QwtPlotMarker::symbol() const
{
return d_data->symbol;
}
/*!
\brief Set the label
\param label Label text
\sa label()
*/
void QwtPlotMarker::setLabel( const QwtText& label )
{
if ( label != d_data->label )
{
d_data->label = label;
itemChanged();
}
}
/*!
\return the label
\sa setLabel()
*/
QwtText QwtPlotMarker::label() const
{
return d_data->label;
}
/*!
\brief Set the alignment of the label
In case of QwtPlotMarker::HLine the alignment is relative to the
y position of the marker, but the horizontal flags correspond to the
canvas rectangle. In case of QwtPlotMarker::VLine the alignment is
relative to the x position of the marker, but the vertical flags
correspond to the canvas rectangle.
In all other styles the alignment is relative to the marker's position.
2021-10-08 02:51:37 +00:00
\param align Alignment.
2019-11-07 02:55:57 +00:00
\sa labelAlignment(), labelOrientation()
*/
void QwtPlotMarker::setLabelAlignment( Qt::Alignment align )
{
if ( align != d_data->labelAlignment )
{
d_data->labelAlignment = align;
itemChanged();
}
}
/*!
\return the label alignment
\sa setLabelAlignment(), setLabelOrientation()
*/
Qt::Alignment QwtPlotMarker::labelAlignment() const
{
return d_data->labelAlignment;
}
/*!
\brief Set the orientation of the label
When orientation is Qt::Vertical the label is rotated by 90.0 degrees
( from bottom to top ).
\param orientation Orientation of the label
\sa labelOrientation(), setLabelAlignment()
*/
void QwtPlotMarker::setLabelOrientation( Qt::Orientation orientation )
{
if ( orientation != d_data->labelOrientation )
{
d_data->labelOrientation = orientation;
itemChanged();
}
}
/*!
\return the label orientation
\sa setLabelOrientation(), labelAlignment()
*/
Qt::Orientation QwtPlotMarker::labelOrientation() const
{
return d_data->labelOrientation;
}
/*!
\brief Set the spacing
When the label is not centered on the marker position, the spacing
is the distance between the position and the label.
\param spacing Spacing
\sa spacing(), setLabelAlignment()
*/
void QwtPlotMarker::setSpacing( int spacing )
{
if ( spacing < 0 )
spacing = 0;
if ( spacing == d_data->spacing )
return;
d_data->spacing = spacing;
itemChanged();
}
/*!
\return the spacing
\sa setSpacing()
*/
int QwtPlotMarker::spacing() const
{
return d_data->spacing;
}
2021-10-08 02:51:37 +00:00
/*!
2019-11-07 02:55:57 +00:00
Build and assign a line pen
2021-10-08 02:51:37 +00:00
2019-11-07 02:55:57 +00:00
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.
2021-10-08 02:51:37 +00:00
2019-11-07 02:55:57 +00:00
\param color Pen color
\param width Pen width
\param style Pen style
2021-10-08 02:51:37 +00:00
2019-11-07 02:55:57 +00:00
\sa pen(), brush()
2021-10-08 02:51:37 +00:00
*/
2019-11-07 02:55:57 +00:00
void QwtPlotMarker::setLinePen( const QColor &color, qreal width, Qt::PenStyle style )
2021-10-08 02:51:37 +00:00
{
2019-11-07 02:55:57 +00:00
setLinePen( QPen( color, width, style ) );
}
/*!
Specify a pen for the line.
\param pen New pen
\sa linePen()
*/
void QwtPlotMarker::setLinePen( const QPen &pen )
{
if ( pen != d_data->pen )
{
d_data->pen = pen;
legendChanged();
itemChanged();
}
}
/*!
\return the line pen
\sa setLinePen()
*/
const QPen &QwtPlotMarker::linePen() const
{
return d_data->pen;
}
QRectF QwtPlotMarker::boundingRect() const
{
2021-10-08 02:51:37 +00:00
// width/height of -1 does not affect the autoscale calculation
switch (d_data->style)
{
case QwtPlotMarker::HLine:
return QRectF( d_data->xValue, d_data->yValue, -1.0, 0.0 );
case QwtPlotMarker::VLine:
return QRectF( d_data->xValue, d_data->yValue, 0.0, -1.0 );
default :
return QRectF( d_data->xValue, d_data->yValue, 0.0, 0.0 );
}
2019-11-07 02:55:57 +00:00
}
/*!
\return Icon representing the marker on the legend
2021-10-08 02:51:37 +00:00
\param index Index of the legend entry
2019-11-07 02:55:57 +00:00
( usually there is only one )
\param size Icon size
\sa setLegendIconSize(), legendData()
*/
QwtGraphic QwtPlotMarker::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 != QwtPlotMarker::NoLine )
{
painter.setPen( d_data->pen );
if ( d_data->style == QwtPlotMarker::HLine ||
d_data->style == QwtPlotMarker::Cross )
{
const double y = 0.5 * size.height();
2021-10-08 02:51:37 +00:00
QwtPainter::drawLine( &painter,
2019-11-07 02:55:57 +00:00
0.0, y, size.width(), y );
}
if ( d_data->style == QwtPlotMarker::VLine ||
d_data->style == QwtPlotMarker::Cross )
{
const double x = 0.5 * size.width();
2021-10-08 02:51:37 +00:00
QwtPainter::drawLine( &painter,
2019-11-07 02:55:57 +00:00
x, 0.0, x, size.height() );
}
}
if ( d_data->symbol )
{
const QRect r( 0.0, 0.0, size.width(), size.height() );
d_data->symbol->drawSymbol( &painter, r );
}
return icon;
}