1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the demonstration applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include <QtCore>
52#include <QtWidgets>
53#include <QtNetwork>
54#include <QtSvg>
55
56#define GET_DATA_ATTR(val) xml.attributes().value(val).toString()
57#define GET_DATETIME(val) QDateTime::fromString(val, "yyyy-MM-ddThh:mm:ss")
58#define FORMAT_TEMPERATURE(val) val + QChar(176) + "C"
59#define TEXTCOLOR palette().color(QPalette::WindowText)
60
61class WeatherInfo: public QMainWindow
62{
63 Q_OBJECT
64
65private:
66
67 QGraphicsView *m_view;
68 QGraphicsScene m_scene;
69 QString city;
70 QGraphicsRectItem *m_statusItem;
71 QGraphicsTextItem *m_temperatureItem;
72 QGraphicsTextItem *m_conditionItem;
73 QGraphicsTextItem *m_cityItem;
74 QGraphicsTextItem *m_copyright;
75 QGraphicsSvgItem *m_iconItem;
76 QList<QGraphicsRectItem*> m_forecastItems;
77 QList<QGraphicsTextItem*> m_dayItems;
78 QList<QGraphicsSvgItem*> m_conditionItems;
79 QList<QGraphicsTextItem*> m_rangeItems;
80 QTimeLine m_timeLine;
81 QHash<QString, QString> m_icons;
82 QNetworkAccessManager m_manager;
83
84public:
85 WeatherInfo(QWidget *parent = 0): QMainWindow(parent) {
86
87 m_view = new QGraphicsView(this);
88 setCentralWidget(m_view);
89
90 setupScene();
91 m_view->setScene(&m_scene);
92 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
93 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
94
95 m_view->setFrameShape(QFrame::NoFrame);
96 setWindowTitle("Weather Info");
97
98 QStringList cities;
99 cities << "Oslo";
100 cities << "Berlin";
101 cities << "Moscow";
102 cities << "Helsinki";
103 cities << "Santa Clara";
104 for (int i = 0; i < cities.count(); ++i) {
105 QAction *action = new QAction(cities[i], this);
106 connect(asender: action, SIGNAL(triggered()), SLOT(chooseCity()));
107 addAction(action);
108 }
109 setContextMenuPolicy(Qt::ActionsContextMenu);
110
111 connect(sender: &m_manager, SIGNAL(finished(QNetworkReply*)),
112 receiver: this, SLOT(handleNetworkData(QNetworkReply*)));
113
114 QTimer::singleShot(msec: 0, receiver: this, SLOT(delayedInit()));
115 }
116
117private slots:
118 void delayedInit() {
119 request(location: "http://www.yr.no/place/Norge/Oslo/Oslo/Oslo/varsel.xml");
120 }
121
122private slots:
123
124 void chooseCity() {
125 QAction *action = qobject_cast<QAction*>(object: sender());
126 if (action) {
127 if (action->text() == "Oslo") {
128 request(location: "http://www.yr.no/place/Norge/Oslo/Oslo/Oslo/varsel.xml");
129 } else if (action->text() == "Berlin") {
130 request(location: "http://www.yr.no/place/Germany/Berlin/Berlin/varsel.xml");
131 } else if (action->text() == "Moscow") {
132 request(location: "http://www.yr.no/place/Russia/Moscow/Moscow/varsel.xml");
133 } else if (action->text() == "Helsinki") {
134 request(location: "http://www.yr.no/place/Finland/Southern_Finland/Helsinki/varsel.xml");
135 } else if (action->text() == "Santa Clara") {
136 request(location: "http://www.yr.no/place/United_States/California/Santa_Clara/varsel.xml");
137 }
138 }
139 }
140
141 void handleNetworkData(QNetworkReply *networkReply) {
142 QUrl url = networkReply->url();
143 if (!networkReply->error())
144 digest(data: QString::fromUtf8(str: networkReply->readAll()));
145 networkReply->deleteLater();
146 }
147
148 void animate(int frame) {
149 qreal progress = static_cast<qreal>(frame) / 100;
150 m_iconItem->setOpacity(progress);
151 qreal hw = width() / 2.0;
152 m_statusItem->setPos(ax: -hw + hw * progress, ay: 0);
153 for (int i = 0; i < m_forecastItems.count(); ++i) {
154 qreal ofs = i * 0.5 / m_forecastItems.count();
155 qreal alpha = qBound(min: qreal(0), val: 2 * (progress - ofs), max: qreal(1));
156 m_conditionItems[i]->setOpacity(alpha);
157 QPointF pos = m_forecastItems[i]->pos();
158 if (width() > height()) {
159 qreal fx = width() - width() * 0.4 * alpha;
160 m_forecastItems[i]->setPos(ax: fx, ay: pos.y());
161 } else {
162 qreal fx = height() - height() * 0.5 * alpha;
163 m_forecastItems[i]->setPos(ax: pos.x(), ay: fx);
164 }
165 }
166 }
167
168private:
169
170 void setupScene() {
171 QFont textFont = font();
172 textFont.setBold(true);
173 textFont.setPointSize(static_cast<int>(textFont.pointSize() * 1.5));
174
175 m_temperatureItem = m_scene.addText(text: QString(), font: textFont);
176 m_temperatureItem->setDefaultTextColor(TEXTCOLOR);
177
178 m_conditionItem = m_scene.addText(text: QString(), font: textFont);
179 m_conditionItem->setDefaultTextColor(TEXTCOLOR);
180
181 m_cityItem = m_scene.addText(text: QString(), font: textFont);
182 m_cityItem->setDefaultTextColor(TEXTCOLOR);
183
184 m_copyright = m_scene.addText(text: QString());
185 m_copyright->setDefaultTextColor(TEXTCOLOR);
186 m_copyright->setOpenExternalLinks(true);
187 m_copyright->setTextInteractionFlags(Qt::TextBrowserInteraction);
188
189 m_iconItem = new QGraphicsSvgItem;
190 m_scene.addItem(item: m_iconItem);
191
192 m_statusItem = m_scene.addRect(x: 0, y: 0, w: 10, h: 10);
193 m_statusItem->setPen(Qt::NoPen);
194 m_statusItem->setBrush(Qt::NoBrush);
195 m_temperatureItem->setParentItem(m_statusItem);
196 m_conditionItem->setParentItem(m_statusItem);
197 m_iconItem->setParentItem(m_statusItem);
198 m_copyright->setParentItem(m_statusItem);
199
200 connect(asender: &m_timeLine, SIGNAL(frameChanged(int)), SLOT(animate(int)));
201 m_timeLine.setDuration(1100);
202 m_timeLine.setFrameRange(startFrame: 0, endFrame: 100);
203 m_timeLine.setEasingCurve(QEasingCurve::InCurve);
204 }
205
206 void request(const QString &location) {
207 QUrl url(location);
208 m_manager.get(request: QNetworkRequest(url));
209
210 city = QString();
211 setWindowTitle("Loading...");
212 }
213
214 QString extractIcon(const QString &data) {
215 if (m_icons.isEmpty()) {
216 m_icons["Partly cloudy"] = "weather-few-clouds";
217 m_icons["Cloudy"] = "weather-overcast";
218 m_icons["Fair"] = "weather-sunny-very-few-clouds";
219 m_icons["Sun"] = "weather-sunny";
220 m_icons["Sun/clear sky"] = "weather-sunny";
221 m_icons["Clear sky"] = "weather-sunny";
222 m_icons["Snow showers"] = "weather-snow";
223 m_icons["Snow"] = "weather-snow";
224 m_icons["Fog"] = "weather-fog";
225 m_icons["Sleet"] = "weather-sleet";
226 m_icons["Sleet showers"] = "weather-sleet";
227 m_icons["Rain showers"] = "weather-showers";
228 m_icons["Rain"] = "weather-showers";
229 m_icons["Heavy rain"] = "weather-showers";
230 m_icons["Rain showers with thunder"] = "weather-thundershower";
231 m_icons["Rain and thunder"] = "weather-thundershower";
232 m_icons["Sleet and thunder"] = "weather-thundershower";
233 m_icons["Heavy rain and thunder"] = "weather-thundershower";
234 m_icons["Snow and thunder"] = "weather-thundershower";
235 m_icons["Sleet showers and thunder"] = "weather-thundershower";
236 m_icons["Snow showers and thunder"] = "weather-thundershower";
237 }
238 QString name = m_icons.value(key: data);
239 if (!name.isEmpty()) {
240 name.prepend(s: ":/icons/");
241 name.append(s: ".svg");
242 return name;
243 }
244 return QString();
245 }
246
247 void digest(const QString &data) {
248 delete m_iconItem;
249 m_iconItem = new QGraphicsSvgItem();
250 m_scene.addItem(item: m_iconItem);
251 m_iconItem->setParentItem(m_statusItem);
252 m_conditionItem->setPlainText(QString());
253
254 qDeleteAll(c: m_dayItems);
255 qDeleteAll(c: m_conditionItems);
256 qDeleteAll(c: m_rangeItems);
257 qDeleteAll(c: m_forecastItems);
258 m_dayItems.clear();
259 m_conditionItems.clear();
260 m_rangeItems.clear();
261 m_forecastItems.clear();
262
263 QXmlStreamReader xml(data);
264
265 bool foundCurrentForecast = false;
266 while (!xml.atEnd()) {
267 xml.readNext();
268 if (xml.tokenType() == QXmlStreamReader::StartElement) {
269 if (xml.name() == "location") {
270 while (!xml.atEnd()) {
271 xml.readNext();
272 if (xml.tokenType() == QXmlStreamReader::StartElement) {
273 if (xml.name() == "name") {
274 city = xml.readElementText();
275 m_cityItem->setPlainText(city);
276 setWindowTitle(city);
277 xml.skipCurrentElement();
278 break;
279 }
280 }
281 }
282 } else if (xml.name() == "credit") {
283 while (!xml.atEnd()) {
284 xml.readNext();
285 if (xml.tokenType() == QXmlStreamReader::StartElement) {
286 if (xml.name() == "link") {
287 m_copyright->setHtml(QString("<td align=\"center\">%1 <a href=\"%2\">(source)</a></td>").arg(GET_DATA_ATTR("text")).arg(GET_DATA_ATTR("url")));
288 xml.skipCurrentElement();
289 break;
290 }
291 }
292 }
293 } else if (xml.name() == "tabular") {
294 while (!xml.atEnd()) {
295 xml.readNext();
296 if (xml.tokenType() == QXmlStreamReader::StartElement) {
297 if (xml.name() == "time") {
298 if (!foundCurrentForecast) {
299 QString temperature;
300 QString symbol;
301 getSymbolTemp(xml, symbol, temp&: temperature);
302 if (!symbol.isEmpty()) {
303 delete m_iconItem;
304 m_iconItem = new QGraphicsSvgItem(symbol);
305 m_scene.addItem(item: m_iconItem);
306 m_iconItem->setParentItem(m_statusItem);
307 }
308 QString s = FORMAT_TEMPERATURE(temperature);
309 m_temperatureItem->setPlainText(s);
310 foundCurrentForecast = true;
311 } else {
312 createNewDay(xml);
313 }
314
315 }
316 }
317 }
318 } else if (xml.name() != "weatherdata" && xml.name() != "forecast" && xml.name() != "credit"){
319 xml.skipCurrentElement();
320 }
321 }
322 }
323
324
325
326
327
328 m_timeLine.stop();
329 layoutItems();
330 animate(frame: 0);
331 m_timeLine.start();
332 }
333
334 void createNewDay(QXmlStreamReader &xml) {
335 QGraphicsTextItem *dayItem = 0;
336 QString lowT;
337 QString highT;
338 QString period = GET_DATA_ATTR("period");
339 QString datetime;
340 if (period == "0")
341 datetime = GET_DATA_ATTR("to");
342 else
343 datetime = GET_DATA_ATTR("from");
344 QString temperature;
345 QString symbol;
346 getSymbolTemp(xml, symbol, temp&: temperature);
347 lowT = highT = temperature;
348 QDateTime date = GET_DATETIME(datetime);
349 dayItem = m_scene.addText(text: date.date().toString(format: "ddd"));
350 dayItem->setDefaultTextColor(TEXTCOLOR);
351
352 // check for other info same day
353 bool saved = false;
354 while (!xml.atEnd()) {
355 xml.readNext();
356 if (xml.tokenType() == QXmlStreamReader::StartElement) {
357 if (xml.name() == "time") {
358 QString period = GET_DATA_ATTR("period");
359 // save data if new day starts
360 if (period == "0") {
361 saveDayItem(dayItem, lowT, highT, symbolToShow: symbol);
362 createNewDay(xml);
363 saved = true;
364 } else {
365 updateDay(xml, lowT, highT, symbolToShow&: symbol, updateSymbol: period == "2");
366 }
367 }
368 }
369 }
370 if (!saved)// last Item
371 saveDayItem(dayItem, lowT, highT, symbolToShow: symbol);
372 }
373
374 void updateDay(QXmlStreamReader &xml, QString &lowT, QString &highT, QString &symbolToShow, bool updateSymbol) {
375 QString temperature;
376 QString symbol;
377 getSymbolTemp(xml, symbol, temp&: temperature);
378 if (lowT.toFloat() > temperature.toFloat())
379 lowT = temperature;
380 if (highT.toFloat() < temperature.toFloat())
381 highT = temperature;
382 if (updateSymbol)
383 symbolToShow = symbol;
384 }
385
386 void saveDayItem(QGraphicsTextItem *dayItem, QString lowT, QString highT, QString symbolToShow) {
387 QGraphicsSvgItem *statusItem = 0;
388 if (!symbolToShow.isEmpty()) {
389 statusItem = new QGraphicsSvgItem(symbolToShow);
390 m_scene.addItem(item: statusItem);
391 }
392 if (m_dayItems.count() < 4 && dayItem && statusItem && // Show 4 days
393 !lowT.isEmpty() && !highT.isEmpty()) {
394 m_dayItems << dayItem;
395 m_conditionItems << statusItem;
396 QString txt = FORMAT_TEMPERATURE(lowT) + '/' + FORMAT_TEMPERATURE(highT);
397 QGraphicsTextItem* rangeItem;
398 rangeItem = m_scene.addText(text: txt);
399 rangeItem->setDefaultTextColor(TEXTCOLOR);
400 m_rangeItems << rangeItem;
401 QGraphicsRectItem *box;
402 box = m_scene.addRect(x: 0, y: 0, w: 10, h: 10);
403 box->setPen(Qt::NoPen);
404 box->setBrush(Qt::NoBrush);
405 m_forecastItems << box;
406 dayItem->setParentItem(box);
407 statusItem->setParentItem(box);
408 rangeItem->setParentItem(box);
409 } else {
410 delete dayItem;
411 delete statusItem;
412 }
413 }
414
415 void getSymbolTemp(QXmlStreamReader &xml, QString &symbol, QString &temp) {
416 bool foundIcon = false;
417 bool foundTemp = false;
418 while (!xml.atEnd()) {
419 xml.readNext();
420 if (xml.tokenType() == QXmlStreamReader::StartElement) {
421 if (xml.name() == "symbol") {
422 QString condition = GET_DATA_ATTR("name");
423 symbol = extractIcon(data: condition);
424 if (m_conditionItem->toPlainText().isEmpty())
425 m_conditionItem->setPlainText(condition);
426 foundIcon = true;
427 }
428 if (xml.name() == "temperature") {
429 temp = GET_DATA_ATTR("value");
430 foundTemp = true;
431 }
432 if (foundIcon && foundTemp)
433 break;
434 }
435 }
436 }
437
438
439 void layoutItems() {
440 m_scene.setSceneRect(x: 0, y: 0, w: width() - 1, h: height() - 1);
441 m_view->centerOn(ax: width() / 2, ay: height() / 2);
442 if (width() > height())
443 layoutItemsLandscape();
444 else
445 layoutItemsPortrait();
446 }
447
448 void layoutItemsLandscape() {
449 qreal statusItemWidth = width() / 2 - 1;
450 m_statusItem->setRect(ax: 0, ay: 0, w: statusItemWidth, h: height() - 1);
451
452 m_temperatureItem->setPos(ax: 10, ay: 2);
453 qreal wtemp = m_temperatureItem->boundingRect().width();
454 qreal h1 = m_conditionItem->boundingRect().height();
455 m_conditionItem->setPos(ax: wtemp + 20, ay: 2);
456
457 m_copyright->setTextWidth(statusItemWidth);
458
459 qreal wcity = m_cityItem->boundingRect().width();
460 m_cityItem->setPos(ax: statusItemWidth - wcity - 1, ay: 2);;
461
462 qreal h2 = m_copyright->boundingRect().height();
463 m_copyright->setPos(ax: 0, ay: height() - h2);
464
465 if (!m_iconItem->boundingRect().isEmpty()) {
466 qreal sizeLeft = qMin(a: statusItemWidth, b: height() - h2 - h1 - 10);
467 qreal sw = sizeLeft / m_iconItem->boundingRect().width();
468 qreal sh = sizeLeft / m_iconItem->boundingRect().height();
469 m_iconItem->setTransform(matrix: QTransform().scale(sx: sw, sy: sh));
470 m_iconItem->setPos(ax: statusItemWidth/2 - sizeLeft/2, ay: h1 + 5);
471 }
472
473 if (m_dayItems.count()) {
474 qreal left = width() * 0.6;
475 qreal statusWidth = 0;
476 qreal rangeWidth = 0;
477 qreal h = height() / m_dayItems.count();
478 for (int i = 0; i < m_dayItems.count(); ++i) {
479 QRectF brect = m_dayItems[i]->boundingRect();
480 statusWidth = qMax(a: statusWidth, b: brect.width());
481 brect = m_rangeItems[i]->boundingRect();
482 rangeWidth = qMax(a: rangeWidth, b: brect.width());
483 }
484 qreal space = width() - left - statusWidth - rangeWidth;
485 qreal dim = qMin(a: h, b: space);
486 qreal pad = statusWidth + (space - dim) / 2;
487 for (int i = 0; i < m_dayItems.count(); ++i) {
488 qreal base = h * i;
489 m_forecastItems[i]->setPos(ax: left, ay: base);
490 m_forecastItems[i]->setRect(ax: 0, ay: 0, w: width() - left, h);
491 QRectF brect = m_dayItems[i]->boundingRect();
492 qreal ofs = (h - brect.height()) / 2;
493 m_dayItems[i]->setPos(ax: 0, ay: ofs);
494 brect = m_rangeItems[i]->boundingRect();
495 ofs = (h - brect.height()) / 2;
496 m_rangeItems[i]->setPos(ax: width() - rangeWidth - left, ay: ofs);
497 brect = m_conditionItems[i]->boundingRect();
498 ofs = (h - dim) / 2;
499 m_conditionItems[i]->setPos(ax: pad, ay: ofs);
500 if (brect.isEmpty())
501 continue;
502 qreal sw = dim / brect.width();
503 qreal sh = dim / brect.height();
504 m_conditionItems[i]->setTransform(matrix: QTransform().scale(sx: sw, sy: sh));
505 }
506 }
507 }
508
509 void layoutItemsPortrait() {
510 qreal statusItemWidth = width() - 1;
511 m_statusItem->setRect(ax: 0, ay: 0, w: statusItemWidth, h: height() / 2 - 1);
512
513 m_temperatureItem->setPos(ax: 10, ay: 2);
514 qreal wtemp = m_temperatureItem->boundingRect().width();
515 qreal h1 = m_conditionItem->boundingRect().height();
516 m_conditionItem->setPos(ax: wtemp + 20, ay: 2);
517
518 m_copyright->setTextWidth(statusItemWidth);
519
520 qreal wcity = m_cityItem->boundingRect().width();
521 m_cityItem->setPos(ax: statusItemWidth - wcity - 1, ay: 2);;
522
523 m_copyright->setTextWidth(statusItemWidth);
524 qreal h2 = m_copyright->boundingRect().height();
525 m_copyright->setPos(ax: 0, ay: height() - h2);
526
527 if (m_dayItems.count()) {
528 qreal top = height() * 0.5;
529 qreal w = width() / m_dayItems.count();
530 qreal statusHeight = 0;
531 qreal rangeHeight = 0;
532 for (int i = 0; i < m_dayItems.count(); ++i) {
533 m_dayItems[i]->setFont(font());
534 QRectF brect = m_dayItems[i]->boundingRect();
535 statusHeight = qMax(a: statusHeight, b: brect.height());
536 brect = m_rangeItems[i]->boundingRect();
537 rangeHeight = qMax(a: rangeHeight, b: brect.height());
538 }
539 qreal space = height() - top - statusHeight - rangeHeight;
540 qreal dim = qMin(a: w, b: space);
541
542 qreal boxh = statusHeight + rangeHeight + dim;
543 qreal pad = (height() - top - boxh) / 2;
544
545 if (!m_iconItem->boundingRect().isEmpty()) {
546 qreal sizeLeft = qMin(a: statusItemWidth - 10, b: height() - top - 10);
547 qreal sw = sizeLeft / m_iconItem->boundingRect().width();
548 qreal sh = sizeLeft / m_iconItem->boundingRect().height();
549 m_iconItem->setTransform(matrix: QTransform().scale(sx: sw, sy: sh));
550 m_iconItem->setPos(ax: statusItemWidth/2 - sizeLeft/2, ay: h1 + 5);
551 }
552
553 for (int i = 0; i < m_dayItems.count(); ++i) {
554 qreal base = w * i;
555 m_forecastItems[i]->setPos(ax: base, ay: top);
556 m_forecastItems[i]->setRect(ax: 0, ay: 0, w, h: boxh);
557 QRectF brect = m_dayItems[i]->boundingRect();
558 qreal ofs = (w - brect.width()) / 2;
559 m_dayItems[i]->setPos(ax: ofs, ay: pad);
560
561 brect = m_rangeItems[i]->boundingRect();
562 ofs = (w - brect.width()) / 2;
563 m_rangeItems[i]->setPos(ax: ofs, ay: pad + statusHeight + dim);
564
565 brect = m_conditionItems[i]->boundingRect();
566 ofs = (w - dim) / 2;
567 m_conditionItems[i]->setPos(ax: ofs, ay: pad + statusHeight);
568 if (brect.isEmpty())
569 continue;
570 qreal sw = dim / brect.width();
571 qreal sh = dim / brect.height();
572 m_conditionItems[i]->setTransform(matrix: QTransform().scale(sx: sw, sy: sh));
573 }
574 }
575 }
576
577
578 void resizeEvent(QResizeEvent *event) override {
579 Q_UNUSED(event);
580 layoutItems();
581 }
582
583};
584
585#include "weatherinfo.moc"
586
587int main(int argc, char *argv[])
588{
589 QApplication app(argc, argv);
590
591 WeatherInfo w;
592 w.resize(w: 520, h: 288);
593 w.show();
594
595 return app.exec();
596}
597

source code of qtsvg/examples/svg/embedded/weatherinfo/weatherinfo.cpp