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 }

Generated on Thu May 1 15:44:09 2008 for Qwt User's Guide by  doxygen 1.5.0