/* -*- 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 #include #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), scaleDraw(new QwtScaleDraw()) { } ~PrivateData() { 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 the scale item is corresponding to the xAxis(), otherwise it corresponds to the yAxis(). \param position x or y position, depending on the corresponding axis. \sa setPosition(), setAlignment() */ QwtPlotScaleItem::QwtPlotScaleItem( QwtScaleDraw::Alignment alignment, const double pos): 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(); } /*! Enable/Disable the synchronization of the scale division with the corresponding axis. \sa isScaleDivFromAxis() */ void QwtPlotScaleItem::setScaleDivFromAxis(bool on) { if ( on != d_data->scaleDivFromAxis ) { d_data->scaleDivFromAxis = on; if ( on ) { const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( *plt->axisScaleDiv(xAxis()), *plt->axisScaleDiv(yAxis()) ); itemChanged(); } } } } /*! \return True, if the synchronization of the scale division with the corresponding axis is enabled. \sa setScaleDiv(), setScaleDivFromAxis() */ bool QwtPlotScaleItem::isScaleDivFromAxis() const { return d_data->scaleDivFromAxis; } #if QT_VERSION < 0x040000 /*! Set the color group \sa QwtAbstractScaleDraw::draw(), colorGroup() */ void QwtPlotScaleItem::setColorGroup(const QColorGroup &colorGroup) { if ( colorGroup != d_data->colorGroup ) { 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) { if ( palette != d_data->palette ) { 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) { if ( font != d_data->font ) { 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() */ void QwtPlotScaleItem::setScaleDraw(QwtScaleDraw *scaleDraw) { if ( scaleDraw == NULL ) return; if ( scaleDraw != d_data->scaleDraw ) delete d_data->scaleDraw; d_data->scaleDraw = scaleDraw; const QwtPlot *plt = plot(); if ( plt ) { updateScaleDiv( *plt->axisScaleDiv(xAxis()), *plt->axisScaleDiv(yAxis()) ); } itemChanged(); } /*! \return Scale draw \sa setScaleDraw() */ const QwtScaleDraw *QwtPlotScaleItem::scaleDraw() const { return d_data->scaleDraw; } /*! \return Scale draw \sa setScaleDraw() */ QwtScaleDraw *QwtPlotScaleItem::scaleDraw() { return d_data->scaleDraw; } /*! Change the position of the scale 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) { if ( d_data->position != pos ) { 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 If distance is >= 0 the scale will be aligned to a border of the contents rect of the canvas. If 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(). \param distance Number of pixels between the canvas border and the backbone of the scale. \sa setPosition(), borderDistance() */ void QwtPlotScaleItem::setBorderDistance(int distance) { if ( distance < 0 ) distance = -1; if ( distance != d_data->borderDistance ) { 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 The alignment sets the orientation of the scale and the position of 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; if ( sd->alignment() != alignment ) { sd->setAlignment(alignment); itemChanged(); } } /*! \brief Draw the scale */ void QwtPlotScaleItem::draw(QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRect &canvasRect) const { if ( canvasRect != d_data->canvasRectCache ) { 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; if ( sd->orientation() == Qt::Horizontal ) { int y; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::BottomScale ) y = canvasRect.top() + d_data->borderDistance; else { y = canvasRect.bottom() - d_data->borderDistance - pw + 1; } } else { 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()); } else { // == Qt::Vertical int x; if ( d_data->borderDistance >= 0 ) { if ( sd->alignment() == QwtScaleDraw::RightScale ) x = canvasRect.left() + d_data->borderDistance; else { x = canvasRect.right() - d_data->borderDistance - pw + 1; } } else { 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 } /*! \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, const QwtScaleDiv& yScaleDiv) { QwtScaleDraw *sd = d_data->scaleDraw; if ( d_data->scaleDivFromAxis && sd ) { sd->setScaleDiv( sd->orientation() == Qt::Horizontal ? xScaleDiv : yScaleDiv); updateBorders(); } } void QwtPlotScaleItem::updateBorders() { const QwtPlot *plt = plot(); if ( plt == NULL || !d_data->scaleDivFromAxis ) return; const QRect r = plt->canvas()->contentsRect(); d_data->canvasRectCache = r; QwtDoubleInterval interval; if ( d_data->scaleDraw->orientation() == Qt::Horizontal ) { const QwtScaleMap map = plt->canvasMap(xAxis()); interval.setMinValue(map.invTransform(r.left())); interval.setMaxValue(map.invTransform(r.right())); } else { 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); }