~ubuntu-branches/ubuntu/oneiric/qwt/oneiric-proposed

« back to all changes in this revision

Viewing changes to qwt-5.1.0/src/qwt_plot_print.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fathi Boudra
  • Date: 2008-05-26 10:26:31 UTC
  • mfrom: (1.1.3 upstream) (2.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080526102631-bp95mfccnrb957nx
Tags: 5.1.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2
 
 * Qwt Widget Library
3
 
 * Copyright (C) 1997   Josef Wilgen
4
 
 * Copyright (C) 2002   Uwe Rathmann
5
 
 *
6
 
 * This library is free software; you can redistribute it and/or
7
 
 * modify it under the terms of the Qwt License, Version 1.0
8
 
 *****************************************************************************/
9
 
 
10
 
// vim: expandtab
11
 
 
12
 
#include <qpainter.h>
13
 
#if QT_VERSION < 0x040000
14
 
#include <qpaintdevicemetrics.h>
15
 
#else
16
 
#include <qpaintengine.h>
17
 
#endif
18
 
#include "qwt_painter.h"
19
 
#include "qwt_legend_item.h"
20
 
#include "qwt_plot.h"
21
 
#include "qwt_plot_canvas.h"
22
 
#include "qwt_plot_layout.h"
23
 
#include "qwt_legend.h"
24
 
#include "qwt_dyngrid_layout.h"
25
 
#include "qwt_scale_widget.h"
26
 
#include "qwt_scale_engine.h"
27
 
#include "qwt_text.h"
28
 
#include "qwt_text_label.h"
29
 
#include "qwt_math.h"
30
 
 
31
 
/*!
32
 
  \brief Print the plot to a \c QPaintDevice (\c QPrinter)
33
 
  This function prints the contents of a QwtPlot instance to
34
 
  \c QPaintDevice object. The size is derived from its device
35
 
  metrics.
36
 
 
37
 
  \param paintDev device to paint on, often a printer
38
 
  \param pfilter print filter
39
 
  \sa QwtPlot::print
40
 
  \sa QwtPlotPrintFilter
41
 
*/
42
 
 
43
 
void QwtPlot::print(QPaintDevice &paintDev,
44
 
   const QwtPlotPrintFilter &pfilter) const
45
 
{
46
 
#if QT_VERSION < 0x040000
47
 
    QPaintDeviceMetrics mpr(&paintDev);
48
 
    int w = mpr.width();
49
 
    int h = mpr.height();
50
 
#else
51
 
    int w = paintDev.width();
52
 
    int h = paintDev.height();
53
 
#endif
54
 
 
55
 
    QRect rect(0, 0, w, h);
56
 
    double aspect = double(rect.width())/double(rect.height());
57
 
    if ((aspect < 1.0))
58
 
        rect.setHeight(int(aspect*rect.width()));
59
 
 
60
 
    QPainter p(&paintDev);
61
 
    print(&p, rect, pfilter);
62
 
}
63
 
 
64
 
/*!
65
 
  \brief Paint the plot into a given rectangle.
66
 
  Paint the contents of a QwtPlot instance into a given rectangle.
67
 
 
68
 
  \param painter Painter
69
 
  \param plotRect Bounding rectangle
70
 
  \param pfilter Print filter
71
 
  \sa QwtPlotPrintFilter
72
 
*/
73
 
void QwtPlot::print(QPainter *painter, const QRect &plotRect,
74
 
        const QwtPlotPrintFilter &pfilter) const
75
 
{
76
 
    int axisId;
77
 
 
78
 
    if ( painter == 0 || !painter->isActive() ||
79
 
            !plotRect.isValid() || size().isNull() )
80
 
       return;
81
 
 
82
 
    painter->save();
83
 
#if 1
84
 
    /*
85
 
      PDF: In Qt4 ( <= 4.3.2 ) the scales are painted in gray instead of
86
 
      black. See http://trolltech.com/developer/task-tracker/index_html?id=184671&method=entry
87
 
      The dummy lines below work around the problem.
88
 
     */
89
 
    const QPen pen = painter->pen();
90
 
    painter->setPen(QPen(Qt::black, 1));
91
 
    painter->setPen(pen);
92
 
#endif
93
 
 
94
 
    // All paint operations need to be scaled according to
95
 
    // the paint device metrics. 
96
 
 
97
 
    QwtPainter::setMetricsMap(this, painter->device());
98
 
    const QwtMetricsMap &metricsMap = QwtPainter::metricsMap();
99
 
 
100
 
    // It is almost impossible to integrate into the Qt layout
101
 
    // framework, when using different fonts for printing
102
 
    // and screen. To avoid writing different and Qt unconform
103
 
    // layout engines we change the widget attributes, print and 
104
 
    // reset the widget attributes again. This way we produce a lot of
105
 
    // useless layout events ...
106
 
 
107
 
    pfilter.apply((QwtPlot *)this);
108
 
 
109
 
    int baseLineDists[QwtPlot::axisCnt];
110
 
    if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
111
 
    {
112
 
        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
113
 
        {
114
 
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
115
 
            if ( scaleWidget )
116
 
            {
117
 
                baseLineDists[axisId] = scaleWidget->margin();
118
 
                scaleWidget->setMargin(0);
119
 
            }
120
 
        }
121
 
    }
122
 
    // Calculate the layout for the print.
123
 
 
124
 
    int layoutOptions = QwtPlotLayout::IgnoreScrollbars 
125
 
        | QwtPlotLayout::IgnoreFrames;
126
 
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) )
127
 
        layoutOptions |= QwtPlotLayout::IgnoreMargin;
128
 
    if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) )
129
 
        layoutOptions |= QwtPlotLayout::IgnoreLegend;
130
 
 
131
 
    ((QwtPlot *)this)->plotLayout()->activate(this, 
132
 
        QwtPainter::metricsMap().deviceToLayout(plotRect), 
133
 
        layoutOptions);
134
 
 
135
 
    if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle)
136
 
        && (!titleLabel()->text().isEmpty()))
137
 
    {
138
 
        printTitle(painter, plotLayout()->titleRect());
139
 
    }
140
 
 
141
 
    if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend)
142
 
        && legend() && !legend()->isEmpty() )
143
 
    {
144
 
        printLegend(painter, plotLayout()->legendRect());
145
 
    }
146
 
 
147
 
    for ( axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
148
 
    {
149
 
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
150
 
        if (scaleWidget)
151
 
        {
152
 
            int baseDist = scaleWidget->margin();
153
 
 
154
 
            int startDist, endDist;
155
 
            scaleWidget->getBorderDistHint(startDist, endDist);
156
 
 
157
 
            printScale(painter, axisId, startDist, endDist,
158
 
                baseDist, plotLayout()->scaleRect(axisId));
159
 
        }
160
 
    }
161
 
 
162
 
    QRect canvasRect = plotLayout()->canvasRect();
163
 
 
164
 
    /* 
165
 
       The border of the bounding rect needs to ba scaled to
166
 
       layout coordinates, so that it is aligned to the axes 
167
 
     */
168
 
    QRect boundingRect( canvasRect.left() - 1, canvasRect.top() - 1,
169
 
        canvasRect.width() + 2, canvasRect.height() + 2);
170
 
    boundingRect = metricsMap.layoutToDevice(boundingRect);
171
 
    boundingRect.setWidth(boundingRect.width() - 1);
172
 
    boundingRect.setHeight(boundingRect.height() - 1);
173
 
 
174
 
    canvasRect = metricsMap.layoutToDevice(canvasRect);
175
 
 
176
 
    // When using QwtPainter all sizes where computed in pixel
177
 
    // coordinates and scaled by QwtPainter later. This limits
178
 
    // the precision to screen resolution. A better solution
179
 
    // is to scale the maps and print in unlimited resolution.
180
 
 
181
 
    QwtScaleMap map[axisCnt];
182
 
    for (axisId = 0; axisId < axisCnt; axisId++)
183
 
    {
184
 
        map[axisId].setTransformation(axisScaleEngine(axisId)->transformation());
185
 
 
186
 
        const QwtScaleDiv &scaleDiv = *axisScaleDiv(axisId);
187
 
        map[axisId].setScaleInterval(scaleDiv.lBound(), scaleDiv.hBound());
188
 
 
189
 
        double from, to;
190
 
        if ( axisEnabled(axisId) )
191
 
        {
192
 
            const int sDist = axisWidget(axisId)->startBorderDist();
193
 
            const int eDist = axisWidget(axisId)->endBorderDist();
194
 
            const QRect &scaleRect = plotLayout()->scaleRect(axisId);
195
 
 
196
 
            if ( axisId == xTop || axisId == xBottom )
197
 
            {
198
 
                from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist);
199
 
                to = metricsMap.layoutToDeviceX(scaleRect.right() + 1 - eDist);
200
 
            }
201
 
            else
202
 
            {
203
 
                from = metricsMap.layoutToDeviceY(scaleRect.bottom() + 1 - eDist );
204
 
                to = metricsMap.layoutToDeviceY(scaleRect.top() + sDist);
205
 
            }
206
 
        }
207
 
        else
208
 
        {
209
 
            const int margin = plotLayout()->canvasMargin(axisId);
210
 
            if ( axisId == yLeft || axisId == yRight )
211
 
            {
212
 
                from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin);
213
 
                to = metricsMap.layoutToDeviceX(canvasRect.top() + margin);
214
 
            }
215
 
            else
216
 
            {
217
 
                from = metricsMap.layoutToDeviceY(canvasRect.left() + margin);
218
 
                to = metricsMap.layoutToDeviceY(canvasRect.right() - margin);
219
 
            }
220
 
        }
221
 
        map[axisId].setPaintXInterval(from, to);
222
 
    }
223
 
 
224
 
    // The canvas maps are already scaled. 
225
 
    QwtPainter::setMetricsMap(painter->device(), painter->device());
226
 
    printCanvas(painter, boundingRect, canvasRect, map, pfilter);
227
 
    QwtPainter::resetMetricsMap();
228
 
 
229
 
    ((QwtPlot *)this)->plotLayout()->invalidate();
230
 
 
231
 
    // reset all widgets with their original attributes.
232
 
    if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
233
 
    {
234
 
        // restore the previous base line dists
235
 
 
236
 
        for (axisId = 0; axisId < QwtPlot::axisCnt; axisId++ )
237
 
        {
238
 
            QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(axisId);
239
 
            if ( scaleWidget  )
240
 
                scaleWidget->setMargin(baseLineDists[axisId]);
241
 
        }
242
 
    }
243
 
 
244
 
    pfilter.reset((QwtPlot *)this);
245
 
 
246
 
    painter->restore();
247
 
}
248
 
 
249
 
/*!
250
 
  Print the title into a given rectangle.
251
 
 
252
 
  \param painter Painter
253
 
  \param rect Bounding rectangle
254
 
*/
255
 
 
256
 
void QwtPlot::printTitle(QPainter *painter, const QRect &rect) const
257
 
{
258
 
    painter->setFont(titleLabel()->font());
259
 
 
260
 
    const QColor color = 
261
 
#if QT_VERSION < 0x040000
262
 
        titleLabel()->palette().color(
263
 
            QPalette::Active, QColorGroup::Text);
264
 
#else
265
 
        titleLabel()->palette().color(
266
 
            QPalette::Active, QPalette::Text);
267
 
#endif
268
 
 
269
 
    painter->setPen(color);
270
 
    titleLabel()->text().draw(painter, rect);
271
 
}
272
 
 
273
 
/*!
274
 
  Print the legend into a given rectangle.
275
 
 
276
 
  \param painter Painter
277
 
  \param rect Bounding rectangle
278
 
*/
279
 
 
280
 
void QwtPlot::printLegend(QPainter *painter, const QRect &rect) const
281
 
{
282
 
    if ( !legend() || legend()->isEmpty() )
283
 
        return;
284
 
 
285
 
    QLayout *l = legend()->contentsWidget()->layout();
286
 
    if ( l == 0 || !l->inherits("QwtDynGridLayout") )
287
 
        return;
288
 
 
289
 
    QwtDynGridLayout *legendLayout = (QwtDynGridLayout *)l;
290
 
 
291
 
    uint numCols = legendLayout->columnsForWidth(rect.width());
292
 
#if QT_VERSION < 0x040000
293
 
    QValueList<QRect> itemRects = 
294
 
        legendLayout->layoutItems(rect, numCols);
295
 
#else
296
 
    QList<QRect> itemRects = 
297
 
        legendLayout->layoutItems(rect, numCols);
298
 
#endif
299
 
 
300
 
    int index = 0;
301
 
 
302
 
#if QT_VERSION < 0x040000
303
 
    QLayoutIterator layoutIterator = legendLayout->iterator();
304
 
    for ( QLayoutItem *item = layoutIterator.current(); 
305
 
        item != 0; item = ++layoutIterator)
306
 
    {
307
 
#else
308
 
    for ( int i = 0; i < legendLayout->count(); i++ )
309
 
    {
310
 
        QLayoutItem *item = legendLayout->itemAt(i);
311
 
#endif
312
 
        QWidget *w = item->widget();
313
 
        if ( w )
314
 
        {
315
 
            painter->save();
316
 
            painter->setClipping(true);
317
 
            QwtPainter::setClipRect(painter, itemRects[index]);
318
 
 
319
 
            printLegendItem(painter, w, itemRects[index]);
320
 
 
321
 
            index++;
322
 
            painter->restore();
323
 
        }
324
 
    }
325
 
}
326
 
 
327
 
/*!
328
 
  Print the legend item into a given rectangle.
329
 
 
330
 
  \param painter Painter
331
 
  \param w Widget representing a legend item
332
 
  \param rect Bounding rectangle
333
 
*/
334
 
 
335
 
void QwtPlot::printLegendItem(QPainter *painter, 
336
 
    const QWidget *w, const QRect &rect) const
337
 
{
338
 
    if ( w->inherits("QwtLegendItem") )
339
 
    {
340
 
        QwtLegendItem *item = (QwtLegendItem *)w;
341
 
 
342
 
        painter->setFont(item->font());
343
 
        item->drawItem(painter, rect);
344
 
    }
345
 
}
346
 
 
347
 
/*!
348
 
  \brief Paint a scale into a given rectangle.
349
 
  Paint the scale into a given rectangle.
350
 
 
351
 
  \param painter Painter
352
 
  \param axisId Axis
353
 
  \param startDist Start border distance
354
 
  \param endDist End border distance
355
 
  \param baseDist Base distance
356
 
  \param rect Bounding rectangle
357
 
*/
358
 
 
359
 
void QwtPlot::printScale(QPainter *painter,
360
 
    int axisId, int startDist, int endDist, int baseDist, 
361
 
    const QRect &rect) const
362
 
{
363
 
    if (!axisEnabled(axisId))
364
 
        return;
365
 
 
366
 
    const QwtScaleWidget *scaleWidget = axisWidget(axisId);
367
 
    if ( scaleWidget->isColorBarEnabled() 
368
 
        && scaleWidget->colorBarWidth() > 0)
369
 
    {
370
 
        const QwtMetricsMap map = QwtPainter::metricsMap();
371
 
 
372
 
        QRect r = map.layoutToScreen(rect);
373
 
        r.setWidth(r.width() - 1);
374
 
        r.setHeight(r.height() - 1);
375
 
 
376
 
        scaleWidget->drawColorBar(painter, scaleWidget->colorBarRect(r));
377
 
 
378
 
        const int off = scaleWidget->colorBarWidth() + scaleWidget->spacing();
379
 
        if ( scaleWidget->scaleDraw()->orientation() == Qt::Horizontal )
380
 
            baseDist += map.screenToLayoutY(off);
381
 
        else
382
 
            baseDist += map.screenToLayoutX(off);
383
 
    }
384
 
 
385
 
    QwtScaleDraw::Alignment align;
386
 
    int x, y, w;
387
 
 
388
 
    switch(axisId)
389
 
    {
390
 
        case yLeft:
391
 
        {
392
 
            x = rect.right() - baseDist;
393
 
            y = rect.y() + startDist;
394
 
            w = rect.height() - startDist - endDist;
395
 
            align = QwtScaleDraw::LeftScale;
396
 
            break;
397
 
        }
398
 
        case yRight:
399
 
        {
400
 
            x = rect.left() + baseDist;
401
 
            y = rect.y() + startDist;
402
 
            w = rect.height() - startDist - endDist;
403
 
            align = QwtScaleDraw::RightScale;
404
 
            break;
405
 
        }
406
 
        case xTop:
407
 
        {
408
 
            x = rect.left() + startDist;
409
 
            y = rect.bottom() - baseDist;
410
 
            w = rect.width() - startDist - endDist;
411
 
            align = QwtScaleDraw::TopScale;
412
 
            break;
413
 
        }
414
 
        case xBottom:
415
 
        {
416
 
            x = rect.left() + startDist;
417
 
            y = rect.top() + baseDist;
418
 
            w = rect.width() - startDist - endDist;
419
 
            align = QwtScaleDraw::BottomScale;
420
 
            break;
421
 
        }
422
 
        default:
423
 
            return;
424
 
    }
425
 
 
426
 
    scaleWidget->drawTitle(painter, align, rect);
427
 
 
428
 
    painter->save();
429
 
    painter->setFont(scaleWidget->font());
430
 
 
431
 
    QPen pen = painter->pen();
432
 
    pen.setWidth(scaleWidget->penWidth());
433
 
    painter->setPen(pen);
434
 
 
435
 
    QwtScaleDraw *sd = (QwtScaleDraw *)scaleWidget->scaleDraw();
436
 
    const QPoint sdPos = sd->pos();
437
 
    const int sdLength = sd->length();
438
 
 
439
 
    sd->move(x, y);
440
 
    sd->setLength(w);
441
 
 
442
 
#if QT_VERSION < 0x040000
443
 
    sd->draw(painter, scaleWidget->palette().active());
444
 
#else
445
 
    QPalette palette = scaleWidget->palette();
446
 
    palette.setCurrentColorGroup(QPalette::Active);
447
 
    sd->draw(painter, palette);
448
 
#endif
449
 
    // reset previous values
450
 
    sd->move(sdPos); 
451
 
    sd->setLength(sdLength); 
452
 
 
453
 
    painter->restore();
454
 
}
455
 
 
456
 
/*!
457
 
  Print the canvas into a given rectangle.
458
 
 
459
 
  \param painter Painter
460
 
  \param map Maps mapping between plot and paint device coordinates
461
 
  \param boundingRect Bounding rectangle
462
 
  \param canvasRect Canvas rectangle
463
 
  \param pfilter Print filter
464
 
  \sa QwtPlotPrintFilter
465
 
*/
466
 
 
467
 
void QwtPlot::printCanvas(QPainter *painter, 
468
 
    const QRect &boundingRect, const QRect &canvasRect,
469
 
    const QwtScaleMap map[axisCnt], const QwtPlotPrintFilter &pfilter) const
470
 
{
471
 
    if ( pfilter.options() & QwtPlotPrintFilter::PrintBackground )
472
 
    {
473
 
        QBrush bgBrush;
474
 
#if QT_VERSION >= 0x040000
475
 
            bgBrush = canvas()->palette().brush(backgroundRole());
476
 
#else
477
 
        QColorGroup::ColorRole role =
478
 
            QPalette::backgroundRoleFromMode( backgroundMode() );
479
 
        bgBrush = canvas()->colorGroup().brush( role );
480
 
#endif
481
 
        QRect r = boundingRect;
482
 
        if ( !(pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales) )
483
 
        {
484
 
            r = canvasRect;
485
 
#if QT_VERSION >= 0x040000
486
 
            // Unfortunately the paint engines do no always the same
487
 
            switch(painter->paintEngine()->type() )
488
 
            {
489
 
                case QPaintEngine::Raster:
490
 
                case QPaintEngine::X11:
491
 
                    break;
492
 
                default:
493
 
                    r.setWidth(r.width() - 1);
494
 
                    r.setHeight(r.height() - 1);
495
 
                    break;
496
 
            }
497
 
#else
498
 
            if ( painter->device()->isExtDev() )
499
 
            {
500
 
                r.setWidth(r.width() - 1);
501
 
                r.setHeight(r.height() - 1);    
502
 
            }
503
 
#endif
504
 
        }
505
 
 
506
 
        QwtPainter::fillRect(painter, r, bgBrush);
507
 
    }
508
 
 
509
 
    if ( pfilter.options() & QwtPlotPrintFilter::PrintFrameWithScales )
510
 
    {
511
 
        painter->save();
512
 
        painter->setPen(QPen(Qt::black));
513
 
        painter->setBrush(QBrush(Qt::NoBrush));
514
 
        QwtPainter::drawRect(painter, boundingRect);
515
 
        painter->restore();
516
 
    }
517
 
 
518
 
    painter->setClipping(true);
519
 
    QwtPainter::setClipRect(painter, canvasRect);
520
 
 
521
 
    drawItems(painter, canvasRect, map, pfilter);
522
 
}