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