You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
610 lines
14 KiB
610 lines
14 KiB
/* -*- 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 |
|
{ |
|
const QPointF pos( xMap.transform( d_data->xValue ), |
|
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(); |
|
|
|
const QRectF clipRect = canvasRect.adjusted( |
|
-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 |
|
\param style Line style. |
|
\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. |
|
|
|
\param align Alignment. |
|
\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; |
|
} |
|
|
|
/*! |
|
Build and assign a line 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 QwtPlotMarker::setLinePen( const QColor &color, qreal width, Qt::PenStyle style ) |
|
{ |
|
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 |
|
{ |
|
return QRectF( d_data->xValue, d_data->yValue, 0.0, 0.0 ); |
|
} |
|
|
|
/*! |
|
\return Icon representing the marker on the legend |
|
|
|
\param index Index of the legend entry |
|
( 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(); |
|
|
|
QwtPainter::drawLine( &painter, |
|
0.0, y, size.width(), y ); |
|
} |
|
|
|
if ( d_data->style == QwtPlotMarker::VLine || |
|
d_data->style == QwtPlotMarker::Cross ) |
|
{ |
|
const double x = 0.5 * size.width(); |
|
|
|
QwtPainter::drawLine( &painter, |
|
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; |
|
} |
|
|
|
|