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_rect.h"
00025 #include "qwt_dyngrid_layout.h"
00026 #include "qwt_scale_widget.h"
00027 #include "qwt_scale_engine.h"
00028 #include "qwt_text.h"
00029 #include "qwt_text_label.h"
00030 #include "qwt_math.h"
00031 
00044 void QwtPlot::print(QPaintDevice &paintDev,
00045    const QwtPlotPrintFilter &pfilter) const
00046 {
00047 #if QT_VERSION < 0x040000
00048     QPaintDeviceMetrics mpr(&paintDev);
00049     int w = mpr.width();
00050     int h = mpr.height();
00051 #else
00052     int w = paintDev.width();
00053     int h = paintDev.height();
00054 #endif
00055 
00056     QRect rect(0, 0, w, h);
00057     double aspect = double(rect.width())/double(rect.height());
00058     if ((aspect < 1.0))
00059         rect.setHeight(int(aspect*rect.width()));
00060 
00061     QPainter p(&paintDev);
00062     print(&p, rect, pfilter);
00063 }
00064 
00074 void QwtPlot::print(QPainter *painter, const QRect &plotRect,
00075         const QwtPlotPrintFilter &pfilter) const
00076 {
00077     int axisId;
00078 
00079     if ( painter == 0 || !painter->isActive() ||
00080             !plotRect.isValid() || size().isNull() )
00081        return;
00082 
00083     painter->save();
00084 
00085     // All paint operations need to be scaled according to
00086     // the paint device metrics. 
00087 
00088     QwtPainter::setMetricsMap(this, painter->device());
00089     const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
00090 
00091     // It is almost impossible to integrate into the Qt layout
00092     // framework, when using different fonts for printing
00093     // and screen. To avoid writing different and Qt unconform
00094     // layout engines we change the widget attributes, print and 
00095     // reset the widget attributes again. This way we produce a lot of
00096     // useless layout events ...
00097 
00098     pfilter.apply((QwtPlot *)this);
00099 
00100     int baseLineDists[QwtPlot::axisCnt];
00101     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
00102     {
00103         // In case of no background we set the backbone of
00104         // the scale on the frame of the canvas.
00105 
00106         for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
00107         {
00108             QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
00109             if ( scaleWidget )
00110             {
00111                 baseLineDists[axisId] = scaleWidget->margin();
00112                 scaleWidget->setMargin(0);
00113             }
00114         }
00115     }
00116     // Calculate the layout for the print.
00117 
00118     int layoutOptions = QwtPlotLayout::IgnoreScrollbars 
00119         | QwtPlotLayout::IgnoreFrames;
00120     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
00121         layoutOptions |= QwtPlotLayout::IgnoreMargin;
00122     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
00123         layoutOptions |= QwtPlotLayout::IgnoreLegend;
00124 
00125     ((QwtPlot *)this)->plotLayout()->activate(this, 
00126         QwtPainter::metricsMap().deviceToLayout(plotRect), 
00127         layoutOptions);
00128 
00129     if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
00130         && (!titleLabel()->text().isEmpty()))
00131     {
00132         printTitle(painter, plotLayout()->titleRect());
00133     }
00134 
00135     if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
00136         && legend() && !legend()->isEmpty() )
00137     {
00138         printLegend(painter, plotLayout()->legendRect());
00139     }
00140 
00141     for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
00142     {
00143         QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
00144         if (scaleWidget)
00145         {
00146             int baseDist = scaleWidget->margin();
00147 
00148             int startDist, endDist;
00149             scaleWidget->getBorderDistHint(startDist, endDist);
00150 
00151             printScale(painter, axisId, startDist, endDist,
00152                 baseDist, plotLayout()->scaleRect(axisId));
00153         }
00154     }
00155 
00156     const QRect canvasRect = metricsMap.layoutToDevice(plotLayout()->canvasRect());
00157 
00158     // When using QwtPainter all sizes where computed in pixel
00159     // coordinates and scaled by QwtPainter later. This limits
00160     // the precision to screen resolution. A much better solution
00161     // is to scale the maps and print in unlimited resolution.
00162 
00163     QwtScaleMap map[axisCnt];
00164     for (axisId = 0; axisId < axisCnt; axisId++)
00165     {
00166         map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());
00167 
00168         const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
00169         map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());
00170 
00171         double from, to;
00172         if ( axisEnabled(axisId) )
00173         {
00174             const int sDist = axisWidget(axisId)->startBorderDist();
00175             const int eDist = axisWidget(axisId)->endBorderDist();
00176             const QRect &scaleRect = plotLayout()->scaleRect(axisId);
00177 
00178             if ( axisId == xTop || axisId == xBottom )
00179             {
00180                 from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
00181                 to = metricsMap.layoutToDeviceX(scaleRect.right() - eDist);
00182             }
00183             else
00184             {
00185                 from = metricsMap.layoutToDeviceY(scaleRect.bottom() - eDist);
00186                 to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
00187             }
00188         }
00189         else
00190         {
00191             const int margin = plotLayout()->canvasMargin(axisId);
00192 
00193             const QRect &canvasRect = plotLayout()->canvasRect();
00194             if ( axisId == yLeft || axisId == yRight )
00195             {
00196                 from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin);
00197                 to = metricsMap.layoutToDeviceX(canvasRect.top() + margin);
00198             }
00199             else
00200             {
00201                 from = metricsMap.layoutToDeviceY(canvasRect.left() + margin);
00202                 to = metricsMap.layoutToDeviceY(canvasRect.right() - margin);
00203             }
00204         }
00205         map[axisId].setPaintXInterval(from, to);
00206     }
00207 
00208 
00209     // The canvas maps are already scaled. 
00210     QwtPainter::setMetricsMap(painter->device(), painter->device());
00211 
00212     printCanvas(painter, canvasRect, map, pfilter);
00213 
00214     QwtPainter::resetMetricsMap();
00215 
00216     ((QwtPlot *)this)->plotLayout()->invalidate();
00217 
00218     // reset all widgets with their original attributes.
00219     if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) )
00220     {
00221         // restore the previous base line dists
00222 
00223         for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
00224         {
00225             QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
00226             if ( scaleWidget  )
00227                 scaleWidget->setMargin(baseLineDists[axisId]);
00228         }
00229     }
00230 
00231     pfilter.reset((QwtPlot *)this);
00232 
00233     painter->restore();
00234 }
00235 
00243 void QwtPlot::printTitle(QPainter *painter, const QRect &rect) const
00244 {
00245     painter->setFont(titleLabel()->font());
00246 
00247     const QColor color = 
00248 #if QT_VERSION < 0x040000
00249         titleLabel()->palette().color(
00250             QPalette::Active, QColorGroup::Text);
00251 #else
00252         titleLabel()->palette().color(
00253             QPalette::Active, QPalette::Text);
00254 #endif
00255 
00256     painter->setPen(color);
00257     titleLabel()->text().draw(painter, rect);
00258 }
00259 
00267 void QwtPlot::printLegend(QPainter *painter, const QRect &rect) const
00268 {
00269     if ( !legend() || legend()->isEmpty() )
00270         return;
00271 
00272     QLayout *l = legend()->contentsWidget()->layout();
00273     if ( l == 0 || !l->inherits("QwtDynGridLayout") )
00274         return;
00275 
00276     QwtDynGridLayout *legendLayout = (QwtDynGridLayout *)l;
00277 
00278     uint numCols = legendLayout->columnsForWidth(rect.width());
00279 #if QT_VERSION < 0x040000
00280     QValueList<QRect> itemRects = 
00281         legendLayout->layoutItems(rect, numCols);
00282 #else
00283     QList<QRect> itemRects = 
00284         legendLayout->layoutItems(rect, numCols);
00285 #endif
00286 
00287     int index = 0;
00288 
00289 #if QT_VERSION < 0x040000
00290     QLayoutIterator layoutIterator = legendLayout->iterator();
00291     for ( QLayoutItem *item = layoutIterator.current(); 
00292         item != 0; item = ++layoutIterator)
00293     {
00294 #else
00295     for ( int i = 0; i < legendLayout->count(); i++ )
00296     {
00297         QLayoutItem *item = legendLayout->itemAt(i);
00298 #endif
00299         QWidget *w = item->widget();
00300         if ( w )
00301         {
00302             painter->save();
00303             painter->setClipping(true);
00304             QwtPainter::setClipRect(painter, itemRects[index]);
00305 
00306             printLegendItem(painter, w, itemRects[index]);
00307 
00308             index++;
00309             painter->restore();
00310         }
00311     }
00312 }
00313 
00322 void QwtPlot::printLegendItem(QPainter *painter, 
00323     const QWidget *w, const QRect &rect) const
00324 {
00325     if ( w->inherits("QwtLegendItem") )
00326     {
00327         QwtLegendItem *item = (QwtLegendItem *)w;
00328 
00329         painter->setFont(item->font());
00330         item->drawItem(painter, rect);
00331     }
00332 }
00333 
00346 void QwtPlot::printScale(QPainter *painter,
00347     int axisId, int startDist, int endDist, int baseDist, 
00348     const QRect &rect) const
00349 {
00350     if (!axisEnabled(axisId))
00351         return;
00352 
00353     const QwtScaleWidget *scaleWidget = axisWidget(axisId);
00354     if ( scaleWidget->isColorBarEnabled() 
00355         && scaleWidget->colorBarWidth() > 0)
00356     {
00357         const QwtMetricsMap map = QwtPainter::metricsMap();
00358 
00359         const QRect r = map.layoutToScreen(rect);
00360         scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
00361 
00362         const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
00363         if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
00364             baseDist += map.screenToLayoutY(off);
00365         else
00366             baseDist += map.screenToLayoutX(off);
00367     }
00368 
00369     QwtScaleDraw::Alignment align;
00370     int x, y, w;
00371 
00372     switch(axisId)
00373     {
00374         case yLeft:
00375         {
00376             x = rect.right() - baseDist + 1;
00377             y = rect.y() + startDist;
00378             w = rect.height() - startDist - endDist;
00379             align = QwtScaleDraw::LeftScale;
00380             break;
00381         }
00382         case yRight:
00383         {
00384             x = rect.left() + baseDist;
00385             y = rect.y() + startDist;
00386             w = rect.height() - startDist - endDist;
00387             align = QwtScaleDraw::RightScale;
00388             break;
00389         }
00390         case xTop:
00391         {
00392             x = rect.left() + startDist;
00393             y = rect.bottom() - baseDist + 1;
00394             w = rect.width() - startDist - endDist;
00395             align = QwtScaleDraw::TopScale;
00396             break;
00397         }
00398         case xBottom:
00399         {
00400             x = rect.left() + startDist;
00401             y = rect.top() + baseDist;
00402             w = rect.width() - startDist - endDist;
00403             align = QwtScaleDraw::BottomScale;
00404             break;
00405         }
00406         default:
00407             return;
00408     }
00409 
00410     scaleWidget->drawTitle(painter, align, rect);
00411 
00412     painter->save();
00413     painter->setFont(scaleWidget->font());
00414 
00415     QPen pen = painter->pen();
00416     pen.setWidth(scaleWidget->penWidth());
00417     painter->setPen(pen);
00418 
00419     QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
00420     const QPoint sdPos = sd->pos();
00421     const int sdLength = sd->length();
00422 
00423     sd->move(x, y);
00424     sd->setLength(w);
00425 
00426 #if QT_VERSION < 0x040000
00427     sd->draw(painter, scaleWidget->palette().active());
00428 #else
00429     QPalette palette = scaleWidget->palette();
00430     palette.setCurrentColorGroup(QPalette::Active);
00431     sd->draw(painter, palette);
00432 #endif
00433     // reset previous values
00434     sd->move(sdPos); 
00435     sd->setLength(sdLength); 
00436 
00437     painter->restore();
00438 }
00439 
00450 void QwtPlot::printCanvas(QPainter *painter, const QRect &canvasRect,
00451     const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
00452 {
00453     if ( pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground )
00454     {
00455         painter->setPen(Qt::NoPen);
00456 
00457         QBrush bgBrush;
00458 #if QT_VERSION >= 0x040000
00459             bgBrush = canvas()->palette().brush(backgroundRole());
00460 #else
00461         QColorGroup::ColorRole role =
00462             QPalette::backgroundRoleFromMode( backgroundMode() ); 
00463         bgBrush = canvas()->colorGroup().brush( role );
00464 #endif
00465         painter->setBrush(bgBrush);
00466         
00467         int x1 = 0;
00468         int x2 = 0;
00469         int y1 = 0;
00470         int y2 = 0;
00471 
00472 #if QT_VERSION >= 0x040000
00473         switch(painter->device()->paintEngine()->type())
00474         {
00475             case QPaintEngine::PostScript:
00476                 x2 = 1;
00477                 y2 = 1;
00478                 break;
00479             default:;
00480         }
00481 #endif
00482 
00483         const QwtMetricsMap map = QwtPainter::metricsMap();
00484         x1 = map.screenToLayoutX(x1);
00485         x2 = map.screenToLayoutX(x2);
00486         y1 = map.screenToLayoutY(y1);
00487         y2 = map.screenToLayoutY(y2);
00488 
00489         QwtPainter::drawRect(painter, 
00490             canvasRect.x() + x1, canvasRect.y() + y1, 
00491             canvasRect.width() - x2, canvasRect.height() - y2); 
00492     }
00493     else
00494     {
00495         // Paint the canvas borders instead.
00496         painter->setPen(QPen(Qt::black));
00497         painter->setBrush(QBrush(Qt::NoBrush));
00498         QwtPainter::drawRect(painter, canvasRect); 
00499     }
00500 
00501 
00502     painter->setClipping(true);
00503     QwtPainter::setClipRect(painter, canvasRect);
00504 
00505     drawItems(painter, canvasRect, map, pfilter);
00506 }

Generated on Mon Feb 26 21:22:38 2007 for Qwt User's Guide by  doxygen 1.4.6