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.
494 lines
15 KiB
494 lines
15 KiB
15 years ago
|
/* -*- 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
|
||
|
*****************************************************************************/
|
||
|
|
||
|
// vim: expandtab
|
||
|
|
||
|
#include <qpainter.h>
|
||
|
#if QT_VERSION < 0x040000
|
||
|
#include <qpaintdevicemetrics.h>
|
||
|
#else
|
||
|
#include <qpaintengine.h>
|
||
|
#endif
|
||
|
#include "qwt_painter.h"
|
||
|
#include "qwt_legend_item.h"
|
||
|
#include "qwt_plot.h"
|
||
|
#include "qwt_plot_canvas.h"
|
||
|
#include "qwt_plot_layout.h"
|
||
|
#include "qwt_legend.h"
|
||
|
#include "qwt_dyngrid_layout.h"
|
||
|
#include "qwt_scale_widget.h"
|
||
|
#include "qwt_scale_engine.h"
|
||
|
#include "qwt_text.h"
|
||
|
#include "qwt_text_label.h"
|
||
|
#include "qwt_math.h"
|
||
|
|
||
|
/*!
|
||
|
\brief Print the plot to a \c QPaintDevice (\c QPrinter)
|
||
|
This function prints the contents of a QwtPlot instance to
|
||
|
\c QPaintDevice object. The size is derived from its device
|
||
|
metrics.
|
||
|
|
||
|
\param paintDev device to paint on, often a printer
|
||
|
\param pfilter print filter
|
||
|
\sa QwtPlot::print
|
||
|
\sa QwtPlotPrintFilter
|
||
|
*/
|
||
|
|
||
|
void QwtPlot::print(QPaintDevice &paintDev,
|
||
14 years ago
|
const QwtPlotPrintFilter &pfilter) const
|
||
15 years ago
|
{
|
||
|
#if QT_VERSION < 0x040000
|
||
|
QPaintDeviceMetrics mpr(&paintDev);
|
||
|
int w = mpr.width();
|
||
|
int h = mpr.height();
|
||
|
#else
|
||
|
int w = paintDev.width();
|
||
|
int h = paintDev.height();
|
||
|
#endif
|
||
|
|
||
|
QRect rect(0, 0, w, h);
|
||
|
double aspect = double(rect.width())/double(rect.height());
|
||
|
if ((aspect < 1.0))
|
||
|
rect.setHeight(int(aspect*rect.width()));
|
||
|
|
||
|
QPainter p(&paintDev);
|
||
|
print(&p, rect, pfilter);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Paint the plot into a given rectangle.
|
||
|
Paint the contents of a QwtPlot instance into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param plotRect Bounding rectangle
|
||
|
\param pfilter Print filter
|
||
|
\sa QwtPlotPrintFilter
|
||
|
*/
|
||
|
void QwtPlot::print(QPainter *painter, const QRect &plotRect,
|
||
14 years ago
|
const QwtPlotPrintFilter &pfilter) const
|
||
15 years ago
|
{
|
||
|
int axisId;
|
||
|
|
||
|
if ( painter == 0 || !painter->isActive() ||
|
||
|
!plotRect.isValid() || size().isNull() )
|
||
14 years ago
|
return;
|
||
15 years ago
|
|
||
|
painter->save();
|
||
|
#if 1
|
||
|
/*
|
||
|
PDF: In Qt4 ( <= 4.3.2 ) the scales are painted in gray instead of
|
||
|
black. See http://trolltech.com/developer/task-tracker/index_html?id=184671&method=entry
|
||
|
The dummy lines below work around the problem.
|
||
|
*/
|
||
|
const QPen pen = painter->pen();
|
||
|
painter->setPen(QPen(Qt::black, 1));
|
||
|
painter->setPen(pen);
|
||
|
#endif
|
||
|
|
||
|
// All paint operations need to be scaled according to
|
||
14 years ago
|
// the paint device metrics.
|
||
15 years ago
|
|
||
|
QwtPainter::setMetricsMap(this, painter->device());
|
||
|
const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
|
||
|
|
||
|
// It is almost impossible to integrate into the Qt layout
|
||
|
// framework, when using different fonts for printing
|
||
|
// and screen. To avoid writing different and Qt unconform
|
||
14 years ago
|
// layout engines we change the widget attributes, print and
|
||
15 years ago
|
// reset the widget attributes again. This way we produce a lot of
|
||
|
// useless layout events ...
|
||
|
|
||
|
pfilter.apply((QwtPlot *)this);
|
||
|
|
||
|
int baseLineDists[QwtPlot::axisCnt];
|
||
14 years ago
|
if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ) {
|
||
|
for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
|
||
15 years ago
|
QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
|
||
14 years ago
|
if ( scaleWidget ) {
|
||
15 years ago
|
baseLineDists[axisId] = scaleWidget->margin();
|
||
|
scaleWidget->setMargin(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Calculate the layout for the print.
|
||
|
|
||
14 years ago
|
int layoutOptions = QwtPlotLayout::IgnoreScrollbars
|
||
|
| QwtPlotLayout::IgnoreFrames;
|
||
15 years ago
|
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
|
||
|
layoutOptions |= QwtPlotLayout::IgnoreMargin;
|
||
|
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
|
||
|
layoutOptions |= QwtPlotLayout::IgnoreLegend;
|
||
|
|
||
14 years ago
|
((QwtPlot *)this)->plotLayout()->activate(this,
|
||
|
QwtPainter::metricsMap().deviceToLayout(plotRect),
|
||
|
layoutOptions);
|
||
15 years ago
|
|
||
|
if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
|
||
14 years ago
|
&& (!titleLabel()->text().isEmpty())) {
|
||
15 years ago
|
printTitle(painter, plotLayout()->titleRect());
|
||
|
}
|
||
|
|
||
|
if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
|
||
14 years ago
|
&& legend() && !legend()->isEmpty() ) {
|
||
15 years ago
|
printLegend(painter, plotLayout()->legendRect());
|
||
|
}
|
||
|
|
||
14 years ago
|
for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
|
||
15 years ago
|
QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
|
||
14 years ago
|
if (scaleWidget) {
|
||
15 years ago
|
int baseDist = scaleWidget->margin();
|
||
|
|
||
|
int startDist, endDist;
|
||
|
scaleWidget->getBorderDistHint(startDist, endDist);
|
||
|
|
||
|
printScale(painter, axisId, startDist, endDist,
|
||
14 years ago
|
baseDist, plotLayout()->scaleRect(axisId));
|
||
15 years ago
|
}
|
||
|
}
|
||
|
|
||
|
QRect canvasRect = plotLayout()->canvasRect();
|
||
|
|
||
14 years ago
|
/*
|
||
15 years ago
|
The border of the bounding rect needs to ba scaled to
|
||
14 years ago
|
layout coordinates, so that it is aligned to the axes
|
||
15 years ago
|
*/
|
||
|
QRect boundingRect( canvasRect.left() - 1, canvasRect.top() - 1,
|
||
14 years ago
|
canvasRect.width() + 2, canvasRect.height() + 2);
|
||
15 years ago
|
boundingRect = metricsMap.layoutToDevice(boundingRect);
|
||
|
boundingRect.setWidth(boundingRect.width() - 1);
|
||
|
boundingRect.setHeight(boundingRect.height() - 1);
|
||
|
|
||
|
canvasRect = metricsMap.layoutToDevice(canvasRect);
|
||
14 years ago
|
|
||
15 years ago
|
// When using QwtPainter all sizes where computed in pixel
|
||
|
// coordinates and scaled by QwtPainter later. This limits
|
||
|
// the precision to screen resolution. A better solution
|
||
|
// is to scale the maps and print in unlimited resolution.
|
||
|
|
||
|
QwtScaleMap map[axisCnt];
|
||
14 years ago
|
for (axisId = 0; axisId < axisCnt; axisId++) {
|
||
15 years ago
|
map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());
|
||
|
|
||
|
const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
|
||
|
map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());
|
||
|
|
||
|
double from, to;
|
||
14 years ago
|
if ( axisEnabled(axisId) ) {
|
||
15 years ago
|
const int sDist = axisWidget(axisId)->startBorderDist();
|
||
|
const int eDist = axisWidget(axisId)->endBorderDist();
|
||
|
const QRect &scaleRect = plotLayout()->scaleRect(axisId);
|
||
|
|
||
14 years ago
|
if ( axisId == xTop || axisId == xBottom ) {
|
||
15 years ago
|
from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
|
||
|
to = metricsMap.layoutToDeviceX(scaleRect.right() + 1 - eDist);
|
||
14 years ago
|
} else {
|
||
15 years ago
|
from = metricsMap.layoutToDeviceY(scaleRect.bottom() + 1 - eDist );
|
||
|
to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
|
||
|
}
|
||
14 years ago
|
} else {
|
||
15 years ago
|
int margin = plotLayout()->canvasMargin(axisId);
|
||
14 years ago
|
if ( axisId == yLeft || axisId == yRight ) {
|
||
15 years ago
|
margin = metricsMap.layoutToDeviceY(margin);
|
||
|
from = canvasRect.bottom() - margin;
|
||
|
to = canvasRect.top() + margin;
|
||
14 years ago
|
} else {
|
||
15 years ago
|
margin = metricsMap.layoutToDeviceX(margin);
|
||
|
from = canvasRect.left() + margin;
|
||
|
to = canvasRect.right() - margin;
|
||
|
}
|
||
|
}
|
||
|
map[axisId].setPaintXInterval(from, to);
|
||
|
}
|
||
|
|
||
14 years ago
|
// The canvas maps are already scaled.
|
||
15 years ago
|
QwtPainter::setMetricsMap(painter->device(), painter->device());
|
||
|
printCanvas(painter, boundingRect, canvasRect, map, pfilter);
|
||
|
QwtPainter::resetMetricsMap();
|
||
|
|
||
|
((QwtPlot *)this)->plotLayout()->invalidate();
|
||
|
|
||
|
// reset all widgets with their original attributes.
|
||
14 years ago
|
if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ) {
|
||
15 years ago
|
// restore the previous base line dists
|
||
|
|
||
14 years ago
|
for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ ) {
|
||
15 years ago
|
QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
|
||
|
if ( scaleWidget )
|
||
|
scaleWidget->setMargin(baseLineDists[axisId]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pfilter.reset((QwtPlot *)this);
|
||
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Print the title into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param rect Bounding rectangle
|
||
|
*/
|
||
|
|
||
|
void QwtPlot::printTitle(QPainter *painter, const QRect &rect) const
|
||
|
{
|
||
|
painter->setFont(titleLabel()->font());
|
||
|
|
||
14 years ago
|
const QColor color =
|
||
15 years ago
|
#if QT_VERSION < 0x040000
|
||
|
titleLabel()->palette().color(
|
||
|
QPalette::Active, QColorGroup::Text);
|
||
|
#else
|
||
|
titleLabel()->palette().color(
|
||
|
QPalette::Active, QPalette::Text);
|
||
|
#endif
|
||
|
|
||
|
painter->setPen(color);
|
||
|
titleLabel()->text().draw(painter, rect);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Print the legend into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param rect Bounding rectangle
|
||
|
*/
|
||
|
|
||
|
void QwtPlot::printLegend(QPainter *painter, const QRect &rect) const
|
||
|
{
|
||
|
if ( !legend() || legend()->isEmpty() )
|
||
|
return;
|
||
|
|
||
|
QLayout *l = legend()->contentsWidget()->layout();
|
||
|
if ( l == 0 || !l->inherits("QwtDynGridLayout") )
|
||
|
return;
|
||
|
|
||
|
QwtDynGridLayout *legendLayout = (QwtDynGridLayout *)l;
|
||
|
|
||
|
uint numCols = legendLayout->columnsForWidth(rect.width());
|
||
|
#if QT_VERSION < 0x040000
|
||
14 years ago
|
QValueList<QRect> itemRects =
|
||
15 years ago
|
legendLayout->layoutItems(rect, numCols);
|
||
|
#else
|
||
14 years ago
|
QList<QRect> itemRects =
|
||
15 years ago
|
legendLayout->layoutItems(rect, numCols);
|
||
|
#endif
|
||
|
|
||
|
int index = 0;
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
QLayoutIterator layoutIterator = legendLayout->iterator();
|
||
14 years ago
|
for ( QLayoutItem *item = layoutIterator.current();
|
||
|
item != 0; item = ++layoutIterator) {
|
||
15 years ago
|
#else
|
||
14 years ago
|
for ( int i = 0; i < legendLayout->count(); i++ ) {
|
||
15 years ago
|
QLayoutItem *item = legendLayout->itemAt(i);
|
||
|
#endif
|
||
|
QWidget *w = item->widget();
|
||
14 years ago
|
if ( w ) {
|
||
15 years ago
|
painter->save();
|
||
|
painter->setClipping(true);
|
||
|
QwtPainter::setClipRect(painter, itemRects[index]);
|
||
|
|
||
|
printLegendItem(painter, w, itemRects[index]);
|
||
|
|
||
|
index++;
|
||
|
painter->restore();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Print the legend item into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param w Widget representing a legend item
|
||
|
\param rect Bounding rectangle
|
||
|
*/
|
||
|
|
||
14 years ago
|
void QwtPlot::printLegendItem(QPainter *painter,
|
||
|
const QWidget *w, const QRect &rect) const
|
||
15 years ago
|
{
|
||
14 years ago
|
if ( w->inherits("QwtLegendItem") ) {
|
||
15 years ago
|
QwtLegendItem *item = (QwtLegendItem *)w;
|
||
|
|
||
|
painter->setFont(item->font());
|
||
|
item->drawItem(painter, rect);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Paint a scale into a given rectangle.
|
||
|
Paint the scale into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param axisId Axis
|
||
|
\param startDist Start border distance
|
||
|
\param endDist End border distance
|
||
|
\param baseDist Base distance
|
||
|
\param rect Bounding rectangle
|
||
|
*/
|
||
|
|
||
|
void QwtPlot::printScale(QPainter *painter,
|
||
14 years ago
|
int axisId, int startDist, int endDist, int baseDist,
|
||
|
const QRect &rect) const
|
||
15 years ago
|
{
|
||
|
if (!axisEnabled(axisId))
|
||
|
return;
|
||
|
|
||
|
const QwtScaleWidget *scaleWidget = axisWidget(axisId);
|
||
14 years ago
|
if ( scaleWidget->isColorBarEnabled()
|
||
|
&& scaleWidget->colorBarWidth() > 0) {
|
||
15 years ago
|
const QwtMetricsMap map = QwtPainter::metricsMap();
|
||
|
|
||
|
QRect r = map.layoutToScreen(rect);
|
||
|
r.setWidth(r.width() - 1);
|
||
|
r.setHeight(r.height() - 1);
|
||
|
|
||
|
scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
|
||
|
|
||
|
const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
|
||
|
if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
|
||
|
baseDist += map.screenToLayoutY(off);
|
||
|
else
|
||
|
baseDist += map.screenToLayoutX(off);
|
||
|
}
|
||
|
|
||
|
QwtScaleDraw::Alignment align;
|
||
|
int x, y, w;
|
||
|
|
||
14 years ago
|
switch(axisId) {
|
||
|
case yLeft: {
|
||
|
x = rect.right() - baseDist;
|
||
|
y = rect.y() + startDist;
|
||
|
w = rect.height() - startDist - endDist;
|
||
|
align = QwtScaleDraw::LeftScale;
|
||
|
break;
|
||
|
}
|
||
|
case yRight: {
|
||
|
x = rect.left() + baseDist;
|
||
|
y = rect.y() + startDist;
|
||
|
w = rect.height() - startDist - endDist;
|
||
|
align = QwtScaleDraw::RightScale;
|
||
|
break;
|
||
|
}
|
||
|
case xTop: {
|
||
|
x = rect.left() + startDist;
|
||
|
y = rect.bottom() - baseDist;
|
||
|
w = rect.width() - startDist - endDist;
|
||
|
align = QwtScaleDraw::TopScale;
|
||
|
break;
|
||
|
}
|
||
|
case xBottom: {
|
||
|
x = rect.left() + startDist;
|
||
|
y = rect.top() + baseDist;
|
||
|
w = rect.width() - startDist - endDist;
|
||
|
align = QwtScaleDraw::BottomScale;
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
return;
|
||
15 years ago
|
}
|
||
|
|
||
|
scaleWidget->drawTitle(painter, align, rect);
|
||
|
|
||
|
painter->save();
|
||
|
painter->setFont(scaleWidget->font());
|
||
|
|
||
|
QPen pen = painter->pen();
|
||
|
pen.setWidth(scaleWidget->penWidth());
|
||
|
painter->setPen(pen);
|
||
|
|
||
|
QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
|
||
|
const QPoint sdPos = sd->pos();
|
||
|
const int sdLength = sd->length();
|
||
|
|
||
|
sd->move(x, y);
|
||
|
sd->setLength(w);
|
||
|
|
||
|
#if QT_VERSION < 0x040000
|
||
|
sd->draw(painter, scaleWidget->palette().active());
|
||
|
#else
|
||
|
QPalette palette = scaleWidget->palette();
|
||
|
palette.setCurrentColorGroup(QPalette::Active);
|
||
|
sd->draw(painter, palette);
|
||
|
#endif
|
||
|
// reset previous values
|
||
14 years ago
|
sd->move(sdPos);
|
||
|
sd->setLength(sdLength);
|
||
15 years ago
|
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Print the canvas into a given rectangle.
|
||
|
|
||
|
\param painter Painter
|
||
|
\param map Maps mapping between plot and paint device coordinates
|
||
|
\param boundingRect Bounding rectangle
|
||
|
\param canvasRect Canvas rectangle
|
||
|
\param pfilter Print filter
|
||
|
\sa QwtPlotPrintFilter
|
||
|
*/
|
||
|
|
||
14 years ago
|
void QwtPlot::printCanvas(QPainter *painter,
|
||
|
const QRect &boundingRect, const QRect &canvasRect,
|
||
|
const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
|
||
15 years ago
|
{
|
||
14 years ago
|
if ( pfilter.options() & QwtPlotPrintFilter::PrintBackground ) {
|
||
15 years ago
|
QBrush bgBrush;
|
||
|
#if QT_VERSION >= 0x040000
|
||
14 years ago
|
bgBrush = canvas()->palette().brush(backgroundRole());
|
||
15 years ago
|
#else
|
||
|
QColorGroup::ColorRole role =
|
||
|
QPalette::backgroundRoleFromMode( backgroundMode() );
|
||
|
bgBrush = canvas()->colorGroup().brush( role );
|
||
|
#endif
|
||
|
QRect r = boundingRect;
|
||
14 years ago
|
if ( !(pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales) ) {
|
||
15 years ago
|
r = canvasRect;
|
||
|
#if QT_VERSION >= 0x040000
|
||
|
// Unfortunately the paint engines do no always the same
|
||
|
const QPaintEngine *pe = painter->paintEngine();
|
||
14 years ago
|
if ( pe ) {
|
||
|
switch(painter->paintEngine()->type() ) {
|
||
|
case QPaintEngine::Raster:
|
||
|
case QPaintEngine::X11:
|
||
|
break;
|
||
|
default:
|
||
|
r.setWidth(r.width() - 1);
|
||
|
r.setHeight(r.height() - 1);
|
||
|
break;
|
||
15 years ago
|
}
|
||
|
}
|
||
|
#else
|
||
14 years ago
|
if ( painter->device()->isExtDev() ) {
|
||
15 years ago
|
r.setWidth(r.width() - 1);
|
||
14 years ago
|
r.setHeight(r.height() - 1);
|
||
15 years ago
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
QwtPainter::fillRect(painter, r, bgBrush);
|
||
|
}
|
||
|
|
||
14 years ago
|
if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales ) {
|
||
15 years ago
|
painter->save();
|
||
|
painter->setPen(QPen(Qt::black));
|
||
|
painter->setBrush(QBrush(Qt::NoBrush));
|
||
|
QwtPainter::drawRect(painter, boundingRect);
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
painter->setClipping(true);
|
||
|
QwtPainter::setClipRect(painter, canvasRect);
|
||
|
|
||
|
drawItems(painter, canvasRect, map, pfilter);
|
||
|
}
|