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 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the Qwt License, Version 1.0
 *****************************************************************************/

#include <qpalette.h>
#include <qpainter.h>
#include "qwt_plot.h"
#include "qwt_plot_canvas.h"
#include "qwt_scale_map.h"
#include "qwt_plot_scaleitem.h"
#include "qwt_double_interval.h"

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

28
    ~PrivateData() {
pixhawk's avatar
pixhawk committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
        delete scaleDraw;
    }

#if QT_VERSION < 0x040000
    QColorGroup colorGroup;
#else
    QPalette palette;
#endif
    QFont font;
    double position;
    int borderDistance;
    bool scaleDivFromAxis;
    QwtScaleDraw *scaleDraw;
    QRect canvasRectCache;
};

/*!
   \brief Constructor for scale item at the position pos.

   \param alignment In case of QwtScaleDraw::BottomScale/QwtScaleDraw::TopScale
49
                    the scale item is corresponding to the xAxis(),
pixhawk's avatar
pixhawk committed
50 51 52
                    otherwise it corresponds to the yAxis().

   \param position  x or y position, depending on the corresponding axis.
53

pixhawk's avatar
pixhawk committed
54 55 56
   \sa setPosition(), setAlignment()
*/
QwtPlotScaleItem::QwtPlotScaleItem(
57
    QwtScaleDraw::Alignment alignment, const double pos):
pixhawk's avatar
pixhawk committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
    QwtPlotItem(QwtText("Scale"))
{
    d_data = new PrivateData;
    d_data->position = pos;
    d_data->scaleDraw->setAlignment(alignment);

    setZ(11.0);
}

//! 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()
*/
void QwtPlotScaleItem::setScaleDiv(const QwtScaleDiv& scaleDiv)
{
    d_data->scaleDivFromAxis = false;
    d_data->scaleDraw->setScaleDiv(scaleDiv);
}

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

/*!
101
   Enable/Disable the synchronization of the scale division with
pixhawk's avatar
pixhawk committed
102 103 104 105 106 107
   the corresponding axis.

   \sa isScaleDivFromAxis()
*/
void QwtPlotScaleItem::setScaleDivFromAxis(bool on)
{
108
    if ( on != d_data->scaleDivFromAxis ) {
pixhawk's avatar
pixhawk committed
109
        d_data->scaleDivFromAxis = on;
110
        if ( on ) {
pixhawk's avatar
pixhawk committed
111
            const QwtPlot *plt = plot();
112
            if ( plt ) {
pixhawk's avatar
pixhawk committed
113
                updateScaleDiv( *plt->axisScaleDiv(xAxis()),
114
                                *plt->axisScaleDiv(yAxis()) );
pixhawk's avatar
pixhawk committed
115 116 117 118 119 120 121
                itemChanged();
            }
        }
    }
}

/*!
122
   \return True, if the synchronization of the scale division with
pixhawk's avatar
pixhawk committed
123 124 125 126 127 128 129 130
           the corresponding axis is enabled.
   \sa setScaleDiv(), setScaleDivFromAxis()
*/
bool QwtPlotScaleItem::isScaleDivFromAxis() const
{
    return d_data->scaleDivFromAxis;
}

131
#if QT_VERSION < 0x040000
pixhawk's avatar
pixhawk committed
132 133 134 135 136 137 138

/*!
   Set the color group
   \sa QwtAbstractScaleDraw::draw(), colorGroup()
*/
void QwtPlotScaleItem::setColorGroup(const QColorGroup &colorGroup)
{
139
    if ( colorGroup != d_data->colorGroup ) {
pixhawk's avatar
pixhawk committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
        d_data->colorGroup = colorGroup;
        itemChanged();
    }
}

/*!
   \return color group
   \sa setColorGroup()
*/
QColorGroup QwtPlotScaleItem::colorGroup() const
{
    return d_data->colorGroup;
}

#else

/*!
   Set the palette
   \sa QwtAbstractScaleDraw::draw(), palette()
*/
void QwtPlotScaleItem::setPalette(const QPalette &palette)
{
162
    if ( palette != d_data->palette ) {
pixhawk's avatar
pixhawk committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
        d_data->palette = palette;
        itemChanged();
    }
}

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

#endif

/*!
   Change the tick label font
   \sa font
*/
void QwtPlotScaleItem::setFont(const QFont &font)
{
185
    if ( font != d_data->font ) {
pixhawk's avatar
pixhawk committed
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
        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 axisId axis index
  \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()
*/
212
void QwtPlotScaleItem::setScaleDraw(QwtScaleDraw *scaleDraw)
pixhawk's avatar
pixhawk committed
213 214 215 216 217 218 219 220 221 222
{
    if ( scaleDraw == NULL )
        return;

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

    d_data->scaleDraw = scaleDraw;

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

    itemChanged();
}

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

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

/*!
   Change the position of the scale
251

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

   The border distance is set to -1.

   \sa position(), setAlignment()
*/
void QwtPlotScaleItem::setPosition(double pos)
{
261
    if ( d_data->position != pos ) {
pixhawk's avatar
pixhawk committed
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
        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

280 281
   If distance is >= 0 the scale will be aligned to a
   border of the contents rect of the canvas. If
pixhawk's avatar
pixhawk committed
282 283 284 285 286 287
   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().

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

   \sa setPosition(), borderDistance()
*/
void QwtPlotScaleItem::setBorderDistance(int distance)
{
    if ( distance < 0 )
        distance = -1;

298
    if ( distance != d_data->borderDistance ) {
pixhawk's avatar
pixhawk committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
        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

316
   The alignment sets the orientation of the scale and the position of
pixhawk's avatar
pixhawk committed
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
   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()
*/
void QwtPlotScaleItem::setAlignment(QwtScaleDraw::Alignment alignment)
{
    QwtScaleDraw *sd = d_data->scaleDraw;
332
    if ( sd->alignment() != alignment ) {
pixhawk's avatar
pixhawk committed
333 334 335 336 337 338 339 340
        sd->setAlignment(alignment);
        itemChanged();
    }
}

/*!
  \brief Draw the scale
*/
341 342 343
void QwtPlotScaleItem::draw(QPainter *painter,
                            const QwtScaleMap &xMap, const QwtScaleMap &yMap,
                            const QRect &canvasRect) const
pixhawk's avatar
pixhawk committed
344
{
345
    if ( canvasRect != d_data->canvasRectCache ) {
pixhawk's avatar
pixhawk committed
346 347 348 349 350 351 352 353 354 355 356 357 358
        QwtPlotScaleItem* that = (QwtPlotScaleItem*)this;
        that->updateBorders();
    }

    QPen pen = painter->pen();
    pen.setStyle(Qt::SolidLine);
    painter->setPen(pen);

    int pw = painter->pen().width();
    if ( pw == 0 )
        pw = 1;

    QwtScaleDraw *sd = d_data->scaleDraw;
359
    if ( sd->orientation() == Qt::Horizontal ) {
pixhawk's avatar
pixhawk committed
360
        int y;
361
        if ( d_data->borderDistance >= 0 ) {
pixhawk's avatar
pixhawk committed
362 363
            if ( sd->alignment() == QwtScaleDraw::BottomScale )
                y = canvasRect.top() + d_data->borderDistance;
364
            else {
pixhawk's avatar
pixhawk committed
365 366 367
                y = canvasRect.bottom() - d_data->borderDistance - pw + 1;
            }

368
        } else {
pixhawk's avatar
pixhawk committed
369 370 371 372 373 374 375 376 377
            y = yMap.transform(d_data->position);
        }

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

        sd->move(canvasRect.left(), y);
        sd->setLength(canvasRect.width() - 1);
        sd->setTransformation(xMap.transformation()->copy());
378
    } else { // == Qt::Vertical
pixhawk's avatar
pixhawk committed
379
        int x;
380
        if ( d_data->borderDistance >= 0 ) {
pixhawk's avatar
pixhawk committed
381 382
            if ( sd->alignment() == QwtScaleDraw::RightScale )
                x = canvasRect.left() + d_data->borderDistance;
383
            else {
pixhawk's avatar
pixhawk committed
384 385
                x = canvasRect.right() - d_data->borderDistance - pw + 1;
            }
386
        } else {
pixhawk's avatar
pixhawk committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
            x = xMap.transform(d_data->position);
        }
        if ( x < canvasRect.left() || x > canvasRect.right() )
            return;

        sd->move(x, canvasRect.top());
        sd->setLength(canvasRect.height() - 1);
        sd->setTransformation(yMap.transformation()->copy());
    }

    painter->setFont(d_data->font);

#if QT_VERSION < 0x040000
    sd->draw(painter, d_data->colorGroup);
#else
    sd->draw(painter, d_data->palette);
#endif
404

pixhawk's avatar
pixhawk committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
}

/*!
   \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()
*/

void QwtPlotScaleItem::updateScaleDiv(const QwtScaleDiv& xScaleDiv,
420
                                      const QwtScaleDiv& yScaleDiv)
pixhawk's avatar
pixhawk committed
421 422
{
    QwtScaleDraw *sd = d_data->scaleDraw;
423
    if ( d_data->scaleDivFromAxis && sd ) {
pixhawk's avatar
pixhawk committed
424 425 426 427 428 429 430 431 432 433 434
        sd->setScaleDiv(
            sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv);
        updateBorders();
    }
}

void QwtPlotScaleItem::updateBorders()
{
    const QwtPlot *plt = plot();
    if ( plt == NULL || !d_data->scaleDivFromAxis )
        return;
435

pixhawk's avatar
pixhawk committed
436 437 438 439
    const QRect r = plt->canvas()->contentsRect();
    d_data->canvasRectCache = r;

    QwtDoubleInterval interval;
440
    if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) {
pixhawk's avatar
pixhawk committed
441 442 443
        const QwtScaleMap map = plt->canvasMap(xAxis());
        interval.setMinValue(map.invTransform(r.left()));
        interval.setMaxValue(map.invTransform(r.right()));
444
    } else {
pixhawk's avatar
pixhawk committed
445 446 447 448 449 450 451 452 453
        const QwtScaleMap map = plt->canvasMap(yAxis());
        interval.setMinValue(map.invTransform(r.bottom()));
        interval.setMaxValue(map.invTransform(r.top()));
    }

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