# qwt_plot_print.cpp

    00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
    00002  * Qwt Widget Library
    00003  * Copyright (C) 1997   Josef Wilgen
    00004  * Copyright (C) 2002   Uwe Rathmann
    00005  *
    00006  * This library is free software; you can redistribute it and/or
    00007  * modify it under the terms of the Qwt License, Version 1.0
    00008  *****************************************************************************/
    00009
    00010 // vim: expandtab
    00011
    00012 #include <qpainter.h>
    00013 #if QT_VERSION < 0x040000
    00014 #include <qpaintdevicemetrics.h>
    00015 #else
    00016 #include <qpaintengine.h>
    00017 #endif
    00018 #include "qwt_painter.h"
    00019 #include "qwt_legend_item.h"
    00020 #include "qwt_plot.h"
    00021 #include "qwt_plot_canvas.h"
    00022 #include "qwt_plot_layout.h"
    00023 #include "qwt_legend.h"
    00024 #include "qwt_dyngrid_layout.h"
    00025 #include "qwt_scale_widget.h"
    00026 #include "qwt_scale_engine.h"
    00027 #include "qwt_text.h"
    00028 #include "qwt_text_label.h"
    00029 #include "qwt_math.h"
    00030
    00043 void QwtPlot::print(QPaintDevice &paintDev,
    00044    const QwtPlotPrintFilter &pfilter) const
    00045 {
    00046 #if QT_VERSION < 0x040000
    00047     QPaintDeviceMetrics mpr(&paintDev);
    00048     int w = mpr.width();
    00049     int h = mpr.height();
    00050 #else
    00051     int w = paintDev.width();
    00052     int h = paintDev.height();
    00053 #endif
    00054
    00055     QRect rect(0, 0, w, h);
    00056     double aspect = double(rect.width())/double(rect.height());
    00057     if ((aspect < 1.0))
    00058         rect.setHeight(int(aspect*rect.width()));
    00059
    00060     QPainter p(&paintDev);
    00061     print(&p, rect, pfilter);
    00062 }
    00063
    00073 void QwtPlot::print(QPainter *painter, const QRect &plotRect,
    00074         const QwtPlotPrintFilter &pfilter) const
    00075 {
    00076     int axisId;
    00077
    00078     if ( painter == 0 || !painter->isActive() ||
    00079             !plotRect.isValid() || size().isNull() )
    00080        return;
    00081
    00082     painter->save();
    00083 #if 1
    00084     /*
    00085       PDF: In Qt4 ( <= 4.3.2 ) the scales are painted in gray instead of
    00086       black. See http://trolltech.com/developer/task-tracker/index_html?id=184671&method=entry
    00087       The dummy lines below work around the problem.
    00088      */
    00089     const QPen pen = painter->pen();
    00090     painter->setPen(QPen(Qt::black, 1));
    00091     painter->setPen(pen);
    00092 #endif
    00093
    00094     // All paint operations need to be scaled according to
    00095     // the paint device metrics.
    00096
    00097     QwtPainter::setMetricsMap(this, painter->device());
    00098     const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
    00099
    00100     // It is almost impossible to integrate into the Qt layout
    00101     // framework, when using different fonts for printing
    00102     // and screen. To avoid writing different and Qt unconform
    00103     // layout engines we change the widget attributes, print and
    00104     // reset the widget attributes again. This way we produce a lot of
    00105     // useless layout events ...
    00106
    00107     pfilter.apply((QwtPlot *)this);
    00108
    00109     int baseLineDists[QwtPlot::axisCnt];
    00110     if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
    00111     {
    00112         for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    00113         {
    00114             QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
    00115             if ( scaleWidget )
    00116             {
    00117                 baseLineDists[axisId] = scaleWidget->margin();
    00118                 scaleWidget->setMargin(0);
    00119             }
    00120         }
    00121     }
    00122     // Calculate the layout for the print.
    00123
    00124     int layoutOptions = QwtPlotLayout::IgnoreScrollbars
    00125         | QwtPlotLayout::IgnoreFrames;
    00126     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
    00127         layoutOptions |= QwtPlotLayout::IgnoreMargin;
    00128     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
    00129         layoutOptions |= QwtPlotLayout::IgnoreLegend;
    00130
    00131     ((QwtPlot *)this)->plotLayout()->activate(this,
    00132         QwtPainter::metricsMap().deviceToLayout(plotRect),
    00133         layoutOptions);
    00134
    00135     if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
    00136         && (!titleLabel()->text().isEmpty()))
    00137     {
    00138         printTitle(painter, plotLayout()->titleRect());
    00139     }
    00140
    00141     if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
    00142         && legend() && !legend()->isEmpty() )
    00143     {
    00144         printLegend(painter, plotLayout()->legendRect());
    00145     }
    00146
    00147     for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    00148     {
    00149         QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
    00150         if (scaleWidget)
    00151         {
    00152             int baseDist = scaleWidget->margin();
    00153
    00154             int startDist, endDist;
    00155             scaleWidget->getBorderDistHint(startDist, endDist);
    00156
    00157             printScale(painter, axisId, startDist, endDist,
    00158                 baseDist, plotLayout()->scaleRect(axisId));
    00159         }
    00160     }
    00161
    00162     QRect canvasRect = plotLayout()->canvasRect();
    00163
    00164     /*
    00165        The border of the bounding rect needs to ba scaled to
    00166        layout coordinates, so that it is aligned to the axes
    00167      */
    00168     QRect boundingRect( canvasRect.left() - 1, canvasRect.top() - 1,
    00169         canvasRect.width() + 2, canvasRect.height() + 2);
    00170     boundingRect = metricsMap.layoutToDevice(boundingRect);
    00171     boundingRect.setWidth(boundingRect.width() - 1);
    00172     boundingRect.setHeight(boundingRect.height() - 1);
    00173
    00174     canvasRect = metricsMap.layoutToDevice(canvasRect);
    00175
    00176     // When using QwtPainter all sizes where computed in pixel
    00177     // coordinates and scaled by QwtPainter later. This limits
    00178     // the precision to screen resolution. A better solution
    00179     // is to scale the maps and print in unlimited resolution.
    00180
    00181     QwtScaleMap map[axisCnt];
    00182     for (axisId = 0; axisId < axisCnt; axisId++)
    00183     {
    00184         map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());
    00185
    00186         const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
    00187         map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());
    00188
    00189         double from, to;
    00190         if ( axisEnabled(axisId) )
    00191         {
    00192             const int sDist = axisWidget(axisId)->startBorderDist();
    00193             const int eDist = axisWidget(axisId)->endBorderDist();
    00194             const QRect &scaleRect = plotLayout()->scaleRect(axisId);
    00195
    00196             if ( axisId == xTop || axisId == xBottom )
    00197             {
    00198                 from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
    00199                 to = metricsMap.layoutToDeviceX(scaleRect.right() + 1 - eDist);
    00200             }
    00201             else
    00202             {
    00203                 from = metricsMap.layoutToDeviceY(scaleRect.bottom() + 1 - eDist );
    00204                 to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
    00205             }
    00206         }
    00207         else
    00208         {
    00209             const int margin = plotLayout()->canvasMargin(axisId);
    00210             if ( axisId == yLeft || axisId == yRight )
    00211             {
    00212                 from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin);
    00213                 to = metricsMap.layoutToDeviceX(canvasRect.top() + margin);
    00214             }
    00215             else
    00216             {
    00217                 from = metricsMap.layoutToDeviceY(canvasRect.left() + margin);
    00218                 to = metricsMap.layoutToDeviceY(canvasRect.right() - margin);
    00219             }
    00220         }
    00221         map[axisId].setPaintXInterval(from, to);
    00222     }
    00223
    00224     // The canvas maps are already scaled.
    00225     QwtPainter::setMetricsMap(painter->device(), painter->device());
    00226     printCanvas(painter, boundingRect, canvasRect, map, pfilter);
    00227     QwtPainter::resetMetricsMap();
    00228
    00229     ((QwtPlot *)this)->plotLayout()->invalidate();
    00230
    00231     // reset all widgets with their original attributes.
    00232     if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
    00233     {
    00234         // restore the previous base line dists
    00235
    00236         for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    00237         {
    00238             QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
    00239             if ( scaleWidget  )
    00240                 scaleWidget->setMargin(baseLineDists[axisId]);
    00241         }
    00242     }
    00243
    00244     pfilter.reset((QwtPlot *)this);
    00245
    00246     painter->restore();
    00247 }
    00248
    00256 void QwtPlot::printTitle(QPainter *painter, const QRect &rect) const
    00257 {
    00258     painter->setFont(titleLabel()->font());
    00259
    00260     const QColor color =
    00261 #if QT_VERSION < 0x040000
    00262         titleLabel()->palette().color(
    00263             QPalette::Active, QColorGroup::Text);
    00264 #else
    00265         titleLabel()->palette().color(
    00266             QPalette::Active, QPalette::Text);
    00267 #endif
    00268
    00269     painter->setPen(color);
    00270     titleLabel()->text().draw(painter, rect);
    00271 }
    00272
    00280 void QwtPlot::printLegend(QPainter *painter, const QRect &rect) const
    00281 {
    00282     if ( !legend() || legend()->isEmpty() )
    00283         return;
    00284
    00285     QLayout *l = legend()->contentsWidget()->layout();
    00286     if ( l == 0 || !l->inherits("QwtDynGridLayout") )
    00287         return;
    00288
    00289     QwtDynGridLayout *legendLayout = (QwtDynGridLayout *)l;
    00290
    00291     uint numCols = legendLayout->columnsForWidth(rect.width());
    00292 #if QT_VERSION < 0x040000
    00293     QValueList<QRect> itemRects =
    00294         legendLayout->layoutItems(rect, numCols);
    00295 #else
    00296     QList<QRect> itemRects =
    00297         legendLayout->layoutItems(rect, numCols);
    00298 #endif
    00299
    00300     int index = 0;
    00301
    00302 #if QT_VERSION < 0x040000
    00303     QLayoutIterator layoutIterator = legendLayout->iterator();
    00304     for ( QLayoutItem *item = layoutIterator.current();
    00305         item != 0; item = ++layoutIterator)
    00306     {
    00307 #else
    00308     for ( int i = 0; i < legendLayout->count(); i++ )
    00309     {
    00310         QLayoutItem *item = legendLayout->itemAt(i);
    00311 #endif
    00312         QWidget *w = item->widget();
    00313         if ( w )
    00314         {
    00315             painter->save();
    00316             painter->setClipping(true);
    00317             QwtPainter::setClipRect(painter, itemRects[index]);
    00318
    00319             printLegendItem(painter, w, itemRects[index]);
    00320
    00321             index++;
    00322             painter->restore();
    00323         }
    00324     }
    00325 }
    00326
    00335 void QwtPlot::printLegendItem(QPainter *painter,
    00336     const QWidget *w, const QRect &rect) const
    00337 {
    00338     if ( w->inherits("QwtLegendItem") )
    00339     {
    00340         QwtLegendItem *item = (QwtLegendItem *)w;
    00341
    00342         painter->setFont(item->font());
    00343         item->drawItem(painter, rect);
    00344     }
    00345 }
    00346
    00359 void QwtPlot::printScale(QPainter *painter,
    00360     int axisId, int startDist, int endDist, int baseDist,
    00361     const QRect &rect) const
    00362 {
    00363     if (!axisEnabled(axisId))
    00364         return;
    00365
    00366     const QwtScaleWidget *scaleWidget = axisWidget(axisId);
    00367     if ( scaleWidget->isColorBarEnabled()
    00368         && scaleWidget->colorBarWidth() > 0)
    00369     {
    00370         const QwtMetricsMap map = QwtPainter::metricsMap();
    00371
    00372         QRect r = map.layoutToScreen(rect);
    00373         r.setWidth(r.width() - 1);
    00374         r.setHeight(r.height() - 1);
    00375
    00376         scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
    00377
    00378         const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
    00379         if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
    00380             baseDist += map.screenToLayoutY(off);
    00381         else
    00382             baseDist += map.screenToLayoutX(off);
    00383     }
    00384
    00385     QwtScaleDraw::Alignment align;
    00386     int x, y, w;
    00387
    00388     switch(axisId)
    00389     {
    00390         case yLeft:
    00391         {
    00392             x = rect.right() - baseDist;
    00393             y = rect.y() + startDist;
    00394             w = rect.height() - startDist - endDist;
    00395             align = QwtScaleDraw::LeftScale;
    00396             break;
    00397         }
    00398         case yRight:
    00399         {
    00400             x = rect.left() + baseDist;
    00401             y = rect.y() + startDist;
    00402             w = rect.height() - startDist - endDist;
    00403             align = QwtScaleDraw::RightScale;
    00404             break;
    00405         }
    00406         case xTop:
    00407         {
    00408             x = rect.left() + startDist;
    00409             y = rect.bottom() - baseDist;
    00410             w = rect.width() - startDist - endDist;
    00411             align = QwtScaleDraw::TopScale;
    00412             break;
    00413         }
    00414         case xBottom:
    00415         {
    00416             x = rect.left() + startDist;
    00417             y = rect.top() + baseDist;
    00418             w = rect.width() - startDist - endDist;
    00419             align = QwtScaleDraw::BottomScale;
    00420             break;
    00421         }
    00422         default:
    00423             return;
    00424     }
    00425
    00426     scaleWidget->drawTitle(painter, align, rect);
    00427
    00428     painter->save();
    00429     painter->setFont(scaleWidget->font());
    00430
    00431     QPen pen = painter->pen();
    00432     pen.setWidth(scaleWidget->penWidth());
    00433     painter->setPen(pen);
    00434
    00435     QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
    00436     const QPoint sdPos = sd->pos();
    00437     const int sdLength = sd->length();
    00438
    00439     sd->move(x, y);
    00440     sd->setLength(w);
    00441
    00442 #if QT_VERSION < 0x040000
    00443     sd->draw(painter, scaleWidget->palette().active());
    00444 #else
    00445     QPalette palette = scaleWidget->palette();
    00446     palette.setCurrentColorGroup(QPalette::Active);
    00447     sd->draw(painter, palette);
    00448 #endif
    00449     // reset previous values
    00450     sd->move(sdPos);
    00451     sd->setLength(sdLength);
    00452
    00453     painter->restore();
    00454 }
    00455
    00467 void QwtPlot::printCanvas(QPainter *painter,
    00468     const QRect &boundingRect, const QRect &canvasRect,
    00469     const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
    00470 {
    00471     if ( pfilter.options() & QwtPlotPrintFilter::PrintBackground )
    00472     {
    00473         QBrush bgBrush;
    00474 #if QT_VERSION >= 0x040000
    00475             bgBrush = canvas()->palette().brush(backgroundRole());
    00476 #else
    00477         QColorGroup::ColorRole role =
    00478             QPalette::backgroundRoleFromMode( backgroundMode() );
    00479         bgBrush = canvas()->colorGroup().brush( role );
    00480 #endif
    00481         QRect r = boundingRect;
    00482         if ( !(pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales) )
    00483         {
    00484             r = canvasRect;
    00485 #if QT_VERSION >= 0x040000
    00486             // Unfortunately the paint engines do no always the same
    00487             switch(painter->paintEngine()->type() )
    00488             {
    00489                 case QPaintEngine::Raster:
    00490                 case QPaintEngine::X11:
    00491                     break;
    00492                 default:
    00493                     r.setWidth(r.width() - 1);
    00494                     r.setHeight(r.height() - 1);
    00495                     break;
    00496             }
    00497 #else
    00498             if ( painter->device()->isExtDev() )
    00499             {
    00500                 r.setWidth(r.width() - 1);
    00501                 r.setHeight(r.height() - 1);
    00502             }
    00503 #endif
    00504         }
    00505
    00506         QwtPainter::fillRect(painter, r, bgBrush);
    00507     }
    00508
    00509     if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
    00510     {
    00511         painter->save();
    00512         painter->setPen(QPen(Qt::black));
    00513         painter->setBrush(QBrush(Qt::NoBrush));
    00514         QwtPainter::drawRect(painter, boundingRect);
    00515         painter->restore();
    00516     }
    00517
    00518     painter->setClipping(true);
    00519     QwtPainter::setClipRect(painter, canvasRect);
    00520
    00521     drawItems(painter, canvasRect, map, pfilter);
    00522 }