/* -*- 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_zoneitem.h"
#include "qwt_painter.h"
#include "qwt_scale_map.h"
#include <qpainter.h>

class QwtPlotZoneItem::PrivateData
{
public:
    PrivateData():
        orientation( Qt::Vertical ),
        pen( Qt::NoPen )
    {
        QColor c( Qt::darkGray );
        c.setAlpha( 100 );
        brush = QBrush( c );
    }

    Qt::Orientation orientation;
    QPen pen;
    QBrush brush;
    QwtInterval interval;
};

/*!
   \brief Constructor

   Initializes the zone with no pen and a semi transparent gray brush

   Sets the following item attributes:

   - QwtPlotItem::AutoScale: false
   - QwtPlotItem::Legend:    false

   The z value is initialized by 5

   \sa QwtPlotItem::setItemAttribute(), QwtPlotItem::setZ()
*/
QwtPlotZoneItem::QwtPlotZoneItem():
    QwtPlotItem( QwtText( "Zone" ) )
{
    d_data = new PrivateData;

    setItemAttribute( QwtPlotItem::AutoScale, false );
    setItemAttribute( QwtPlotItem::Legend, false );

    setZ( 5 );
}

//! Destructor
QwtPlotZoneItem::~QwtPlotZoneItem()
{
    delete d_data;
}

//! \return QwtPlotItem::Rtti_PlotZone
int QwtPlotZoneItem::rtti() const
{
    return QwtPlotItem::Rtti_PlotZone;
}

/*!
  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 QwtPlotZoneItem::setPen( const QColor &color, qreal width, Qt::PenStyle style )
{
    setPen( QPen( color, width, style ) );
}

/*!
  \brief Assign a pen

  The pen is used to draw the border lines of the zone

  \param pen Pen
  \sa pen(), setBrush()
*/
void QwtPlotZoneItem::setPen( const QPen &pen )
{
    if ( d_data->pen != pen )
    {
        d_data->pen = pen;
        itemChanged();
    }
}

/*!
  \return Pen used to draw the border lines
  \sa setPen(), brush()
*/
const QPen &QwtPlotZoneItem::pen() const
{
    return d_data->pen;
}

/*!
  \brief Assign a brush

  The brush is used to fill the zone

  \param brush Brush
  \sa pen(), setBrush()
*/
void QwtPlotZoneItem::setBrush( const QBrush &brush )
{
    if ( d_data->brush != brush )
    {
        d_data->brush = brush;
        itemChanged();
    }
}

/*!
  \return Brush used to fill the zone
  \sa setPen(), brush()
*/
const QBrush &QwtPlotZoneItem::brush() const
{
    return d_data->brush;
}

/*!
  \brief Set the orientation of the zone

  A horizontal zone highlights an interval of the y axis,
  a vertical zone of the x axis. It is unbounded in the
  opposite direction.

  \sa orientation(), QwtPlotItem::setAxes()
*/
void QwtPlotZoneItem::setOrientation( Qt::Orientation orientation )
{
    if ( d_data->orientation != orientation )
    {
        d_data->orientation = orientation;
        itemChanged();
    }
}

/*!
  \return Orientation of the zone
  \sa setOrientation()
 */
Qt::Orientation QwtPlotZoneItem::orientation()
{
    return d_data->orientation;
}

/*!
  Set the interval of the zone

  For a horizontal zone the interval is related to the y axis,
  for a vertical zone it is related to the x axis.

  \param min Minimum of the interval
  \param max Maximum of the interval

  \sa interval(), setOrientation()
 */
void QwtPlotZoneItem::setInterval( double min, double max )
{
    setInterval( QwtInterval( min, max ) );
}

/*!
  Set the interval of the zone

  For a horizontal zone the interval is related to the y axis,
  for a vertical zone it is related to the x axis.

  \param interval Zone interval

  \sa interval(), setOrientation()
 */
void QwtPlotZoneItem::setInterval( const QwtInterval &interval )
{
    if ( d_data->interval != interval )
    {
        d_data->interval = interval;
        itemChanged();
    }
}

/*!
  \return Zone interval
  \sa setInterval(), orientation()
 */
QwtInterval QwtPlotZoneItem::interval() const
{
    return d_data->interval;
}

/*!
  Draw the zone

  \param painter Painter
  \param xMap x Scale Map
  \param yMap y Scale Map
  \param canvasRect Contents rectangle of the canvas in painter coordinates
*/

void QwtPlotZoneItem::draw( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect ) const
{
    if ( !d_data->interval.isValid() )
        return;

    QPen pen = d_data->pen;
    pen.setCapStyle( Qt::FlatCap );

    const bool doAlign = QwtPainter::roundingAlignment( painter );

    if ( d_data->orientation == Qt::Horizontal )
    {
        double y1 = yMap.transform( d_data->interval.minValue() );
        double y2 = yMap.transform( d_data->interval.maxValue() );

        if ( doAlign )
        {
            y1 = qRound( y1 );
            y2 = qRound( y2 );
        }

        QRectF r( canvasRect.left(), y1, canvasRect.width(), y2 - y1 );
        r = r.normalized();

        if ( ( d_data->brush.style() != Qt::NoBrush ) && ( y1 != y2 ) )
        {
            QwtPainter::fillRect( painter, r, d_data->brush );
        }

        if ( d_data->pen.style() != Qt::NoPen )
        {
            painter->setPen( d_data->pen );

            QwtPainter::drawLine( painter, r.left(), r.top(), r.right(), r.top() );
            QwtPainter::drawLine( painter, r.left(), r.bottom(), r.right(), r.bottom() );
        }
    }
    else
    {
        double x1 = xMap.transform( d_data->interval.minValue() );
        double x2 = xMap.transform( d_data->interval.maxValue() );

        if ( doAlign )
        {
            x1 = qRound( x1 );
            x2 = qRound( x2 );
        }

        QRectF r( x1, canvasRect.top(), x2 - x1, canvasRect.height() );
        r = r.normalized();

        if ( ( d_data->brush.style() != Qt::NoBrush ) && ( x1 != x2 ) )
        {
            QwtPainter::fillRect( painter, r, d_data->brush );
        }

        if ( d_data->pen.style() != Qt::NoPen )
        {
            painter->setPen( d_data->pen );

            QwtPainter::drawLine( painter, r.left(), r.top(), r.left(), r.bottom() );
            QwtPainter::drawLine( painter, r.right(), r.top(), r.right(), r.bottom() );
        }
    }
}

/*!
  The bounding rectangle is build from the interval in one direction
  and something invalid for the opposite direction.

  \return An invalid rectangle with valid boundaries in one direction
*/
QRectF QwtPlotZoneItem::boundingRect() const
{
    QRectF br = QwtPlotItem::boundingRect();

    const QwtInterval &intv = d_data->interval;

    if ( intv.isValid() )
    {
        if ( d_data->orientation == Qt::Horizontal )
        {
            br.setTop( intv.minValue() );
            br.setBottom( intv.maxValue() );
        }
        else
        {
            br.setLeft( intv.minValue() );
            br.setRight( intv.maxValue() );
        }
    }

    return br;
}
