qwt_plot_scaleitem.cpp 10.8 KB
Newer Older
pixhawk's avatar
pixhawk committed
1 2 3 4
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * Qwt Widget Library
 * Copyright (C) 1997   Josef Wilgen
 * Copyright (C) 2002   Uwe Rathmann
5
 *
pixhawk's avatar
pixhawk committed
6 7 8 9
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

Bryant's avatar
Bryant committed
10
#include "qwt_plot_scaleitem.h"
pixhawk's avatar
pixhawk committed
11 12
#include "qwt_plot.h"
#include "qwt_scale_map.h"
Bryant's avatar
Bryant committed
13 14 15
#include "qwt_interval.h"
#include <qpalette.h>
#include <qpainter.h>
pixhawk's avatar
pixhawk committed
16 17 18 19 20

class QwtPlotScaleItem::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
21 22 23 24 25
        position( 0.0 ),
        borderDistance( -1 ),
        scaleDivFromAxis( true ),
        scaleDraw( new QwtScaleDraw() )
    {
pixhawk's avatar
pixhawk committed
26 27
    }

Bryant's avatar
Bryant committed
28 29
    ~PrivateData()
    {
pixhawk's avatar
pixhawk committed
30 31 32
        delete scaleDraw;
    }

Bryant's avatar
Bryant committed
33 34 35
    void updateBorders( const QRectF &,
        const QwtScaleMap &, const QwtScaleMap & );

pixhawk's avatar
pixhawk committed
36 37 38 39 40 41
    QPalette palette;
    QFont font;
    double position;
    int borderDistance;
    bool scaleDivFromAxis;
    QwtScaleDraw *scaleDraw;
Bryant's avatar
Bryant committed
42
    QRectF canvasRectCache;
pixhawk's avatar
pixhawk committed
43 44
};

Bryant's avatar
Bryant committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
void QwtPlotScaleItem::PrivateData::updateBorders( const QRectF &canvasRect,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap )
{
    QwtInterval interval;
    if ( scaleDraw->orientation() == Qt::Horizontal )
    {
        interval.setMinValue( xMap.invTransform( canvasRect.left() ) );
        interval.setMaxValue( xMap.invTransform( canvasRect.right() - 1 ) );
    }
    else
    {
        interval.setMinValue( yMap.invTransform( canvasRect.bottom() - 1 ) );
        interval.setMaxValue( yMap.invTransform( canvasRect.top() ) );
    }

    QwtScaleDiv scaleDiv = scaleDraw->scaleDiv();
    scaleDiv.setInterval( interval );
    scaleDraw->setScaleDiv( scaleDiv );
}

pixhawk's avatar
pixhawk committed
65 66 67
/*!
   \brief Constructor for scale item at the position pos.

Bryant's avatar
Bryant committed
68
   \param alignment In case of QwtScaleDraw::BottomScale or QwtScaleDraw::TopScale
69
                    the scale item is corresponding to the xAxis(),
pixhawk's avatar
pixhawk committed
70 71
                    otherwise it corresponds to the yAxis().

Bryant's avatar
Bryant committed
72
   \param pos x or y position, depending on the corresponding axis.
73

pixhawk's avatar
pixhawk committed
74 75 76
   \sa setPosition(), setAlignment()
*/
QwtPlotScaleItem::QwtPlotScaleItem(
Bryant's avatar
Bryant committed
77 78
        QwtScaleDraw::Alignment alignment, const double pos ):
    QwtPlotItem( QwtText( "Scale" ) )
pixhawk's avatar
pixhawk committed
79 80 81
{
    d_data = new PrivateData;
    d_data->position = pos;
Bryant's avatar
Bryant committed
82
    d_data->scaleDraw->setAlignment( alignment );
pixhawk's avatar
pixhawk committed
83

Bryant's avatar
Bryant committed
84 85
    setItemInterest( QwtPlotItem::ScaleInterest, true );
    setZ( 11.0 );
pixhawk's avatar
pixhawk committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
}

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

//! \return QwtPlotItem::Rtti_PlotScale
int QwtPlotScaleItem::rtti() const
{
    return QwtPlotItem::Rtti_PlotScale;
}

/*!
   \brief Assign a scale division

   When assigning a scaleDiv the scale division won't be synchronized
   with the corresponding axis anymore.

   \param scaleDiv Scale division
   \sa scaleDiv(), setScaleDivFromAxis(), isScaleDivFromAxis()
*/
Bryant's avatar
Bryant committed
109
void QwtPlotScaleItem::setScaleDiv( const QwtScaleDiv& scaleDiv )
pixhawk's avatar
pixhawk committed
110 111
{
    d_data->scaleDivFromAxis = false;
Bryant's avatar
Bryant committed
112
    d_data->scaleDraw->setScaleDiv( scaleDiv );
pixhawk's avatar
pixhawk committed
113 114 115 116 117 118 119 120 121
}

//! \return Scale division
const QwtScaleDiv& QwtPlotScaleItem::scaleDiv() const
{
    return d_data->scaleDraw->scaleDiv();
}

/*!
122
   Enable/Disable the synchronization of the scale division with
pixhawk's avatar
pixhawk committed
123 124
   the corresponding axis.

Bryant's avatar
Bryant committed
125
   \param on true/false
pixhawk's avatar
pixhawk committed
126 127
   \sa isScaleDivFromAxis()
*/
Bryant's avatar
Bryant committed
128
void QwtPlotScaleItem::setScaleDivFromAxis( bool on )
pixhawk's avatar
pixhawk committed
129
{
Bryant's avatar
Bryant committed
130 131
    if ( on != d_data->scaleDivFromAxis )
    {
pixhawk's avatar
pixhawk committed
132
        d_data->scaleDivFromAxis = on;
Bryant's avatar
Bryant committed
133 134
        if ( on )
        {
pixhawk's avatar
pixhawk committed
135
            const QwtPlot *plt = plot();
Bryant's avatar
Bryant committed
136 137 138 139
            if ( plt )
            {
                updateScaleDiv( plt->axisScaleDiv( xAxis() ),
                    plt->axisScaleDiv( yAxis() ) );
pixhawk's avatar
pixhawk committed
140 141 142 143 144 145 146
                itemChanged();
            }
        }
    }
}

/*!
147
   \return True, if the synchronization of the scale division with
pixhawk's avatar
pixhawk committed
148 149 150 151 152 153 154 155 156 157 158 159
           the corresponding axis is enabled.
   \sa setScaleDiv(), setScaleDivFromAxis()
*/
bool QwtPlotScaleItem::isScaleDivFromAxis() const
{
    return d_data->scaleDivFromAxis;
}

/*!
   Set the palette
   \sa QwtAbstractScaleDraw::draw(), palette()
*/
Bryant's avatar
Bryant committed
160
void QwtPlotScaleItem::setPalette( const QPalette &palette )
pixhawk's avatar
pixhawk committed
161
{
Bryant's avatar
Bryant committed
162 163
    if ( palette != d_data->palette )
    {
pixhawk's avatar
pixhawk committed
164
        d_data->palette = palette;
Bryant's avatar
Bryant committed
165 166

        legendChanged();
pixhawk's avatar
pixhawk committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
        itemChanged();
    }
}

/*!
   \return palette
   \sa setPalette()
*/
QPalette QwtPlotScaleItem::palette() const
{
    return d_data->palette;
}

/*!
   Change the tick label font
Bryant's avatar
Bryant committed
182
   \sa font()
pixhawk's avatar
pixhawk committed
183
*/
Bryant's avatar
Bryant committed
184
void QwtPlotScaleItem::setFont( const QFont &font )
pixhawk's avatar
pixhawk committed
185
{
Bryant's avatar
Bryant committed
186 187
    if ( font != d_data->font )
    {
pixhawk's avatar
pixhawk committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        d_data->font = font;
        itemChanged();
    }
}

/*!
   \return tick label font
   \sa setFont()
*/
QFont QwtPlotScaleItem::font() const
{
    return d_data->font;
}

/*!
  \brief Set a scale draw

  \param scaleDraw object responsible for drawing scales.

  The main use case for replacing the default QwtScaleDraw is
  to overload QwtAbstractScaleDraw::label, to replace or swallow
  tick labels.

  \sa scaleDraw()
*/
Bryant's avatar
Bryant committed
213
void QwtPlotScaleItem::setScaleDraw( QwtScaleDraw *scaleDraw )
pixhawk's avatar
pixhawk committed
214 215 216 217 218 219 220 221 222 223
{
    if ( scaleDraw == NULL )
        return;

    if ( scaleDraw != d_data->scaleDraw )
        delete d_data->scaleDraw;

    d_data->scaleDraw = scaleDraw;

    const QwtPlot *plt = plot();
Bryant's avatar
Bryant committed
224 225 226 227
    if ( plt )
    {
        updateScaleDiv( plt->axisScaleDiv( xAxis() ),
            plt->axisScaleDiv( yAxis() ) );
pixhawk's avatar
pixhawk committed
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    }

    itemChanged();
}

/*!
   \return Scale draw
   \sa setScaleDraw()
*/
const QwtScaleDraw *QwtPlotScaleItem::scaleDraw() const
{
    return d_data->scaleDraw;
}

/*!
   \return Scale draw
   \sa setScaleDraw()
*/
246
QwtScaleDraw *QwtPlotScaleItem::scaleDraw()
pixhawk's avatar
pixhawk committed
247 248 249 250 251 252
{
    return d_data->scaleDraw;
}

/*!
   Change the position of the scale
253

pixhawk's avatar
pixhawk committed
254 255 256 257 258
   The position is interpreted as y value for horizontal axes
   and as x value for vertical axes.

   The border distance is set to -1.

Bryant's avatar
Bryant committed
259
   \param pos New position
pixhawk's avatar
pixhawk committed
260 261
   \sa position(), setAlignment()
*/
Bryant's avatar
Bryant committed
262
void QwtPlotScaleItem::setPosition( double pos )
pixhawk's avatar
pixhawk committed
263
{
Bryant's avatar
Bryant committed
264 265
    if ( d_data->position != pos )
    {
pixhawk's avatar
pixhawk committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
        d_data->position = pos;
        d_data->borderDistance = -1;
        itemChanged();
    }
}

/*!
   \return Position of the scale
   \sa setPosition(), setAlignment()
*/
double QwtPlotScaleItem::position() const
{
    return d_data->position;
}

/*!
   \brief Align the scale to the canvas

284
   If distance is >= 0 the scale will be aligned to a
Bryant's avatar
Bryant committed
285
   border of the contents rectangle of the canvas. If
pixhawk's avatar
pixhawk committed
286 287 288 289 290 291
   alignment() is QwtScaleDraw::LeftScale, the scale will
   be aligned to the right border, if it is QwtScaleDraw::TopScale
   it will be aligned to the bottom (and vice versa),

   If distance is < 0 the scale will be at the position().

292
   \param distance Number of pixels between the canvas border and the
pixhawk's avatar
pixhawk committed
293 294 295 296
                   backbone of the scale.

   \sa setPosition(), borderDistance()
*/
Bryant's avatar
Bryant committed
297
void QwtPlotScaleItem::setBorderDistance( int distance )
pixhawk's avatar
pixhawk committed
298 299 300 301
{
    if ( distance < 0 )
        distance = -1;

Bryant's avatar
Bryant committed
302 303
    if ( distance != d_data->borderDistance )
    {
pixhawk's avatar
pixhawk committed
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
        d_data->borderDistance = distance;
        itemChanged();
    }
}

/*!
   \return Distance from a canvas border
   \sa setBorderDistance(), setPosition()
*/
int QwtPlotScaleItem::borderDistance() const
{
    return d_data->borderDistance;
}

/*!
   Change the alignment of the scale

321
   The alignment sets the orientation of the scale and the position of
pixhawk's avatar
pixhawk committed
322 323 324 325 326 327 328 329 330 331 332 333
   the ticks:

   - QwtScaleDraw::BottomScale: horizontal, ticks below
   - QwtScaleDraw::TopScale: horizontal, ticks above
   - QwtScaleDraw::LeftScale: vertical, ticks left
   - QwtScaleDraw::RightScale: vertical, ticks right

   For horizontal scales the position corresponds to QwtPlotItem::yAxis(),
   otherwise to QwtPlotItem::xAxis().

   \sa scaleDraw(), QwtScaleDraw::alignment(), setPosition()
*/
Bryant's avatar
Bryant committed
334
void QwtPlotScaleItem::setAlignment( QwtScaleDraw::Alignment alignment )
pixhawk's avatar
pixhawk committed
335 336
{
    QwtScaleDraw *sd = d_data->scaleDraw;
Bryant's avatar
Bryant committed
337 338 339
    if ( sd->alignment() != alignment )
    {
        sd->setAlignment( alignment );
pixhawk's avatar
pixhawk committed
340 341 342 343 344 345 346
        itemChanged();
    }
}

/*!
  \brief Draw the scale
*/
Bryant's avatar
Bryant committed
347 348 349
void QwtPlotScaleItem::draw( QPainter *painter,
    const QwtScaleMap &xMap, const QwtScaleMap &yMap,
    const QRectF &canvasRect ) const
pixhawk's avatar
pixhawk committed
350
{
Bryant's avatar
Bryant committed
351 352 353 354 355 356 357
    if ( d_data->scaleDivFromAxis )
    {
        if ( canvasRect != d_data->canvasRectCache )
        {
            d_data->updateBorders( canvasRect, xMap, yMap );
            d_data->canvasRectCache = canvasRect;
        }
pixhawk's avatar
pixhawk committed
358 359 360
    }

    QPen pen = painter->pen();
Bryant's avatar
Bryant committed
361 362
    pen.setStyle( Qt::SolidLine );
    painter->setPen( pen );
pixhawk's avatar
pixhawk committed
363 364

    QwtScaleDraw *sd = d_data->scaleDraw;
Bryant's avatar
Bryant committed
365 366 367 368 369
    if ( sd->orientation() == Qt::Horizontal )
    {
        double y;
        if ( d_data->borderDistance >= 0 )
        {
pixhawk's avatar
pixhawk committed
370 371
            if ( sd->alignment() == QwtScaleDraw::BottomScale )
                y = canvasRect.top() + d_data->borderDistance;
Bryant's avatar
Bryant committed
372 373 374
            else
            {
                y = canvasRect.bottom() - d_data->borderDistance;
pixhawk's avatar
pixhawk committed
375 376
            }

Bryant's avatar
Bryant committed
377 378 379 380
        }
        else
        {
            y = yMap.transform( d_data->position );
pixhawk's avatar
pixhawk committed
381 382 383 384 385
        }

        if ( y < canvasRect.top() || y > canvasRect.bottom() )
            return;

Bryant's avatar
Bryant committed
386 387 388 389 390 391 392 393 394 395 396 397 398 399
        sd->move( canvasRect.left(), y );
        sd->setLength( canvasRect.width() - 1 );

        QwtTransform *transform = NULL;
        if ( xMap.transformation() )
            transform = xMap.transformation()->copy();

        sd->setTransformation( transform );
    }
    else // == Qt::Vertical
    {
        double x;
        if ( d_data->borderDistance >= 0 )
        {
pixhawk's avatar
pixhawk committed
400 401
            if ( sd->alignment() == QwtScaleDraw::RightScale )
                x = canvasRect.left() + d_data->borderDistance;
Bryant's avatar
Bryant committed
402 403 404
            else
            {
                x = canvasRect.right() - d_data->borderDistance;
pixhawk's avatar
pixhawk committed
405
            }
Bryant's avatar
Bryant committed
406 407 408 409
        }
        else
        {
            x = xMap.transform( d_data->position );
pixhawk's avatar
pixhawk committed
410 411 412 413
        }
        if ( x < canvasRect.left() || x > canvasRect.right() )
            return;

Bryant's avatar
Bryant committed
414 415 416 417 418 419
        sd->move( x, canvasRect.top() );
        sd->setLength( canvasRect.height() - 1 );

        QwtTransform *transform = NULL;
        if ( yMap.transformation() )
            transform = yMap.transformation()->copy();
pixhawk's avatar
pixhawk committed
420

Bryant's avatar
Bryant committed
421 422
        sd->setTransformation( transform );
    }
pixhawk's avatar
pixhawk committed
423

Bryant's avatar
Bryant committed
424
    painter->setFont( d_data->font );
425

Bryant's avatar
Bryant committed
426
    sd->draw( painter, d_data->palette );
pixhawk's avatar
pixhawk committed
427 428 429 430 431 432 433 434 435 436 437 438 439 440
}

/*!
   \brief Update the item to changes of the axes scale division

   In case of isScaleDivFromAxis(), the scale draw is synchronized
   to the correspond axis.

   \param xScaleDiv Scale division of the x-axis
   \param yScaleDiv Scale division of the y-axis

   \sa QwtPlot::updateAxes()
*/

Bryant's avatar
Bryant committed
441 442
void QwtPlotScaleItem::updateScaleDiv( const QwtScaleDiv& xScaleDiv,
    const QwtScaleDiv& yScaleDiv )
pixhawk's avatar
pixhawk committed
443 444
{
    QwtScaleDraw *sd = d_data->scaleDraw;
Bryant's avatar
Bryant committed
445 446
    if ( d_data->scaleDivFromAxis && sd )
    {
pixhawk's avatar
pixhawk committed
447
        sd->setScaleDiv(
Bryant's avatar
Bryant committed
448 449 450 451 452 453 454 455 456
            sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv );

        const QwtPlot *plt = plot();
        if ( plt != NULL )
        {
            d_data->updateBorders( plt->canvas()->contentsRect(),
                plt->canvasMap( xAxis() ), plt->canvasMap( yAxis() ) );
            d_data->canvasRectCache = QRect();
        }
pixhawk's avatar
pixhawk committed
457 458
    }
}