Qwt User's Guide: qwt_plot_print.cpp Source File

- Main Page
- Classes
- Files
- Related Pages

- File List
- File Members

# 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             int margin = plotLayout()->canvasMargin(axisId);
    00210             if ( axisId == yLeft || axisId == yRight )
    00211             {
    00212                 margin = metricsMap.layoutToDeviceY(margin);
    00213                 from = canvasRect.bottom() - margin;
    00214                 to = canvasRect.top() + margin;
    00215             }
    00216             else
    00217             {
    00218                 margin = metricsMap.layoutToDeviceX(margin);
    00219                 from = canvasRect.left() + margin;
    00220                 to = canvasRect.right() - margin;
    00221             }
    00222         }
    00223         map[axisId].setPaintXInterval(from, to);
    00224     }
    00225
    00226     // The canvas maps are already scaled.
    00227     QwtPainter::setMetricsMap(painter->device(), painter->device());
    00228     printCanvas(painter, boundingRect, canvasRect, map, pfilter);
    00229     QwtPainter::resetMetricsMap();
    00230
    00231     ((QwtPlot *)this)->plotLayout()->invalidate();
    00232
    00233     // reset all widgets with their original attributes.
    00234     if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
    00235     {
    00236         // restore the previous base line dists
    00237
    00238         for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
    00239         {
    00240             QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
    00241             if ( scaleWidget  )
    00242                 scaleWidget->setMargin(baseLineDists[axisId]);
    00243         }
    00244     }
    00245
    00246     pfilter.reset((QwtPlot *)this);
    00247
    00248     painter->restore();
    00249 }
    00250
    00258 void QwtPlot::printTitle(QPainter *painter, const QRect &rect) const
    00259 {
    00260     painter->setFont(titleLabel()->font());
    00261
    00262     const QColor color =
    00263 #if QT_VERSION < 0x040000
    00264         titleLabel()->palette().color(
    00265             QPalette::Active, QColorGroup::Text);
    00266 #else
    00267         titleLabel()->palette().color(
    00268             QPalette::Active, QPalette::Text);
    00269 #endif
    00270
    00271     painter->setPen(color);
    00272     titleLabel()->text().draw(painter, rect);
    00273 }
    00274
    00282 void QwtPlot::printLegend(QPainter *painter, const QRect &rect) const
    00283 {
    00284     if ( !legend() || legend()->isEmpty() )
    00285         return;
    00286
    00287     QLayout *l = legend()->contentsWidget()->layout();
    00288     if ( l == 0 || !l->inherits("QwtDynGridLayout") )
    00289         return;
    00290
    00291     QwtDynGridLayout *legendLayout = (QwtDynGridLayout *)l;
    00292
    00293     uint numCols = legendLayout->columnsForWidth(rect.width());
    00294 #if QT_VERSION < 0x040000
    00295     QValueList<QRect> itemRects =
    00296         legendLayout->layoutItems(rect, numCols);
    00297 #else
    00298     QList<QRect> itemRects =
    00299         legendLayout->layoutItems(rect, numCols);
    00300 #endif
    00301
    00302     int index = 0;
    00303
    00304 #if QT_VERSION < 0x040000
    00305     QLayoutIterator layoutIterator = legendLayout->iterator();
    00306     for ( QLayoutItem *item = layoutIterator.current();
    00307         item != 0; item = ++layoutIterator)
    00308     {
    00309 #else
    00310     for ( int i = 0; i < legendLayout->count(); i++ )
    00311     {
    00312         QLayoutItem *item = legendLayout->itemAt(i);
    00313 #endif
    00314         QWidget *w = item->widget();
    00315         if ( w )
    00316         {
    00317             painter->save();
    00318             painter->setClipping(true);
    00319             QwtPainter::setClipRect(painter, itemRects[index]);
    00320
    00321             printLegendItem(painter, w, itemRects[index]);
    00322
    00323             index++;
    00324             painter->restore();
    00325         }
    00326     }
    00327 }
    00328
    00337 void QwtPlot::printLegendItem(QPainter *painter,
    00338     const QWidget *w, const QRect &rect) const
    00339 {
    00340     if ( w->inherits("QwtLegendItem") )
    00341     {
    00342         QwtLegendItem *item = (QwtLegendItem *)w;
    00343
    00344         painter->setFont(item->font());
    00345         item->drawItem(painter, rect);
    00346     }
    00347 }
    00348
    00361 void QwtPlot::printScale(QPainter *painter,
    00362     int axisId, int startDist, int endDist, int baseDist,
    00363     const QRect &rect) const
    00364 {
    00365     if (!axisEnabled(axisId))
    00366         return;
    00367
    00368     const QwtScaleWidget *scaleWidget = axisWidget(axisId);
    00369     if ( scaleWidget->isColorBarEnabled()
    00370         && scaleWidget->colorBarWidth() > 0)
    00371     {
    00372         const QwtMetricsMap map = QwtPainter::metricsMap();
    00373
    00374         QRect r = map.layoutToScreen(rect);
    00375         r.setWidth(r.width() - 1);
    00376         r.setHeight(r.height() - 1);
    00377
    00378         scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
    00379
    00380         const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
    00381         if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
    00382             baseDist += map.screenToLayoutY(off);
    00383         else
    00384             baseDist += map.screenToLayoutX(off);
    00385     }
    00386
    00387     QwtScaleDraw::Alignment align;
    00388     int x, y, w;
    00389
    00390     switch(axisId)
    00391     {
    00392         case yLeft:
    00393         {
    00394             x = rect.right() - baseDist;
    00395             y = rect.y() + startDist;
    00396             w = rect.height() - startDist - endDist;
    00397             align = QwtScaleDraw::LeftScale;
    00398             break;
    00399         }
    00400         case yRight:
    00401         {
    00402             x = rect.left() + baseDist;
    00403             y = rect.y() + startDist;
    00404             w = rect.height() - startDist - endDist;
    00405             align = QwtScaleDraw::RightScale;
    00406             break;
    00407         }
    00408         case xTop:
    00409         {
    00410             x = rect.left() + startDist;
    00411             y = rect.bottom() - baseDist;
    00412             w = rect.width() - startDist - endDist;
    00413             align = QwtScaleDraw::TopScale;
    00414             break;
    00415         }
    00416         case xBottom:
    00417         {
    00418             x = rect.left() + startDist;
    00419             y = rect.top() + baseDist;
    00420             w = rect.width() - startDist - endDist;
    00421             align = QwtScaleDraw::BottomScale;
    00422             break;
    00423         }
    00424         default:
    00425             return;
    00426     }
    00427
    00428     scaleWidget->drawTitle(painter, align, rect);
    00429
    00430     painter->save();
    00431     painter->setFont(scaleWidget->font());
    00432
    00433     QPen pen = painter->pen();
    00434     pen.setWidth(scaleWidget->penWidth());
    00435     painter->setPen(pen);
    00436
    00437     QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
    00438     const QPoint sdPos = sd->pos();
    00439     const int sdLength = sd->length();
    00440
    00441     sd->move(x, y);
    00442     sd->setLength(w);
    00443
    00444 #if QT_VERSION < 0x040000
    00445     sd->draw(painter, scaleWidget->palette().active());
    00446 #else
    00447     QPalette palette = scaleWidget->palette();
    00448     palette.setCurrentColorGroup(QPalette::Active);
    00449     sd->draw(painter, palette);
    00450 #endif
    00451     // reset previous values
    00452     sd->move(sdPos);
    00453     sd->setLength(sdLength);
    00454
    00455     painter->restore();
    00456 }
    00457
    00469 void QwtPlot::printCanvas(QPainter *painter,
    00470     const QRect &boundingRect, const QRect &canvasRect,
    00471     const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
    00472 {
    00473     if ( pfilter.options() & QwtPlotPrintFilter::PrintBackground )
    00474     {
    00475         QBrush bgBrush;
    00476 #if QT_VERSION >= 0x040000
    00477             bgBrush = canvas()->palette().brush(backgroundRole());
    00478 #else
    00479         QColorGroup::ColorRole role =
    00480             QPalette::backgroundRoleFromMode( backgroundMode() );
    00481         bgBrush = canvas()->colorGroup().brush( role );
    00482 #endif
    00483         QRect r = boundingRect;
    00484         if ( !(pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales) )
    00485         {
    00486             r = canvasRect;
    00487 #if QT_VERSION >= 0x040000
    00488             // Unfortunately the paint engines do no always the same
    00489             const QPaintEngine *pe = painter->paintEngine();
    00490             if ( pe )
    00491             {
    00492                 switch(painter->paintEngine()->type() )
    00493                 {
    00494                     case QPaintEngine::Raster:
    00495                     case QPaintEngine::X11:
    00496                         break;
    00497                     default:
    00498                         r.setWidth(r.width() - 1);
    00499                         r.setHeight(r.height() - 1);
    00500                         break;
    00501                 }
    00502             }
    00503 #else
    00504             if ( painter->device()->isExtDev() )
    00505             {
    00506                 r.setWidth(r.width() - 1);
    00507                 r.setHeight(r.height() - 1);
    00508             }
    00509 #endif
    00510         }
    00511
    00512         QwtPainter::fillRect(painter, r, bgBrush);
    00513     }
    00514
    00515     if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
    00516     {
    00517         painter->save();
    00518         painter->setPen(QPen(Qt::black));
    00519         painter->setBrush(QBrush(Qt::NoBrush));
    00520         QwtPainter::drawRect(painter, boundingRect);
    00521         painter->restore();
    00522     }
    00523
    00524     painter->setClipping(true);
    00525     QwtPainter::setClipRect(painter, canvasRect);
    00526
    00527     drawItems(painter, canvasRect, map, pfilter);
    00528 }