# 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 }