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 }

Generated on Sun Mar 22 16:54:07 2009 for Qwt User's Guide by  doxygen 1.5.0