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 #include <qglobal.h>
11 
12 #include <qpainter.h>
13 #if QT_VERSION >= 0x040100
14 #include <qsvgrenderer.h>
15 #else
16 #include <qbuffer.h>
17 #include <qpicture.h>
18 #endif
19 #if QT_VERSION < 0x040000
20 #include <qpaintdevicemetrics.h>
21 #endif
22 #include "qwt_scale_map.h"
23 #include "qwt_legend.h"
24 #include "qwt_legend_item.h"
25 #include "qwt_plot_svgitem.h"
26 
27 class QwtPlotSvgItem::PrivateData
28 {
29 public:
PrivateData()30     PrivateData()
31     {
32     }
33 
34     QwtDoubleRect boundingRect;
35 #if QT_VERSION >= 0x040100
36     QSvgRenderer renderer;
37 #else
38     QPicture picture;
39 #endif
40 };
41 
42 /*!
43    \brief Constructor
44 
45    Sets the following item attributes:
46    - QwtPlotItem::AutoScale: true
47    - QwtPlotItem::Legend:    false
48 
49    \param title Title
50 */
QwtPlotSvgItem(const QString & title)51 QwtPlotSvgItem::QwtPlotSvgItem(const QString& title):
52     QwtPlotItem(QwtText(title))
53 {
54     init();
55 }
56 
57 /*!
58    \brief Constructor
59 
60    Sets the following item attributes:
61    - QwtPlotItem::AutoScale: true
62    - QwtPlotItem::Legend:    false
63 
64    \param title Title
65 */
QwtPlotSvgItem(const QwtText & title)66 QwtPlotSvgItem::QwtPlotSvgItem(const QwtText& title):
67     QwtPlotItem(title)
68 {
69     init();
70 }
71 
72 //! Destructor
~QwtPlotSvgItem()73 QwtPlotSvgItem::~QwtPlotSvgItem()
74 {
75     delete d_data;
76 }
77 
init()78 void QwtPlotSvgItem::init()
79 {
80     d_data = new PrivateData();
81 
82     setItemAttribute(QwtPlotItem::AutoScale, true);
83     setItemAttribute(QwtPlotItem::Legend, false);
84 
85     setZ(8.0);
86 }
87 
88 //! \return QwtPlotItem::Rtti_PlotSVG
rtti() const89 int QwtPlotSvgItem::rtti() const
90 {
91     return QwtPlotItem::Rtti_PlotSVG;
92 }
93 
94 /*!
95    Load a SVG file
96 
97    \param rect Bounding rectangle
98    \param fileName SVG file name
99 
100    \return true, if the SVG file could be loaded
101 */
loadFile(const QwtDoubleRect & rect,const QString & fileName)102 bool QwtPlotSvgItem::loadFile(const QwtDoubleRect &rect,
103     const QString &fileName)
104 {
105     d_data->boundingRect = rect;
106 #if QT_VERSION >= 0x040100
107     const bool ok = d_data->renderer.load(fileName);
108 #else
109     const bool ok = d_data->picture.load(fileName, "svg");
110 #endif
111     itemChanged();
112     return ok;
113 }
114 
115 /*!
116    Load SVG data
117 
118    \param rect Bounding rectangle
119    \param data in SVG format
120 
121    \return true, if the SVG data could be loaded
122 */
loadData(const QwtDoubleRect & rect,const QByteArray & data)123 bool QwtPlotSvgItem::loadData(const QwtDoubleRect &rect,
124     const QByteArray &data)
125 {
126     d_data->boundingRect = rect;
127 #if QT_VERSION >= 0x040100
128     const bool ok = d_data->renderer.load(data);
129 #else
130 #if QT_VERSION >= 0x040000
131     QBuffer buffer(&(QByteArray&)data);
132 #else
133     QBuffer buffer(data);
134 #endif
135     const bool ok = d_data->picture.load(&buffer, "svg");
136 #endif
137     itemChanged();
138     return ok;
139 }
140 
141 //! Bounding rect of the item
boundingRect() const142 QwtDoubleRect QwtPlotSvgItem::boundingRect() const
143 {
144     return d_data->boundingRect;
145 }
146 
147 #if QT_VERSION >= 0x040100
148 
149 //! \return Renderer used to render the SVG data
renderer() const150 const QSvgRenderer &QwtPlotSvgItem::renderer() const
151 {
152     return d_data->renderer;
153 }
154 
155 //! \return Renderer used to render the SVG data
renderer()156 QSvgRenderer &QwtPlotSvgItem::renderer()
157 {
158     return d_data->renderer;
159 }
160 #endif
161 
162 /*!
163   Draw the SVG item
164 
165   \param painter Painter
166   \param xMap X-Scale Map
167   \param yMap Y-Scale Map
168   \param canvasRect Contents rect of the plot canvas
169 */
draw(QPainter * painter,const QwtScaleMap & xMap,const QwtScaleMap & yMap,const QRect & canvasRect) const170 void QwtPlotSvgItem::draw(QPainter *painter,
171     const QwtScaleMap &xMap, const QwtScaleMap &yMap,
172     const QRect &canvasRect) const
173 {
174     const QwtDoubleRect cRect = invTransform(xMap, yMap, canvasRect);
175     const QwtDoubleRect bRect = boundingRect();
176     if ( bRect.isValid() && cRect.isValid() )
177     {
178         QwtDoubleRect rect = bRect;
179         if ( bRect.contains(cRect) )
180             rect = cRect;
181 
182         const QRect r = transform(xMap, yMap, rect);
183         render(painter, viewBox(rect), r);
184     }
185 }
186 
187 /*!
188   Render the SVG data
189 
190   \param painter Painter
191   \param viewBox View Box, see QSvgRenderer::viewBox
192   \param rect Traget rectangle on the paint device
193 */
render(QPainter * painter,const QwtDoubleRect & viewBox,const QRect & rect) const194 void QwtPlotSvgItem::render(QPainter *painter,
195         const QwtDoubleRect &viewBox, const QRect &rect) const
196 {
197     if ( !viewBox.isValid() )
198         return;
199 
200 #if QT_VERSION >= 0x040200
201     d_data->renderer.setViewBox(viewBox);
202     d_data->renderer.render(painter, rect);
203     return;
204 #else
205 
206 #if QT_VERSION >= 0x040100
207     const QSize paintSize(painter->window().width(),
208         painter->window().height());
209     if ( !paintSize.isValid() )
210         return;
211 
212     const double xRatio = paintSize.width() / viewBox.width();
213     const double yRatio = paintSize.height() / viewBox.height();
214 
215     const double dx = rect.left() / xRatio + 1.0;
216     const double dy = rect.top() / yRatio + 1.0;
217 
218     const double mx = double(rect.width()) / paintSize.width();
219     const double my = double(rect.height()) / paintSize.height();
220 
221     painter->save();
222 
223     painter->translate(dx, dy);
224     painter->scale(mx, my);
225 
226     d_data->renderer.setViewBox(viewBox.toRect());
227     d_data->renderer.render(painter);
228 
229     painter->restore();
230 #else
231     const double mx = rect.width() / viewBox.width();
232     const double my = rect.height() / viewBox.height();
233     const double dx = rect.x() - mx * viewBox.x();
234     const double dy = rect.y() - my * viewBox.y();
235 
236     painter->save();
237 
238     painter->translate(dx, dy);
239     painter->scale(mx, my);
240 
241     d_data->picture.play(painter);
242 
243     painter->restore();
244 #endif // < 0x040100
245 #endif // < 0x040200
246 }
247 
248 /*!
249   Calculate the viewBox from an rect and boundingRect().
250 
251   \param rect Rectangle in scale coordinates
252   \return viewBox View Box, see QSvgRenderer::viewBox
253 */
viewBox(const QwtDoubleRect & rect) const254 QwtDoubleRect QwtPlotSvgItem::viewBox(const QwtDoubleRect &rect) const
255 {
256 #if QT_VERSION >= 0x040100
257     const QSize sz = d_data->renderer.defaultSize();
258 #else
259 #if QT_VERSION > 0x040000
260     const QSize sz(d_data->picture.width(),
261         d_data->picture.height());
262 #else
263     QPaintDeviceMetrics metrics(&d_data->picture);
264     const QSize sz(metrics.width(), metrics.height());
265 #endif
266 #endif
267     const QwtDoubleRect br = boundingRect();
268 
269     if ( !rect.isValid() || !br.isValid() || sz.isNull() )
270         return QwtDoubleRect();
271 
272     QwtScaleMap xMap;
273     xMap.setScaleInterval(br.left(), br.right());
274     xMap.setPaintInterval(0, sz.width());
275 
276     QwtScaleMap yMap;
277     yMap.setScaleInterval(br.top(), br.bottom());
278     yMap.setPaintInterval(sz.height(), 0);
279 
280     const double x1 = xMap.xTransform(rect.left());
281     const double x2 = xMap.xTransform(rect.right());
282     const double y1 = yMap.xTransform(rect.bottom());
283     const double y2 = yMap.xTransform(rect.top());
284 
285     return QwtDoubleRect(x1, y1, x2 - x1, y2 - y1);
286 }
287