From 030635a554511669baa09445cc9b11cb18e40539 Mon Sep 17 00:00:00 2001 From: Liang Jian Date: Wed, 28 May 2014 15:46:51 +0800 Subject: Fix Stmt:Data object leak call Stmt::destroyData() whenever a Stmt object is to be removed in BasicBlock to delete the Stmt::Data object hold in the Stmt object. Change-Id: I59c939d79b935153e6f8613e54f149120f5198f5 Reviewed-by: Lars Knoll Reviewed-by: Erik Verbruggen --- src/qml/compiler/qv4jsir.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 5d30d6e3b9..f81985c07d 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -1049,6 +1049,11 @@ void BasicBlock::setStatements(const QVector &newStatements) { Q_ASSERT(!isRemoved()); Q_ASSERT(newStatements.size() >= _statements.size()); + // FIXME: this gets quite inefficient for large basic-blocks, so this function/case should be re-worked. + foreach (Stmt *s, _statements) { + if (!newStatements.contains(s)) + s->destroyData(); + } _statements = newStatements; } @@ -1088,18 +1093,21 @@ void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt) void BasicBlock::replaceStatement(int index, Stmt *newStmt) { Q_ASSERT(!isRemoved()); + _statements[index]->destroyData(); _statements[index] = newStmt; } void BasicBlock::removeStatement(Stmt *stmt) { Q_ASSERT(!isRemoved()); + stmt->destroyData(); _statements.remove(_statements.indexOf(stmt)); } void BasicBlock::removeStatement(int idx) { Q_ASSERT(!isRemoved()); + _statements[idx]->destroyData(); _statements.remove(idx); } -- cgit v1.2.3 -- cgit v1.2.3 From df2c91bfb1e70937725bf2da760dc9475cb04105 Mon Sep 17 00:00:00 2001 From: Niels Weber Date: Fri, 13 Jun 2014 13:27:45 +0200 Subject: Use newest QtQuick in rssnews demo Task-number: QTBUG-37203 Change-Id: I720e510b875f63eb5c184cd7d8b9eb127674d505 Reviewed-by: Alessandro Portale --- examples/quick/demos/rssnews/content/BusyIndicator.qml | 4 ++-- examples/quick/demos/rssnews/content/CategoryDelegate.qml | 4 ++-- examples/quick/demos/rssnews/content/NewsDelegate.qml | 4 ++-- examples/quick/demos/rssnews/content/RssFeeds.qml | 4 ++-- examples/quick/demos/rssnews/content/ScrollBar.qml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/quick/demos/rssnews/content/BusyIndicator.qml b/examples/quick/demos/rssnews/content/BusyIndicator.qml index c16f582c40..d9c3646ae3 100644 --- a/examples/quick/demos/rssnews/content/BusyIndicator.qml +++ b/examples/quick/demos/rssnews/content/BusyIndicator.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,7 +39,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 Image { id: container diff --git a/examples/quick/demos/rssnews/content/CategoryDelegate.qml b/examples/quick/demos/rssnews/content/CategoryDelegate.qml index 31dd9c0d3b..bb2b3581df 100644 --- a/examples/quick/demos/rssnews/content/CategoryDelegate.qml +++ b/examples/quick/demos/rssnews/content/CategoryDelegate.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,7 +39,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 Item { id: delegate diff --git a/examples/quick/demos/rssnews/content/NewsDelegate.qml b/examples/quick/demos/rssnews/content/NewsDelegate.qml index ec39510eba..feb0516653 100644 --- a/examples/quick/demos/rssnews/content/NewsDelegate.qml +++ b/examples/quick/demos/rssnews/content/NewsDelegate.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,7 +39,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 Item { id: delegate diff --git a/examples/quick/demos/rssnews/content/RssFeeds.qml b/examples/quick/demos/rssnews/content/RssFeeds.qml index 50bc771192..425b011a78 100644 --- a/examples/quick/demos/rssnews/content/RssFeeds.qml +++ b/examples/quick/demos/rssnews/content/RssFeeds.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,7 +39,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 ListModel { id: rssFeeds diff --git a/examples/quick/demos/rssnews/content/ScrollBar.qml b/examples/quick/demos/rssnews/content/ScrollBar.qml index d3cf4a6851..b8f1b730e0 100644 --- a/examples/quick/demos/rssnews/content/ScrollBar.qml +++ b/examples/quick/demos/rssnews/content/ScrollBar.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. @@ -39,7 +39,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 Item { id: container -- cgit v1.2.3 From 1e39eb5f701977ac3ea4b6d66f2ce304931a1085 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 13 Jun 2014 13:59:57 +0200 Subject: Separate renderer out in "OpenGL under QML" example. The example was promoting very bad practice. Change-Id: Ibb83780ec33e59ee5aabf65a775705dd0da681e6 Reviewed-by: Laszlo Agocs --- .../openglunderqml/doc/src/openglunderqml.qdoc | 113 ++++++++++----------- .../quick/scenegraph/openglunderqml/squircle.cpp | 74 +++++++------- .../quick/scenegraph/openglunderqml/squircle.h | 32 ++++-- 3 files changed, 115 insertions(+), 104 deletions(-) diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 1f87412aa4..de023ff95c 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -50,54 +50,40 @@ in the QML file and this value is used by the OpenGL shader program that draws the squircles. + \snippet scenegraph/openglunderqml/squircle.h 2 + + First of all, we need an object we can expose to QML. This is a + subclass of QQuickItem so we can easily access \l QQuickItem::window(). + \snippet scenegraph/openglunderqml/squircle.h 1 - First of all, we need a QObject with a slot to connect the signals - to. We subclass QQuickItem in order to use the \l - QQuickItem::window() which holds the window instance we want to - connect to. - - We use two values of \c t. The variable \c m_t is the property - value as it exists in the GUI thread. The \c m_thread_t value is a - copy of \c m_t for use in the rendering thread. We need an - explicit copy because the scene graph can render in one thread - while updating properties on the GUI thread in preparation for the - next frame. If we had used only one value, the animation could - have updated the value to that of the next frame before we got a - chance to render it. - - \note In this example, a wrong value for \c t will have minimal - consequences, but we emphasize that rendering and GUI thread - objects and values must stay separate to avoid race conditions, - undesired behavior and in the worst case, crashes. + Then we need an object to take care of the rendering. This + instance needs to be separated from the QQuickItem because the + item lives in the GUI thread and the rendering potentially happens + on the render thread. Since we want to connect to \l + QQuickWindow::beforeRendering(), we make the renderer a QObject. + The renderer contains a copy of all the state it needs, + independent of the GUI thread. + + \note Don't be tempted to merge the two objects into + one. QQuickItems may be deleted on the GUI thread while the render + thread is rendering. Lets move on to the implementation. \snippet scenegraph/openglunderqml/squircle.cpp 7 The constructor of the \c Squircle class simply initializes the - values. The shader program will be initialized during rendering - later. - - \snippet scenegraph/openglunderqml/squircle.cpp 8 - - The property setter checks that the value has indeed changed - before updating its internal variable. It then calls \l - QQuickWindow::update() which will trigger another frame to be - rendered. Note that the setter might be called during - initialization, before the object has been entered into the scene - and before it has a window. + values and connects to the window changed signal which we will use + to prepare our renderer. \snippet scenegraph/openglunderqml/squircle.cpp 1 - \snippet scenegraph/openglunderqml/squircle.cpp 2 - For our paint function to be called, we need to connect to the - window's signals. When Squircle object is populated into the - scene, the windowChanged signal is emitted. In our handler, - we connect \l QQuickWindow::beforeRendering() to - \c paint() to do the rendering, and \l - QQuickWindow::beforeSynchronizing() to \c sync() to copy the state - of the \c t property for the upcoming frame. + Once we have a window, we attach to the \l + QQuickWindow::beforeSynchronizing() signal which we will use to + create the renderer and to copy state into it safely. We also + connect to the \l QQuickWindow::sceneGraphInvalidated() signal to + handle the cleanup of the renderer. \note Since the Squircle object has affinity to the GUI thread and the signals are emitted from the rendering thread, it is crucial @@ -113,18 +99,35 @@ graph, we need to turn this clearing off. This means that we need to clear ourselves in the \c paint() function. - \snippet scenegraph/openglunderqml/squircle.cpp 4 + \snippet scenegraph/openglunderqml/squircle.cpp 9 + + We use the \c sync() function to initialize the renderer and to + copy the state in our item into the renderer. When the renderer is + created, we also connect the \l QQuickWindow::beforeRendering() to + the renderer's \c paint() slot. - The first thing we do in the \c paint() function is to - initialize the shader program. By initializing the shader program - here, we make sure that the OpenGL context is bound and that we - are on the correct thread. + \note The \l QQuickWindow::beforeSynchronizing() signal is emitted + on the rendering thread while the GUI thread is blocked, so it is + safe to simply copy the value without any additional protection. - We also connect to the QOpenGLContext::aboutToBeDestroyed() - signal, so that we can clean up the shader program when the - context is destroyed. Again, this is a \l Qt::DirectConnection as - all rendering related operations must happen on the rendering - thread. + \snippet scenegraph/openglunderqml/squircle.cpp 6 + + In the \c cleanup() function we delete the renderer which in turn + cleans up its own resources. + + \snippet scenegraph/openglunderqml/squircle.cpp 8 + + When the value of \c t changes, we call \l QQuickWindow::update() + rather than \l QQuickItem::update() because the former will force + the entire window to be redrawn, even when the scene graph has not + changed since the last frame. + + \snippet scenegraph/openglunderqml/squircle.cpp 4 + + In the SquircleRenderer's \c paint() function we start by + initializing the shader program. By initializing the shader + program here, we make sure that the OpenGL context is bound and + that we are on the correct thread. \snippet scenegraph/openglunderqml/squircle.cpp 5 @@ -133,18 +136,10 @@ attributes we used so that the OpenGL context is in a "clean" state for the scene graph to pick it up. - \snippet scenegraph/openglunderqml/squircle.cpp 6 - - In the \c cleanup() function we delete the program. - - \snippet scenegraph/openglunderqml/squircle.cpp 9 - - We use the \c sync() function to copy the state of the - object in the GUI thread into the rendering thread. - - The signal is emitted on the rendering thread while the GUI - thread is blocked, so it is safe to simply copy the value without - any additional protection. + \note If tracking the changes in the OpenGL context's state is not + feasible, one can use the function \l + QQuickWindow::resetOpenGLState() which will reset all state that + the scene graph relies on. \snippet scenegraph/openglunderqml/main.cpp 1 diff --git a/examples/quick/scenegraph/openglunderqml/squircle.cpp b/examples/quick/scenegraph/openglunderqml/squircle.cpp index 91d69c90a4..4b892e3761 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.cpp +++ b/examples/quick/scenegraph/openglunderqml/squircle.cpp @@ -47,9 +47,8 @@ //! [7] Squircle::Squircle() - : m_program(0) - , m_t(0) - , m_thread_t(0) + : m_t(0) + , m_renderer(0) { connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*))); } @@ -71,24 +70,46 @@ void Squircle::setT(qreal t) void Squircle::handleWindowChanged(QQuickWindow *win) { if (win) { -//! [1] - // Connect the beforeRendering signal to our paint function. - // Since this call is executed on the rendering thread it must be - // a Qt::DirectConnection -//! [2] - connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection); connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection); -//! [2] - + connect(win, SIGNAL(sceneGraphInvalidated()), this, SLOT(cleanup()), Qt::DirectConnection); +//! [1] // If we allow QML to do the clearing, they would clear what we paint // and nothing would show. //! [3] win->setClearBeforeRendering(false); } } +//! [3] + +//! [6] +void Squircle::cleanup() +{ + if (m_renderer) { + delete m_renderer; + m_renderer = 0; + } +} -//! [3] //! [4] -void Squircle::paint() +SquircleRenderer::~SquircleRenderer() +{ + delete m_program; +} +//! [6] + +//! [9] +void Squircle::sync() +{ + if (!m_renderer) { + m_renderer = new SquircleRenderer(); + connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection); + } + m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio()); + m_renderer->setT(m_t); +} +//! [9] + +//! [4] +void SquircleRenderer::paint() { if (!m_program) { m_program = new QOpenGLShaderProgram(); @@ -112,8 +133,6 @@ void Squircle::paint() m_program->bindAttributeLocation("vertices", 0); m_program->link(); - connect(window()->openglContext(), SIGNAL(aboutToBeDestroyed()), - this, SLOT(cleanup()), Qt::DirectConnection); } //! [4] //! [5] m_program->bind(); @@ -127,12 +146,9 @@ void Squircle::paint() 1, 1 }; m_program->setAttributeArray(0, GL_FLOAT, values, 2); - m_program->setUniformValue("t", (float) m_thread_t); + m_program->setUniformValue("t", (float) m_t); - qreal ratio = window()->devicePixelRatio(); - int w = int(ratio * window()->width()); - int h = int(ratio * window()->height()); - glViewport(0, 0, w, h); + glViewport(0, 0, m_viewportSize.width(), m_viewportSize.height()); glDisable(GL_DEPTH_TEST); @@ -148,21 +164,3 @@ void Squircle::paint() m_program->release(); } //! [5] - -//! [6] -void Squircle::cleanup() -{ - if (m_program) { - delete m_program; - m_program = 0; - } -} -//! [6] - -//! [9] -void Squircle::sync() -{ - m_thread_t = m_t; -} -//! [9] - diff --git a/examples/quick/scenegraph/openglunderqml/squircle.h b/examples/quick/scenegraph/openglunderqml/squircle.h index 449e02bbf1..aa50908242 100644 --- a/examples/quick/scenegraph/openglunderqml/squircle.h +++ b/examples/quick/scenegraph/openglunderqml/squircle.h @@ -45,11 +45,32 @@ #include #include + + +//! [1] +class SquircleRenderer : public QObject { + Q_OBJECT +public: + SquircleRenderer() : m_t(0), m_program(0) { } + ~SquircleRenderer(); + + void setT(qreal t) { m_t = t; } + void setViewportSize(const QSize &size) { m_viewportSize = size; } + +public slots: + void paint(); + +private: + QSize m_viewportSize; + qreal m_t; + QOpenGLShaderProgram *m_program; +}; //! [1] + +//! [2] class Squircle : public QQuickItem { Q_OBJECT - Q_PROPERTY(qreal t READ t WRITE setT NOTIFY tChanged) public: @@ -62,19 +83,16 @@ signals: void tChanged(); public slots: - void paint(); - void cleanup(); void sync(); + void cleanup(); private slots: void handleWindowChanged(QQuickWindow *win); private: - QOpenGLShaderProgram *m_program; - qreal m_t; - qreal m_thread_t; + SquircleRenderer *m_renderer; }; -//! [1] +//! [2] #endif // SQUIRCLE_H -- cgit v1.2.3 From 3bc827feb38f0d90f6c2254eb0816504b8e1c2cb Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 18 Jun 2014 00:28:50 +0200 Subject: Bump version Change-Id: I48d18a93971f4595b295aa6a1f70dfbe2b2266a1 --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index d170e6d272..effef04600 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) CONFIG += qt_example_installs CONFIG += warning_clean -MODULE_VERSION = 5.3.1 +MODULE_VERSION = 5.3.2 -- cgit v1.2.3 From bbd8080e952e7fd4c98dd67a1523dd8fd1c0c006 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 18 Jun 2014 10:27:05 +0200 Subject: Add changelog for 5.3.1 Change-Id: I5d9c67a2f89c0c191de9e6de24d068fca17dba0e Reviewed-by: Jani Heikkinen --- dist/changes-5.3.1 | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 dist/changes-5.3.1 diff --git a/dist/changes-5.3.1 b/dist/changes-5.3.1 new file mode 100644 index 0000000000..f015cb804c --- /dev/null +++ b/dist/changes-5.3.1 @@ -0,0 +1,31 @@ +Qt 5.3.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.3.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + http://qt-project.org/doc/qt-5.3 + +The Qt version 5.3 series is binary compatible with the 5.2.x series. +Applications compiled for 5.2 will continue to run with 5.3. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + http://bugreports.qt-project.org/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Library * +**************************************************************************** + + +QtQuick +------- + + - Platform Specific Changes: + * Added canPaste property to TextInput element also on platforms that + don't support a clipboard (QT_NO_CLIPBOARD is defined). + -- cgit v1.2.3 From fdedb07d73c3bf8e816fc0bb99497576bb3f89f9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 16 Jun 2014 11:21:01 +0200 Subject: Use QSignalSpy instead of waitFor in tst_qpacketprotocol QTcpServer::waitForNewConnection() blocks the event loop and prevents the client, that runs in the same event loop, from sending anything. Also, if the connection is established before waitForNewConnection() is called we're going to wait for another connection, which will never happen. It's not clear if this is actually the cause of the test failures but blocking the event loop is generally a bad idea and the last change to the test that actually made a difference to the functionality added exactly that line, see b36bbe3626bc68ac267d7653fa6408a8f258251d. Task-number: QTBUG-39655 Change-Id: Ic03a4e7cac78155532588476b99449664c343ee2 Reviewed-by: Simon Hausmann --- tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp index 26919af1b6..f91d0135a9 100644 --- a/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp +++ b/tests/auto/qml/debugger/qpacketprotocol/tst_qpacketprotocol.cpp @@ -84,10 +84,15 @@ void tst_QPacketProtocol::init() QVERIFY(m_server->listen(QHostAddress("127.0.0.1"))); m_client = new QTcpSocket(this); + + QSignalSpy serverSpy(m_server, SIGNAL(newConnection())); + QSignalSpy clientSpy(m_client, SIGNAL(connected())); + m_client->connectToHost(m_server->serverAddress(), m_server->serverPort()); - QVERIFY(m_client->waitForConnected()); - QVERIFY(m_server->waitForNewConnection(10000)); + QVERIFY(clientSpy.count() > 0 || clientSpy.wait()); + QVERIFY(serverSpy.count() > 0 || serverSpy.wait()); + m_serverConn = m_server->nextPendingConnection(); } -- cgit v1.2.3 From a560018d08d4212bc65c163eb608639f19b38df2 Mon Sep 17 00:00:00 2001 From: Oleg Shparber Date: Tue, 17 Jun 2014 15:47:43 -0700 Subject: Fix crash in QObjectWrapper This can happen during QObject destruction, when QObjectPrivate::deleteChildren() itself sets entries in the children list to zero when deleting. These zeros cause crash in markChildQObjectsRecursively(). Task-number: QTBUG-38635 Change-Id: I29ad9e793b78ca4e8d73fbb125f46db1b8292f20 Reviewed-by: Alan Alpert --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index a02424a3dc..d64f821a38 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -962,6 +962,8 @@ static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine * const QObjectList &children = parent->children(); for (int i = 0; i < children.count(); ++i) { QObject *child = children.at(i); + if (!child) + continue; QQmlData *ddata = QQmlData::get(child, /*create*/false); if (ddata) ddata->jsWrapper.markOnce(e); -- cgit v1.2.3 From 2bc44ba16bb86bd7ebc7eb59ae78eda80a737984 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 6 Jun 2014 16:53:33 +0200 Subject: Add a QQuickWidget - QQuickView comparison example Besides serving as a side-by-side test tool for QQuickView and QQuickWidget (including multisampling), it also demonstrates some useful practices for rendering 3D content via QQuickFramebufferObject. Done-with: Paul Olav Tvete Change-Id: Ie73e998ee91e32ef1535dd6f0f65c8a69addcc5e Reviewed-by: Paul Olav Tvete --- .../quickwidgets/qquickviewcomparison/fbitem.cpp | 273 +++++++++++++++++++++ .../quickwidgets/qquickviewcomparison/fbitem.h | 136 ++++++++++ .../quickwidgets/qquickviewcomparison/logo.cpp | 141 +++++++++++ .../quick/quickwidgets/qquickviewcomparison/logo.h | 65 +++++ .../quickwidgets/qquickviewcomparison/main.cpp | 56 +++++ .../qquickviewcomparison/mainwindow.cpp | 216 ++++++++++++++++ .../quickwidgets/qquickviewcomparison/mainwindow.h | 80 ++++++ .../qquickviewcomparison/qquickviewcomparison.pro | 17 ++ .../qquickviewcomparison/qquickviewcomparison.qrc | 5 + .../quickwidgets/qquickviewcomparison/test.qml | 210 ++++++++++++++++ examples/quick/quickwidgets/quickwidgets.pro | 3 +- 11 files changed, 1201 insertions(+), 1 deletion(-) create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/fbitem.h create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/logo.cpp create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/logo.h create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/main.cpp create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc create mode 100644 examples/quick/quickwidgets/qquickviewcomparison/test.qml diff --git a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp new file mode 100644 index 0000000000..3b9f2e97f3 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fbitem.h" +#include +#include +#include + +FbItem::FbItem(QQuickItem *parent) + : QQuickFramebufferObject(parent), + m_target(0, 0, -1), + m_syncState(AllNeedsSync), + m_multisample(false) +{ +} + +QQuickFramebufferObject::Renderer *FbItem::createRenderer() const +{ + return new FbItemRenderer(m_multisample); +} + +void FbItem::setEye(const QVector3D &v) +{ + if (m_eye != v) { + m_eye = v; + m_syncState |= CameraNeedsSync; + update(); + } +} + +void FbItem::setTarget(const QVector3D &v) +{ + if (m_target != v) { + m_target = v; + m_syncState |= CameraNeedsSync; + update(); + } +} + +void FbItem::setRotation(const QVector3D &v) +{ + if (m_rotation != v) { + m_rotation = v; + m_syncState |= RotationNeedsSync; + update(); + } +} + +int FbItem::swapSyncState() +{ + int s = m_syncState; + m_syncState = 0; + return s; +} + +FbItemRenderer::FbItemRenderer(bool multisample) + : m_inited(false), + m_multisample(multisample), + m_dirty(DirtyAll) +{ + m_camera.setToIdentity(); + m_baseWorld.setToIdentity(); + m_baseWorld.translate(0, 0, -1); + m_world = m_baseWorld; +} + +void FbItemRenderer::synchronize(QQuickFramebufferObject *qfbitem) +{ + FbItem *item = static_cast(qfbitem); + int syncState = item->swapSyncState(); + if (syncState & FbItem::CameraNeedsSync) { + m_camera.setToIdentity(); + m_camera.lookAt(item->eye(), item->eye() + item->target(), QVector3D(0, 1, 0)); + m_dirty |= DirtyCamera; + } + if (syncState & FbItem::RotationNeedsSync) { + m_rotation = item->rotation(); + m_dirty |= DirtyWorld; + } +} + +struct StateBinder +{ + StateBinder(FbItemRenderer *r) + : m_r(r) { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnable(GL_DEPTH_TEST); + f->glEnable(GL_CULL_FACE); + f->glDepthMask(GL_TRUE); + f->glDepthFunc(GL_LESS); + f->glFrontFace(GL_CCW); + f->glCullFace(GL_BACK); + m_r->m_program->bind(); + } + ~StateBinder() { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + m_r->m_program->release(); + f->glDisable(GL_CULL_FACE); + f->glDisable(GL_DEPTH_TEST); + } + FbItemRenderer *m_r; +}; + +void FbItemRenderer::updateDirtyUniforms() +{ + if (m_dirty & DirtyProjection) + m_program->setUniformValue(m_projMatrixLoc, m_proj); + + if (m_dirty & DirtyCamera) + m_program->setUniformValue(m_camMatrixLoc, m_camera); + + if (m_dirty & DirtyWorld) { + m_program->setUniformValue(m_worldMatrixLoc, m_world); + QMatrix3x3 normalMatrix = m_world.normalMatrix(); + m_program->setUniformValue(m_normalMatrixLoc, normalMatrix); + } + + if (m_dirty & DirtyLight) + m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 70)); + + m_dirty = 0; +} + +void FbItemRenderer::render() +{ + ensureInit(); + + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + if (!m_vao.isCreated()) + setupVertexAttribs(); + + StateBinder state(this); + + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glClearColor(0, 0, 0, 0); + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (m_dirty & DirtyWorld) { + m_world = m_baseWorld; + m_world.rotate(m_rotation.x(), 1, 0, 0); + m_world.rotate(m_rotation.y(), 0, 1, 0); + m_world.rotate(m_rotation.z(), 0, 0, 1); + } + + updateDirtyUniforms(); + + f->glDrawArrays(GL_TRIANGLES, 0, m_logo.vertexCount()); +} + +QOpenGLFramebufferObject *FbItemRenderer::createFramebufferObject(const QSize &size) +{ + m_dirty |= DirtyProjection; + m_proj.setToIdentity(); + m_proj.perspective(45.0f, GLfloat(size.width()) / size.height(), 0.01f, 100.0f); + + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + format.setSamples(m_multisample ? 4 : 0); + return new QOpenGLFramebufferObject(size, format); +} + +void FbItemRenderer::ensureInit() +{ + if (m_inited) + return; + + m_inited = true; + + initBuf(); + initProgram(); +} + +void FbItemRenderer::initBuf() +{ + m_vao.create(); + QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao); + + m_logoVbo.create(); + m_logoVbo.bind(); + m_logoVbo.allocate(m_logo.constData(), m_logo.count() * sizeof(GLfloat)); + + setupVertexAttribs(); +} + +void FbItemRenderer::setupVertexAttribs() +{ + m_logoVbo.bind(); + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + f->glEnableVertexAttribArray(0); + f->glEnableVertexAttribArray(1); + f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), 0); + f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast(3 * sizeof(GLfloat))); + m_logoVbo.release(); +} + +static const char *vertexShaderSource = + "attribute vec4 vertex;\n" + "attribute vec3 normal;\n" + "varying vec3 vert;\n" + "varying vec3 vertNormal;\n" + "uniform mat4 projMatrix;\n" + "uniform mat4 camMatrix;\n" + "uniform mat4 worldMatrix;\n" + "uniform mat3 normalMatrix;\n" + "void main() {\n" + " vert = vertex.xyz;\n" + " vertNormal = normalMatrix * normal;\n" + " gl_Position = projMatrix * camMatrix * worldMatrix * vertex;\n" + "}\n"; + +static const char *fragmentShaderSource = + "varying highp vec3 vert;\n" + "varying highp vec3 vertNormal;\n" + "uniform highp vec3 lightPos;\n" + "void main() {\n" + " highp vec3 L = normalize(lightPos - vert);\n" + " highp float NL = max(dot(normalize(vertNormal), L), 0.0);\n" + " highp vec3 color = vec3(0.39, 1.0, 0.0);\n" + " highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);\n" + " gl_FragColor = vec4(col, 1.0);\n" + "}\n"; + +void FbItemRenderer::initProgram() +{ + m_program.reset(new QOpenGLShaderProgram); + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("normal", 1); + m_program->link(); + m_projMatrixLoc = m_program->uniformLocation("projMatrix"); + m_camMatrixLoc = m_program->uniformLocation("camMatrix"); + m_worldMatrixLoc = m_program->uniformLocation("worldMatrix"); + m_normalMatrixLoc = m_program->uniformLocation("normalMatrix"); + m_lightPosLoc = m_program->uniformLocation("lightPos"); +} diff --git a/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h new file mode 100644 index 0000000000..b29998c253 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/fbitem.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FBITEM_H +#define FBITEM_H + +#include +#include +#include +#include +#include +#include "logo.h" + +struct StateBinder; + +class FbItemRenderer : public QQuickFramebufferObject::Renderer +{ +public: + FbItemRenderer(bool multisample); + void synchronize(QQuickFramebufferObject *item) Q_DECL_OVERRIDE; + void render() Q_DECL_OVERRIDE; + QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) Q_DECL_OVERRIDE; + +private: + void ensureInit(); + void initBuf(); + void setupVertexAttribs(); + void initProgram(); + void updateDirtyUniforms(); + + bool m_inited; + bool m_multisample; + QMatrix4x4 m_proj; + QMatrix4x4 m_camera; + QMatrix4x4 m_baseWorld; + QMatrix4x4 m_world; + QOpenGLVertexArrayObject m_vao; + QOpenGLBuffer m_logoVbo; + Logo m_logo; + QScopedPointer m_program; + int m_projMatrixLoc; + int m_camMatrixLoc; + int m_worldMatrixLoc; + int m_normalMatrixLoc; + int m_lightPosLoc; + QVector3D m_rotation; + + enum Dirty { + DirtyProjection = 0x01, + DirtyCamera = 0x02, + DirtyWorld = 0x04, + DirtyLight = 0x08, + DirtyAll = 0xFF + }; + int m_dirty; + + friend struct StateBinder; +}; + +class FbItem : public QQuickFramebufferObject +{ + Q_OBJECT + Q_PROPERTY(QVector3D eye READ eye WRITE setEye) + Q_PROPERTY(QVector3D target READ target WRITE setTarget) + Q_PROPERTY(QVector3D rotation READ rotation WRITE setRotation) + Q_PROPERTY(bool multisample READ multisample WRITE setMultisample) + +public: + explicit FbItem(QQuickItem *parent = 0); + + QQuickFramebufferObject::Renderer *createRenderer() const Q_DECL_OVERRIDE; + + QVector3D eye() const { return m_eye; } + void setEye(const QVector3D &v); + QVector3D target() const { return m_target; } + void setTarget(const QVector3D &v); + + QVector3D rotation() const { return m_rotation; } + void setRotation(const QVector3D &v); + + enum SyncState { + CameraNeedsSync = 0x01, + RotationNeedsSync = 0x02, + AllNeedsSync = 0xFF + }; + int swapSyncState(); + + bool multisample() const { return m_multisample; } + void setMultisample(bool m) { m_multisample = m; } + +private: + QVector3D m_eye; + QVector3D m_target; + QVector3D m_rotation; + int m_syncState; + bool m_multisample; +}; + +#endif // FBITEM_H diff --git a/examples/quick/quickwidgets/qquickviewcomparison/logo.cpp b/examples/quick/quickwidgets/qquickviewcomparison/logo.cpp new file mode 100644 index 0000000000..1ba47ddfb5 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/logo.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "logo.h" +#include + +Logo::Logo() + : m_count(0) +{ + m_data.resize(2500 * 6); + + const GLfloat x1 = +0.06f; + const GLfloat y1 = -0.14f; + const GLfloat x2 = +0.14f; + const GLfloat y2 = -0.06f; + const GLfloat x3 = +0.08f; + const GLfloat y3 = +0.00f; + const GLfloat x4 = +0.30f; + const GLfloat y4 = +0.22f; + + quad(x1, y1, x2, y2, y2, x2, y1, x1); + quad(x3, y3, x4, y4, y4, x4, y3, x3); + + extrude(x1, y1, x2, y2); + extrude(x2, y2, y2, x2); + extrude(y2, x2, y1, x1); + extrude(y1, x1, x1, y1); + extrude(x3, y3, x4, y4); + extrude(x4, y4, y4, x4); + extrude(y4, x4, y3, x3); + + const int NumSectors = 100; + + for (int i = 0; i < NumSectors; ++i) { + GLfloat angle = (i * 2 * M_PI) / NumSectors; + GLfloat angleSin = qSin(angle); + GLfloat angleCos = qCos(angle); + const GLfloat x5 = 0.30f * angleSin; + const GLfloat y5 = 0.30f * angleCos; + const GLfloat x6 = 0.20f * angleSin; + const GLfloat y6 = 0.20f * angleCos; + + angle = ((i + 1) * 2 * M_PI) / NumSectors; + angleSin = qSin(angle); + angleCos = qCos(angle); + const GLfloat x7 = 0.20f * angleSin; + const GLfloat y7 = 0.20f * angleCos; + const GLfloat x8 = 0.30f * angleSin; + const GLfloat y8 = 0.30f * angleCos; + + quad(x5, y5, x6, y6, x7, y7, x8, y8); + + extrude(x6, y6, x7, y7); + extrude(x8, y8, x5, y5); + } +} + +void Logo::add(const QVector3D &v, const QVector3D &n) +{ + GLfloat *p = m_data.data() + m_count; + *p++ = v.x(); + *p++ = v.y(); + *p++ = v.z(); + *p++ = n.x(); + *p++ = n.y(); + *p++ = n.z(); + m_count += 6; +} + +void Logo::quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4) +{ + QVector3D n = QVector3D::normal(QVector3D(x4 - x1, y4 - y1, 0.0f), QVector3D(x2 - x1, y2 - y1, 0.0f)); + + add(QVector3D(x1, y1, -0.05f), n); + add(QVector3D(x4, y4, -0.05f), n); + add(QVector3D(x2, y2, -0.05f), n); + + add(QVector3D(x3, y3, -0.05f), n); + add(QVector3D(x2, y2, -0.05f), n); + add(QVector3D(x4, y4, -0.05f), n); + + n = QVector3D::normal(QVector3D(x1 - x4, y1 - y4, 0.0f), QVector3D(x2 - x4, y2 - y4, 0.0f)); + + add(QVector3D(x4, y4, 0.05f), n); + add(QVector3D(x1, y1, 0.05f), n); + add(QVector3D(x2, y2, 0.05f), n); + + add(QVector3D(x2, y2, 0.05f), n); + add(QVector3D(x3, y3, 0.05f), n); + add(QVector3D(x4, y4, 0.05f), n); +} + +void Logo::extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) +{ + QVector3D n = QVector3D::normal(QVector3D(0.0f, 0.0f, -0.1f), QVector3D(x2 - x1, y2 - y1, 0.0f)); + + add(QVector3D(x1, y1, +0.05f), n); + add(QVector3D(x1, y1, -0.05f), n); + add(QVector3D(x2, y2, +0.05f), n); + + add(QVector3D(x2, y2, -0.05f), n); + add(QVector3D(x2, y2, +0.05f), n); + add(QVector3D(x1, y1, -0.05f), n); +} diff --git a/examples/quick/quickwidgets/qquickviewcomparison/logo.h b/examples/quick/quickwidgets/qquickviewcomparison/logo.h new file mode 100644 index 0000000000..29bb7fa241 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/logo.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LOGO_H +#define LOGO_H + +#include +#include +#include + +class Logo +{ +public: + Logo(); + const GLfloat *constData() const { return m_data.constData(); } + int count() const { return m_count; } + int vertexCount() const { return m_count / 6; } + +private: + void quad(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2, GLfloat x3, GLfloat y3, GLfloat x4, GLfloat y4); + void extrude(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); + void add(const QVector3D &v, const QVector3D &n); + + QVector m_data; + int m_count; +}; + +#endif // LOGO_H diff --git a/examples/quick/quickwidgets/qquickviewcomparison/main.cpp b/examples/quick/quickwidgets/qquickviewcomparison/main.cpp new file mode 100644 index 0000000000..5f006c3fb6 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char **argv) +{ + qputenv("QML_BAD_GUI_RENDER_LOOP", "1"); // QTBUG-39507 + + QApplication app(argc, argv); + + MainWindow widgetWindow; + widgetWindow.resize(1024, 768); + widgetWindow.show(); + + return app.exec(); +} diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp new file mode 100644 index 0000000000..dbf4121518 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.cpp @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "fbitem.h" +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow() + : m_currentView(0), + m_currentRootObject(0) +{ + QVBoxLayout *layout = new QVBoxLayout; + + QGroupBox *groupBox = new QGroupBox(tr("Type")); + QVBoxLayout *vbox = new QVBoxLayout; + m_radioView = new QRadioButton(tr("QQuickView in a window container (direct)")); + m_radioWidget = new QRadioButton(tr("QQuickWidget (indirect through framebuffer objects)")); + vbox->addWidget(m_radioView); + vbox->addWidget(m_radioWidget); + m_radioView->setChecked(true); + connect(m_radioView, &QRadioButton::toggled, this, &MainWindow::updateView); + connect(m_radioWidget, &QRadioButton::toggled, this, &MainWindow::updateView); + groupBox->setLayout(vbox); + + layout->addWidget(groupBox); + + m_checkboxMultiSample = new QCheckBox(tr("Multisample (4x)")); + connect(m_checkboxMultiSample, &QCheckBox::toggled, this, &MainWindow::updateView); + layout->addWidget(m_checkboxMultiSample); + + m_labelStatus = new QLabel; + layout->addWidget(m_labelStatus); + + qmlRegisterType("fbitem", 1, 0, "FbItem"); + + QWidget *quickContainer = new QWidget; + layout->addWidget(quickContainer); + layout->setStretchFactor(quickContainer, 8); + m_containerLayout = new QVBoxLayout; + quickContainer->setLayout(m_containerLayout); + + // Add an overlay widget to demonstrate that it will _not_ work with + // QQuickView, whereas it is perfectly fine with QQuickWidget. + QPalette semiTransparent(QColor(255,0,0,128)); + semiTransparent.setBrush(QPalette::Text, Qt::white); + semiTransparent.setBrush(QPalette::WindowText, Qt::white); + + m_overlayLabel = new QLabel("This is a\nsemi-transparent\n overlay widget\nwhich is placed\non top\n of the Quick\ncontent.", this); + m_overlayLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); + m_overlayLabel->setAutoFillBackground(true); + m_overlayLabel->setPalette(semiTransparent); + QFont f = font(); + f.setPixelSize(QFontInfo(f).pixelSize()*2); + f.setWeight(QFont::Bold); + m_overlayLabel->setFont(f); + m_overlayLabel->hide(); + + m_checkboxOverlayVisible = new QCheckBox(tr("Show widget overlay")); + connect(m_checkboxOverlayVisible, &QCheckBox::toggled, m_overlayLabel, &QWidget::setVisible); + layout->addWidget(m_checkboxOverlayVisible); + + setLayout(layout); + + updateView(); +} + +void MainWindow::resizeEvent(QResizeEvent*) +{ + int margin = width() / 10; + int top = m_checkboxMultiSample->y(); + int bottom = m_checkboxOverlayVisible->geometry().bottom(); + m_overlayLabel->setGeometry(margin, top, width() - 2 * margin, bottom - top); +} + +void MainWindow::switchTo(QWidget *view) +{ + if (m_containerLayout->count()) + m_containerLayout->takeAt(0); + + delete m_currentView; + m_currentView = view; + m_containerLayout->addWidget(m_currentView); + m_currentView->setFocus(); +} + +void MainWindow::updateView() +{ + QString text = m_currentRootObject + ? m_currentRootObject->property("currentText").toString() + : QStringLiteral("Hello Qt"); + + QUrl source("qrc:qquickviewcomparison/test.qml"); + QSurfaceFormat format; + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + if (m_checkboxMultiSample->isChecked()) + format.setSamples(4); + + if (m_radioView->isChecked()) { + QQuickView *quickView = new QQuickView; + quickView->setFormat(format); + quickView->setResizeMode(QQuickView::SizeRootObjectToView); + connect(quickView, &QQuickView::statusChanged, this, &MainWindow::onStatusChangedView); + connect(quickView, &QQuickView::sceneGraphError, this, &MainWindow::onSceneGraphError); + quickView->setSource(source); + m_currentRootObject = quickView->rootObject(); + switchTo(QWidget::createWindowContainer(quickView)); + } else { + QQuickWidget *quickWidget = new QQuickWidget; + quickWidget->setFormat(format); + quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + connect(quickWidget, &QQuickWidget::statusChanged, this, &MainWindow::onStatusChangedWidget); + connect(quickWidget, &QQuickWidget::sceneGraphError, this, &MainWindow::onSceneGraphError); + quickWidget->setSource(source); + m_currentRootObject = quickWidget->rootObject(); + switchTo(quickWidget); + } + + m_currentRootObject->setProperty("currentText", text); + m_currentRootObject->setProperty("multisample", m_checkboxMultiSample->isChecked()); + + m_overlayLabel->raise(); +} + +void MainWindow::onStatusChangedView(QQuickView::Status status) +{ + QString s; + switch (status) { + case QQuickView::Null: + s = tr("Null"); + break; + case QQuickView::Ready: + s = tr("Ready"); + break; + case QQuickView::Loading: + s = tr("Loading"); + break; + case QQuickView::Error: + s = tr("Error"); + break; + default: + s = tr("Unknown"); + break; + } + m_labelStatus->setText(tr("QQuickView status: %1").arg(s)); +} + +void MainWindow::onStatusChangedWidget(QQuickWidget::Status status) +{ + QString s; + switch (status) { + case QQuickWidget::Null: + s = tr("Null"); + break; + case QQuickWidget::Ready: + s = tr("Ready"); + break; + case QQuickWidget::Loading: + s = tr("Loading"); + break; + case QQuickWidget::Error: + s = tr("Error"); + break; + default: + s = tr("Unknown"); + break; + } + m_labelStatus->setText(tr("QQuickWidget status: %1").arg(s)); +} + +void MainWindow::onSceneGraphError(QQuickWindow::SceneGraphError error, const QString &message) +{ + m_labelStatus->setText(tr("Scenegraph error %1: %2").arg(error).arg(message)); +} diff --git a/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h new file mode 100644 index 0000000000..c7bd514d81 --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/mainwindow.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +QT_FORWARD_DECLARE_CLASS(QRadioButton) +QT_FORWARD_DECLARE_CLASS(QCheckBox) +QT_FORWARD_DECLARE_CLASS(QLabel) +QT_FORWARD_DECLARE_CLASS(QLayout) + +class MainWindow : public QWidget +{ +public: + MainWindow(); + +protected: + void resizeEvent(QResizeEvent*); +private slots: + void updateView(); + void onStatusChangedView(QQuickView::Status status); + void onStatusChangedWidget(QQuickWidget::Status status); + void onSceneGraphError(QQuickWindow::SceneGraphError error, const QString &message); + +private: + void switchTo(QWidget *view); + + QRadioButton *m_radioView; + QRadioButton *m_radioWidget; + QCheckBox *m_checkboxMultiSample; + QLabel *m_labelStatus; + QLayout *m_containerLayout; + QWidget *m_currentView; + QObject *m_currentRootObject; + QLabel *m_overlayLabel; + QCheckBox *m_checkboxOverlayVisible; +}; + +#endif diff --git a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro b/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro new file mode 100644 index 0000000000..9d70f7aa5a --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.pro @@ -0,0 +1,17 @@ +TEMPLATE = app +TARGET = qquickviewcomparison + +QT += quick widgets quickwidgets + +SOURCES += main.cpp \ + mainwindow.cpp \ + logo.cpp \ + fbitem.cpp + +HEADERS += mainwindow.h \ + logo.h \ + fbitem.h + +RESOURCES += qquickviewcomparison.qrc + +OTHER_FILES += test.qml diff --git a/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc b/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc new file mode 100644 index 0000000000..2b259fdeec --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/qquickviewcomparison.qrc @@ -0,0 +1,5 @@ + + + test.qml + + diff --git a/examples/quick/quickwidgets/qquickviewcomparison/test.qml b/examples/quick/quickwidgets/qquickviewcomparison/test.qml new file mode 100644 index 0000000000..2e8c83024a --- /dev/null +++ b/examples/quick/quickwidgets/qquickviewcomparison/test.qml @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Particles 2.0 +import fbitem 1.0 + +Rectangle { + id: root + color: "lightBlue" + property alias currentText: edit.text + property alias multisample: fbitem.multisample + + ParticleSystem { + anchors.fill: parent + running: true + + ImageParticle { + source: "qrc:///particleresources/glowdot.png" + alpha: 0 + colorVariation: 1 + } + + Emitter { + anchors.fill: parent + lifeSpan: 3000 + emitRate: 30 + size: 50 + sizeVariation: 10 + velocity: PointDirection { xVariation: 10; yVariation: 10; } + acceleration: PointDirection { + y: -10 + xVariation: 5 + yVariation: 5 + } + } + } + + Rectangle { + y: 10 + width: parent.width / 2 + height: edit.contentHeight + 4 + anchors.horizontalCenter: parent.horizontalCenter + border.color: "gray" + border.width: 2 + radius: 8 + color: "lightGray" + clip: true + TextInput { + id: edit + anchors.horizontalCenter: parent.horizontalCenter + maximumLength: 30 + focus: true + font.pointSize: 20 + } + } + + Rectangle { + width: 300 + height: 300 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 20000; loops: Animation.Infinite; } + } + + FbItem { + id: fbitem + anchors.fill: parent + SequentialAnimation on eye.y { + loops: Animation.Infinite + NumberAnimation { + from: 0 + to: 0.15 + duration: 1000 + } + NumberAnimation { + from: 0.15 + to: 0 + duration: 2000 + } + } + SequentialAnimation on eye.x { + loops: Animation.Infinite + NumberAnimation { + from: 0 + to: -0.5 + duration: 3000 + } + NumberAnimation { + from: -0.5 + to: 0.5 + duration: 3000 + easing.type: Easing.OutQuad + } + NumberAnimation { + from: 0.5 + to: 0 + duration: 1000 + } + } + SequentialAnimation on rotation.y { + loops: Animation.Infinite + NumberAnimation { + from: 0 + to: 360 + duration: 5000 + } + NumberAnimation { + from: 360 + to: 0 + duration: 2500 + } + } + SequentialAnimation on rotation.x { + loops: Animation.Infinite + NumberAnimation { + from: 0 + to: 360 + duration: 6000 + } + NumberAnimation { + from: 360 + to: 0 + duration: 3000 + } + } + } + + Text { + id: effText + text: edit.text + anchors.centerIn: parent + font.pointSize: 60 + style: Text.Outline + styleColor: "green" + } + + ShaderEffectSource { + id: effSource + sourceItem: effText + hideSource: true + } + + ShaderEffect { + SequentialAnimation on scale { + loops: Animation.Infinite + NumberAnimation { from: 1.0; to: 2.0; duration: 1000; easing.type: Easing.InCirc } + PauseAnimation { duration: 1000 } + NumberAnimation { from: 2.0; to: 0.5; duration: 1000; easing.type: Easing.OutExpo } + NumberAnimation { from: 0.5; to: 1.0; duration: 500 } + PauseAnimation { duration: 1000 } + } + width: effText.width + height: effText.height + anchors.centerIn: parent + property variant source: effSource + property real amplitude: 0.002 + property real frequency: 10 + property real time: 0 + NumberAnimation on time { loops: Animation.Infinite; from: 0; to: Math.PI * 2; duration: 1000 } + fragmentShader: + "uniform lowp float qt_Opacity;" + + "uniform highp float amplitude;" + + "uniform highp float frequency;" + + "uniform highp float time;" + + "uniform sampler2D source;" + + "varying highp vec2 qt_TexCoord0;" + + "void main() {" + + " highp vec2 p = sin(time + frequency * qt_TexCoord0);" + + " gl_FragColor = texture2D(source, qt_TexCoord0 + amplitude * vec2(p.y, -p.x)) * qt_Opacity;" + + "}" + } +} diff --git a/examples/quick/quickwidgets/quickwidgets.pro b/examples/quick/quickwidgets/quickwidgets.pro index 07192b6696..be932f33d0 100644 --- a/examples/quick/quickwidgets/quickwidgets.pro +++ b/examples/quick/quickwidgets/quickwidgets.pro @@ -1,2 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = quickwidget +SUBDIRS = quickwidget \ + qquickviewcomparison -- cgit v1.2.3 From 28851c675cff5484be6abcbfd045537615e7a288 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 17 Jun 2014 13:35:21 +0200 Subject: Fix QQmlComponent detailed description. setParent() => setParentItem() Task-number: QTBUG-39687 Change-Id: I67dc871a6d3b10af321d1f7b08921dcad0a6f19d Reviewed-by: J-P Nurmi --- src/qml/qml/qqmlcomponent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 39a7d8905d..e9a3449a22 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -150,7 +150,7 @@ V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension); // QQmlEngine *engine = qmlContext(this)->engine(); QQmlComponent component(engine, QUrl::fromLocalFile("MyItem.qml")); QQuickItem *childItem = qobject_cast(component.create()); - childItem->setParent(this); + childItem->setParentItem(this); } \endcode -- cgit v1.2.3 From 68c78625d888cdd6650851290d140ccf8fbf4d6b Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 12 Jun 2014 15:05:05 +0200 Subject: Improve RSS News Qt Quick Demo - Add main.cpp for launching, use Qt resource system - Update feed URLs - New layout and images - Make the example scalable, react to orientation changes - Use graphical effects and animations - Display time and link for each news item - Fix license headers to use the correct license Task-number: QTBUG-37203 Change-Id: I6f8941cbdaed78a3dee30305496b3ea7777ba3e3 Reviewed-by: Jerome Pasion Reviewed-by: Leena Miettinen --- examples/quick/demos/demos.pro | 4 +- .../quick/demos/rssnews/content/BusyIndicator.qml | 69 ++++---- .../demos/rssnews/content/CategoryDelegate.qml | 143 +++++++++------ .../quick/demos/rssnews/content/NewsDelegate.qml | 142 ++++++++++----- examples/quick/demos/rssnews/content/RssFeeds.qml | 87 +++++---- examples/quick/demos/rssnews/content/ScrollBar.qml | 75 ++++---- .../quick/demos/rssnews/content/images/Asia.jpg | Bin 0 -> 10578 bytes .../demos/rssnews/content/images/Business.jpg | Bin 0 -> 17276 bytes .../demos/rssnews/content/images/Entertainment.jpg | Bin 0 -> 15433 bytes .../quick/demos/rssnews/content/images/Europe.jpg | Bin 0 -> 15872 bytes .../quick/demos/rssnews/content/images/Health.jpg | Bin 0 -> 16015 bytes .../demos/rssnews/content/images/Politics.jpg | Bin 0 -> 16401 bytes .../quick/demos/rssnews/content/images/Science.jpg | Bin 0 -> 9496 bytes .../quick/demos/rssnews/content/images/Sports.jpg | Bin 0 -> 9281 bytes .../demos/rssnews/content/images/Technology.jpg | Bin 0 -> 22290 bytes .../demos/rssnews/content/images/TopStories.jpg | Bin 0 -> 8067 bytes .../demos/rssnews/content/images/USNational.jpg | Bin 0 -> 9635 bytes .../quick/demos/rssnews/content/images/World.jpg | Bin 0 -> 15128 bytes .../demos/rssnews/content/images/btn_close.png | Bin 0 -> 1267 bytes .../doc/images/qtquick-demo-rssnews-small.png | Bin 43372 -> 56864 bytes examples/quick/demos/rssnews/main.cpp | 41 +++++ examples/quick/demos/rssnews/rssnews.pro | 13 ++ examples/quick/demos/rssnews/rssnews.qml | 197 +++++++++++++-------- examples/quick/demos/rssnews/rssnews.qrc | 25 +++ 24 files changed, 515 insertions(+), 281 deletions(-) create mode 100644 examples/quick/demos/rssnews/content/images/Asia.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Business.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Entertainment.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Europe.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Health.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Politics.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Science.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Sports.jpg create mode 100644 examples/quick/demos/rssnews/content/images/Technology.jpg create mode 100644 examples/quick/demos/rssnews/content/images/TopStories.jpg create mode 100644 examples/quick/demos/rssnews/content/images/USNational.jpg create mode 100644 examples/quick/demos/rssnews/content/images/World.jpg create mode 100644 examples/quick/demos/rssnews/content/images/btn_close.png create mode 100644 examples/quick/demos/rssnews/main.cpp create mode 100644 examples/quick/demos/rssnews/rssnews.pro create mode 100644 examples/quick/demos/rssnews/rssnews.qrc diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro index ac15cc3c1f..c1768ce721 100644 --- a/examples/quick/demos/demos.pro +++ b/examples/quick/demos/demos.pro @@ -5,8 +5,8 @@ SUBDIRS = samegame \ tweetsearch \ maroon \ photosurface \ + rssnews \ stocqt EXAMPLE_FILES = \ - photoviewer \ - rssnews + photoviewer diff --git a/examples/quick/demos/rssnews/content/BusyIndicator.qml b/examples/quick/demos/rssnews/content/BusyIndicator.qml index d9c3646ae3..e6cd15847a 100644 --- a/examples/quick/demos/rssnews/content/BusyIndicator.qml +++ b/examples/quick/demos/rssnews/content/BusyIndicator.qml @@ -3,37 +3,36 @@ ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** @@ -43,11 +42,13 @@ import QtQuick 2.2 Image { id: container - property bool on: false - source: "images/busy.png"; visible: container.on + source: "images/busy.png"; NumberAnimation on rotation { - running: container.on; from: 0; to: 360; loops: Animation.Infinite; duration: 1200 + running: container.visible + from: 0; to: 360; + loops: Animation.Infinite; + duration: 1200 } } diff --git a/examples/quick/demos/rssnews/content/CategoryDelegate.qml b/examples/quick/demos/rssnews/content/CategoryDelegate.qml index bb2b3581df..cb48715609 100644 --- a/examples/quick/demos/rssnews/content/CategoryDelegate.qml +++ b/examples/quick/demos/rssnews/content/CategoryDelegate.qml @@ -3,80 +3,123 @@ ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. ** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.2 +import QtGraphicalEffects 1.0 -Item { +Rectangle { id: delegate - width: delegate.ListView.view.width; height: 60 + property bool selected: ListView.isCurrentItem + property real itemSize + width: itemSize + height: itemSize - Text { - text: name - color: delegate.ListView.isCurrentItem ? "white" : "black" - font { family: "Helvetica"; pixelSize: 16; bold: true } - anchors { - left: parent.left; leftMargin: 15 - verticalCenter: parent.verticalCenter - } + Image { + anchors.centerIn: parent + source: image } - BusyIndicator { - scale: 0.6 - on: delegate.ListView.isCurrentItem && window.loading - anchors { right: parent.right; rightMargin: 10; verticalCenter: parent.verticalCenter } - } + Item { + id: title + anchors.fill: parent + + Text { + id: titleText + + anchors { + left: parent.left; leftMargin: 20 + right: parent.right; rightMargin: 20 + top: parent.top; topMargin: 20 + } + font { pixelSize: 18; bold: true } + text: name + color: selected ? "#ffffff" : "#ebebdd" + Behavior on color { ColorAnimation { duration: 150 } } + } - Rectangle { - width: delegate.width; height: 1; color: "#cccccc" - anchors.bottom: delegate.bottom - visible: delegate.ListView.isCurrentItem ? false : true + DropShadow { + source: titleText + anchors.fill: titleText + horizontalOffset: selected ? 3 : 1 + verticalOffset: selected ? 3 : 1 + radius: 4 + color: "#2f1000" + samples: 8 + + Behavior on horizontalOffset { NumberAnimation { duration: 300 } } + Behavior on verticalOffset { NumberAnimation { duration: 300 } } + } + + states: [ + State { + name: "selected" + when: selected + PropertyChanges { target: title; scale: "1.1" } + }] + + transitions: [ + Transition { + to: "selected" + SequentialAnimation { + id: titleAnimation + PropertyAnimation { target: title; property: "scale"; duration: 300 } + } + }, + Transition { + to: "" + animations: titleAnimation + }] } - Rectangle { - width: delegate.width; height: 1; color: "white" - visible: delegate.ListView.isCurrentItem ? false : true + + BusyIndicator { + scale: 0.8 + visible: delegate.ListView.isCurrentItem && window.loading + anchors.centerIn: parent } MouseArea { anchors.fill: delegate onClicked: { delegate.ListView.view.currentIndex = index - window.currentFeed = feed + if (window.currentFeed == feed) + feedModel.reload() + else + window.currentFeed = feed } } } diff --git a/examples/quick/demos/rssnews/content/NewsDelegate.qml b/examples/quick/demos/rssnews/content/NewsDelegate.qml index feb0516653..fee1119b08 100644 --- a/examples/quick/demos/rssnews/content/NewsDelegate.qml +++ b/examples/quick/demos/rssnews/content/NewsDelegate.qml @@ -3,69 +3,127 @@ ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. ** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.2 +import QtQuick.Layouts 1.1 -Item { +ColumnLayout { id: delegate - height: column.height + 40 width: delegate.ListView.view.width - Column { - id: column - x: 20; y: 20 - width: parent.width - 40 + // Returns a string representing how long ago an event occurred + function timeSinceEvent(pubDate) { + var result = pubDate; + + // We need to modify the pubDate read from the RSS feed + // so the JavaScript Date object can interpret it + var d = pubDate.replace(',','').split(' '); + if (d.length != 6) + return result; + + var date = new Date([d[0], d[2], d[1], d[3], d[4], 'GMT' + d[5]].join(' ')); + + if (!isNaN(date.getDate())) { + var age = new Date() - date; + var minutes = Math.floor(Number(age) / 60000); + if (minutes < 1440) { + if (minutes < 2) + result = qsTr("Just now"); + else if (minutes < 60) + result = '' + minutes + ' ' + qsTr("minutes ago") + else if (minutes < 120) + result = qsTr("1 hour ago"); + else + result = '' + Math.floor(minutes/60) + ' ' + qsTr("hours ago"); + } + else { + result = date.toDateString(); + } + } + return result; + } + + RowLayout { + Layout.maximumWidth: parent.width + + ColumnLayout { + Layout.alignment: Qt.AlignTop + + Item { + height: titleText.font.pixelSize / 4 + } + + Image { + id: titleImage + source: image + } + } Text { id: titleText - text: title; width: parent.width; wrapMode: Text.WordWrap - font { bold: true; family: "Helvetica"; pointSize: 16 } + + text: title + Layout.maximumWidth: delegate.width - titleImage.width + wrapMode: Text.WordWrap + font.pixelSize: 26 + font.bold: true } + } - Text { - id: descriptionText - width: parent.width; text: description - wrapMode: Text.WordWrap; font.family: "Helvetica" + Text { + Layout.maximumWidth: delegate.width + font.pixelSize: 12 + textFormat: Text.RichText + font.italic: true + Layout.alignment: Qt.AlignLeft + text: timeSinceEvent(pubDate) + " (Link)" + onLinkActivated: { + Qt.openUrlExternally(link) } } - Rectangle { - width: parent.width; height: 1; color: "#cccccc" - anchors.bottom: parent.bottom + Text { + id: descriptionText + + text: description + Layout.maximumWidth: parent.width + wrapMode: Text.WordWrap + font.pixelSize: 14 + textFormat: Text.StyledText + horizontalAlignment: Qt.AlignLeft } } diff --git a/examples/quick/demos/rssnews/content/RssFeeds.qml b/examples/quick/demos/rssnews/content/RssFeeds.qml index 425b011a78..3ae3b23921 100644 --- a/examples/quick/demos/rssnews/content/RssFeeds.qml +++ b/examples/quick/demos/rssnews/content/RssFeeds.qml @@ -3,37 +3,36 @@ ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** @@ -42,18 +41,16 @@ import QtQuick 2.2 ListModel { - id: rssFeeds - - ListElement { name: "Top Stories"; feed: "rss.news.yahoo.com/rss/topstories" } - ListElement { name: "World"; feed: "rss.news.yahoo.com/rss/world" } - ListElement { name: "Europe"; feed: "rss.news.yahoo.com/rss/europe" } - ListElement { name: "Oceania"; feed: "rss.news.yahoo.com/rss/oceania" } - ListElement { name: "U.S. National"; feed: "rss.news.yahoo.com/rss/us" } - ListElement { name: "Politics"; feed: "rss.news.yahoo.com/rss/politics" } - ListElement { name: "Business"; feed: "rss.news.yahoo.com/rss/business" } - ListElement { name: "Technology"; feed: "rss.news.yahoo.com/rss/tech" } - ListElement { name: "Entertainment"; feed: "rss.news.yahoo.com/rss/entertainment" } - ListElement { name: "Health"; feed: "rss.news.yahoo.com/rss/health" } - ListElement { name: "Science"; feed: "rss.news.yahoo.com/rss/science" } - ListElement { name: "Sports"; feed: "rss.news.yahoo.com/rss/sports" } + ListElement { name: "Top Stories"; feed: "news.yahoo.com/rss/topstories"; image: "images/TopStories.jpg" } + ListElement { name: "World"; feed: "news.yahoo.com/rss/world"; image: "images/World.jpg" } + ListElement { name: "Europe"; feed: "news.yahoo.com/rss/europe"; image: "images/Europe.jpg" } + ListElement { name: "Asia"; feed: "news.yahoo.com/rss/asia"; image: "images/Asia.jpg" } + ListElement { name: "U.S. National"; feed: "news.yahoo.com/rss/us"; image: "images/USNational.jpg" } + ListElement { name: "Politics"; feed: "news.yahoo.com/rss/politics"; image: "images/Politics.jpg" } + ListElement { name: "Business"; feed: "news.yahoo.com/rss/business"; image: "images/Business.jpg" } + ListElement { name: "Technology"; feed: "news.yahoo.com/rss/tech"; image: "images/Technology.jpg" } + ListElement { name: "Entertainment"; feed: "news.yahoo.com/rss/entertainment"; image: "images/Entertainment.jpg" } + ListElement { name: "Health"; feed: "news.yahoo.com/rss/health"; image: "images/Health.jpg" } + ListElement { name: "Science"; feed: "news.yahoo.com/rss/science"; image: "images/Science.jpg" } + ListElement { name: "Sports"; feed: "news.yahoo.com/rss/sports"; image: "images/Sports.jpg" } } diff --git a/examples/quick/demos/rssnews/content/ScrollBar.qml b/examples/quick/demos/rssnews/content/ScrollBar.qml index b8f1b730e0..606f2e4259 100644 --- a/examples/quick/demos/rssnews/content/ScrollBar.qml +++ b/examples/quick/demos/rssnews/content/ScrollBar.qml @@ -3,37 +3,36 @@ ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. ** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** @@ -45,7 +44,7 @@ Item { id: container property variant scrollArea - property variant orientation: Qt.Vertical + property int orientation: Qt.Vertical opacity: 0 @@ -56,7 +55,11 @@ Item { ny = scrollArea.visibleArea.yPosition * container.height; else ny = scrollArea.visibleArea.xPosition * container.width; - if (ny > 2) return ny; else return 2; + + if (ny > 2) + return ny; + else + return 2; } function size() @@ -79,8 +82,12 @@ Item { t = Math.ceil(container.height - 3 - ny); else t = Math.ceil(container.width - 3 - ny); - if (nh > t) return t; else return nh; - } else return nh + ny; + if (nh > t) + return t; + else + return nh; + } else + return nh + ny; } Rectangle { anchors.fill: parent; color: "Black"; opacity: 0.3 } @@ -89,14 +96,16 @@ Item { source: "images/scrollbar.png" border { left: 1; right: 1; top: 1; bottom: 1 } x: container.orientation == Qt.Vertical ? 2 : position() - width: container.orientation == Qt.Vertical ? container.width - 4 : size() y: container.orientation == Qt.Vertical ? position() : 2 + width: container.orientation == Qt.Vertical ? container.width - 4 : size() height: container.orientation == Qt.Vertical ? size() : container.height - 4 } states: State { name: "visible" - when: container.orientation == Qt.Vertical ? scrollArea.movingVertically : scrollArea.movingHorizontally + when: container.orientation == Qt.Vertical ? + scrollArea.movingVertically : + scrollArea.movingHorizontally PropertyChanges { target: container; opacity: 1.0 } } diff --git a/examples/quick/demos/rssnews/content/images/Asia.jpg b/examples/quick/demos/rssnews/content/images/Asia.jpg new file mode 100644 index 0000000000..a609557a08 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Asia.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Business.jpg b/examples/quick/demos/rssnews/content/images/Business.jpg new file mode 100644 index 0000000000..b2c1d92138 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Business.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Entertainment.jpg b/examples/quick/demos/rssnews/content/images/Entertainment.jpg new file mode 100644 index 0000000000..2c69fc04d7 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Entertainment.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Europe.jpg b/examples/quick/demos/rssnews/content/images/Europe.jpg new file mode 100644 index 0000000000..bf524e13d0 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Europe.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Health.jpg b/examples/quick/demos/rssnews/content/images/Health.jpg new file mode 100644 index 0000000000..0e8c71f0c9 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Health.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Politics.jpg b/examples/quick/demos/rssnews/content/images/Politics.jpg new file mode 100644 index 0000000000..0b1800c97e Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Politics.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Science.jpg b/examples/quick/demos/rssnews/content/images/Science.jpg new file mode 100644 index 0000000000..7faccbbb97 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Science.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Sports.jpg b/examples/quick/demos/rssnews/content/images/Sports.jpg new file mode 100644 index 0000000000..0ab3bd3ce7 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Sports.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/Technology.jpg b/examples/quick/demos/rssnews/content/images/Technology.jpg new file mode 100644 index 0000000000..db553028fb Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/Technology.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/TopStories.jpg b/examples/quick/demos/rssnews/content/images/TopStories.jpg new file mode 100644 index 0000000000..e35bd67f20 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/TopStories.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/USNational.jpg b/examples/quick/demos/rssnews/content/images/USNational.jpg new file mode 100644 index 0000000000..82c78228c1 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/USNational.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/World.jpg b/examples/quick/demos/rssnews/content/images/World.jpg new file mode 100644 index 0000000000..7a0a806fd4 Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/World.jpg differ diff --git a/examples/quick/demos/rssnews/content/images/btn_close.png b/examples/quick/demos/rssnews/content/images/btn_close.png new file mode 100644 index 0000000000..6d635375eb Binary files /dev/null and b/examples/quick/demos/rssnews/content/images/btn_close.png differ diff --git a/examples/quick/demos/rssnews/doc/images/qtquick-demo-rssnews-small.png b/examples/quick/demos/rssnews/doc/images/qtquick-demo-rssnews-small.png index 0ad6c02251..ffef99ee5c 100644 Binary files a/examples/quick/demos/rssnews/doc/images/qtquick-demo-rssnews-small.png and b/examples/quick/demos/rssnews/doc/images/qtquick-demo-rssnews-small.png differ diff --git a/examples/quick/demos/rssnews/main.cpp b/examples/quick/demos/rssnews/main.cpp new file mode 100644 index 0000000000..0064412f39 --- /dev/null +++ b/examples/quick/demos/rssnews/main.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "../../shared/shared.h" +DECLARATIVE_EXAMPLE_MAIN(demos/rssnews/rssnews) diff --git a/examples/quick/demos/rssnews/rssnews.pro b/examples/quick/demos/rssnews/rssnews.pro new file mode 100644 index 0000000000..c67c5a6558 --- /dev/null +++ b/examples/quick/demos/rssnews/rssnews.pro @@ -0,0 +1,13 @@ +TEMPLATE = app + +QT += quick qml xml xmlpatterns +SOURCES += main.cpp +RESOURCES += rssnews.qrc + +OTHER_FILES = rssnews.qml \ + content/*.qml \ + content/*.js \ + content/images/* + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/demos/rssnews +INSTALLS += target diff --git a/examples/quick/demos/rssnews/rssnews.qml b/examples/quick/demos/rssnews/rssnews.qml index a367490ef7..cb9734208d 100644 --- a/examples/quick/demos/rssnews/rssnews.qml +++ b/examples/quick/demos/rssnews/rssnews.qml @@ -1,112 +1,159 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** -** This file is part of the QtQml module of the Qt Toolkit. +** This file is part of the examples of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: ** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. ** -** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. ** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.2 import QtQuick.XmlListModel 2.0 -import "content" +import QtQuick.Window 2.1 +import "./content" Rectangle { id: window - width: 800; height: 480 - property string currentFeed: "rss.news.yahoo.com/rss/topstories" - property bool loading: feedModel.status == XmlListModel.Loading + width: 800 + height: 480 + + property string currentFeed: rssFeeds.get(0).feed + property bool loading: feedModel.status === XmlListModel.Loading + property bool isPortrait: Screen.primaryOrientation === Qt.PortraitOrientation + + onLoadingChanged: { + if (feedModel.status == XmlListModel.Ready) + list.positionViewAtBeginning() + } RssFeeds { id: rssFeeds } XmlListModel { id: feedModel + source: "http://" + window.currentFeed - query: "/rss/channel/item" + query: "/rss/channel/item[child::media:content]" + namespaceDeclarations: "declare namespace media = 'http://search.yahoo.com/mrss/';" XmlRole { name: "title"; query: "title/string()" } + // Remove any links from the description + XmlRole { name: "description"; query: "fn:replace(description/string(), '\<a href=.*\/a\>', '')" } + XmlRole { name: "image"; query: "media:content/@url/string()" } XmlRole { name: "link"; query: "link/string()" } - XmlRole { name: "description"; query: "description/string()" } + XmlRole { name: "pubDate"; query: "pubDate/string()" } } - Row { - Rectangle { - width: 220; height: window.height - color: "#efefef" - - ListView { - focus: true - id: categories - anchors.fill: parent - model: rssFeeds - footer: quitButtonDelegate - delegate: CategoryDelegate {} - highlight: Rectangle { color: "steelblue" } - highlightMoveVelocity: 9999999 - } - ScrollBar { - scrollArea: categories; height: categories.height; width: 8 - anchors.right: categories.right - } - } - ListView { - id: list - width: window.width - 220; height: window.height - model: feedModel - delegate: NewsDelegate {} - } + ListView { + id: categories + property int itemWidth: 190 + + width: isPortrait ? parent.width : itemWidth + height: isPortrait ? itemWidth : parent.height + orientation: isPortrait ? ListView.Horizontal : ListView.Vertical + anchors.top: parent.top + model: rssFeeds + delegate: CategoryDelegate { itemSize: categories.itemWidth } + spacing: 3 + } + + ScrollBar { + id: listScrollBar + + orientation: isPortrait ? Qt.Horizontal : Qt.Vertical + height: isPortrait ? 8 : categories.height; + width: isPortrait ? categories.width : 8 + scrollArea: categories; + anchors.right: categories.right } + + ListView { + id: list + + anchors.left: isPortrait ? window.left : categories.right + anchors.right: closeButton.left + anchors.top: isPortrait ? categories.bottom : window.top + anchors.bottom: window.bottom + anchors.leftMargin: 30 + anchors.rightMargin: 4 + clip: isPortrait + model: feedModel + footer: footerText + delegate: NewsDelegate {} + } + + ScrollBar { + scrollArea: list + width: 8 + anchors.right: window.right + anchors.top: isPortrait ? categories.bottom : window.top + anchors.bottom: window.bottom + } + Component { - id: quitButtonDelegate - Item { - width: categories.width; height: 60 + id: footerText + + Rectangle { + width: parent.width + height: closeButton.height + color: "lightgray" + Text { - text: "Quit" - font { family: "Helvetica"; pixelSize: 16; bold: true } - anchors { - left: parent.left; leftMargin: 15 - verticalCenter: parent.verticalCenter - } + text: "RSS Feed from Yahoo News" + anchors.centerIn: parent + font.pixelSize: 14 } - MouseArea { - anchors.fill: parent - onClicked: Qt.quit() + } + } + + Image { + id: closeButton + source: "content/images/btn_close.png" + scale: 0.8 + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: 4 + opacity: (isPortrait && categories.moving) ? 0.2 : 1.0 + Behavior on opacity { + NumberAnimation { duration: 300; easing.type: Easing.OutSine } + } + + MouseArea { + anchors.fill: parent + onClicked: { + Qt.quit() } } } - ScrollBar { scrollArea: list; height: list.height; width: 8; anchors.right: window.right } - Rectangle { x: 220; height: window.height; width: 1; color: "#cccccc" } } diff --git a/examples/quick/demos/rssnews/rssnews.qrc b/examples/quick/demos/rssnews/rssnews.qrc new file mode 100644 index 0000000000..1208d44fd7 --- /dev/null +++ b/examples/quick/demos/rssnews/rssnews.qrc @@ -0,0 +1,25 @@ + + + rssnews.qml + content/BusyIndicator.qml + content/CategoryDelegate.qml + content/NewsDelegate.qml + content/RssFeeds.qml + content/ScrollBar.qml + content/images/btn_close.png + content/images/Business.jpg + content/images/busy.png + content/images/Entertainment.jpg + content/images/Europe.jpg + content/images/Health.jpg + content/images/Asia.jpg + content/images/Politics.jpg + content/images/Science.jpg + content/images/scrollbar.png + content/images/Sports.jpg + content/images/Technology.jpg + content/images/TopStories.jpg + content/images/USNational.jpg + content/images/World.jpg + + -- cgit v1.2.3 From 0f63dba04de3d61fc191b324010305064c876a9a Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Mon, 16 Jun 2014 16:51:17 +0200 Subject: Initialize velocity Fixes valgrind warning ==21054== Conditional jump or move depends on uninitialised value(s) ==21054== at 0x5DAE6D4: QQuickListView::viewportMoved(QFlags) (qquicklistview.cpp:2789) ==21054== by 0x5D9ED76: QQuickFlickablePrivate::itemGeometryChanged(QQuickItem*, QRectF const&, QRectF const&) (qquickflickable.cpp:296) ==21054== by 0x5DFC438: QQuickItemViewPrivate::itemGeometryChanged(QQuickItem*, QRectF const&, QRectF const&) (qquickitemview.cpp:1158) ==21054== by 0x5DAC6A2: QQuickListViewPrivate::itemGeometryChanged(QQuickItem*, QRectF const&, QRectF const&) (qquicklistview.cpp:1369) ==21054== by 0x5D0D5F2: QQuickItem::geometryChanged(QRectF const&, QRectF const&) (qquickitem.cpp:3365) ==21054== by 0x5D11822: QQuickItem::setY(double) (qquickitem.cpp:5858) ==21054== by 0x5C84FED: QQuickTimeLinePrivate::advance(int) (qquicktimeline.cpp:826) ==21054== by 0x5C85155: QQuickTimeLine::updateCurrentTime(int) (qquicktimeline.cpp:702) ==21054== by 0x58576FA: QAbstractAnimationJob::setCurrentTime(int) (qabstractanimationjob.cpp:497) ==21054== by 0x5857BDD: QQmlAnimationTimer::updateAnimationsTime(long long) (qabstractanimationjob.cpp:119) ==21054== by 0x640C7EC: QUnifiedTimer::updateAnimationTimers(long long) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x58570C8: QQmlAnimationTimer::startAnimations() (qabstractanimationjob.cpp:152) ==21054== by 0x66895B5: QObject::event(QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x6659CDC: QCoreApplication::notify(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x66599D4: QCoreApplication::notifyInternal(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x665B826: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x66B1242: ??? (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x8EE2E43: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==21054== by 0x8EE3087: g_main_context_iterate.isra.24 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==21054== by 0x8EE312B: g_main_context_iteration (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==21054== by 0x66B06BB: QEventDispatcherGlib::processEvents(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x66578EA: QEventLoop::exec(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==21054== by 0x665EF45: QCoreApplication::exec() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) Change-Id: I72e101140b8bee0b6867cf92902e70660c8d21ab Reviewed-by: Martin Jones Reviewed-by: Gunnar Sletta --- src/quick/items/qquickflickable_p_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 07c434f452..33a642eb69 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -101,7 +101,7 @@ public: AxisData(QQuickFlickablePrivate *fp, void (QQuickFlickablePrivate::*func)(qreal)) : move(fp, func) , transitionToBounds(0) - , viewSize(-1), lastPos(0), startMargin(0), endMargin(0) + , viewSize(-1), lastPos(0), velocity(0), startMargin(0), endMargin(0) , origin(0) , transitionTo(0) , continuousFlickVelocity(0), velocityTime(), vTime(0) -- cgit v1.2.3 From fca40e7cf81338e4c22ef25fa0b3fe0f691632b7 Mon Sep 17 00:00:00 2001 From: Albert Astals Cid Date: Tue, 17 Jun 2014 13:10:35 +0200 Subject: QQmlObjectCreator: Clear sharedState componentAttached in destruction/clear Fixes crash when delegate is being deleted while not totally instantiated Valgrind trace: ==15748== Invalid write of size 8 ==15748== at 0x57A02DB: QQmlComponentAttached::~QQmlComponentAttached() (qqmlcomponent.cpp:985) ==15748== by 0x57A0318: QQmlComponentAttached::~QQmlComponentAttached() (qqmlcomponent.cpp:989) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D33AE5: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D34655: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D33AE5: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D348A5: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D34655: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x668736B: QObjectPrivate::deleteChildren() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66900EB: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1D4B5: QQuickItem::~QQuickItem() (qquickitem.cpp:2064) ==15748== by 0x5D33AE5: QQmlPrivate::QQmlElement::~QQmlElement() (qqmlprivate.h:106) ==15748== by 0x6689607: QObject::event(QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x5D1B012: QQuickItem::event(QEvent*) (qquickitem.cpp:7114) ==15748== by 0x6659CDC: QCoreApplication::notify(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66599D4: QCoreApplication::notifyInternal(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x665B826: QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66B1242: ??? (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x8EE2E43: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x8EE3087: g_main_context_iterate.isra.24 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x8EE312B: g_main_context_iteration (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x66B06BB: QEventDispatcherGlib::processEvents(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66578EA: QEventLoop::exec(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x665EF45: QCoreApplication::exec() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x40711B: startShell(int, char const**, void*) (main.cpp:171) ==15748== by 0x407A74: main (main.cpp:227) ==15748== Address 0x1be83870 is 64 bytes inside a block of size 112 free'd ==15748== at 0x4C2C2BC: operator delete(void*) (vg_replace_malloc.c:503) ==15748== by 0x5815FB0: QQmlObjectCreator::~QQmlObjectCreator() (qqmlobjectcreator.cpp:156) ==15748== by 0x57A52AA: QQmlIncubatorPrivate::clear() (qscopedpointer.h:62) ==15748== by 0x57A53C6: QQmlIncubator::clear() (qqmlincubator.cpp:577) ==15748== by 0x5DCEA20: QQuickLoader::setActive(bool) (qquickloader.cpp:350) ==15748== by 0x5DCF6D2: QQuickLoader::qt_metacall(QMetaObject::Call, int, void**) (moc_qquickloader_p.cpp:277) ==15748== by 0x579DC66: QQmlPropertyPrivate::write(QObject*, QQmlPropertyData const&, QVariant const&, QQmlContextData*, QFlags) (qqmlproperty.cpp:1322) ==15748== by 0x579E76E: QQmlPropertyPrivate::writeValueProperty(QObject*, QQmlPropertyData const&, QVariant const&, QQmlContextData*, QFlags) (qqmlproperty.cpp:1246) ==15748== by 0x579F2F9: QQmlPropertyPrivate::writeBinding(QObject*, QQmlPropertyData const&, QQmlContextData*, QQmlJavaScriptExpression*, QV4::ValueRef, bool, QFlags) (qqmlproperty.cpp:1578) ==15748== by 0x580CF69: QQmlBinding::update(QFlags) (qqmlbinding.cpp:266) ==15748== by 0x580D5BD: QQmlBinding::expressionChanged(QQmlJavaScriptExpression*) (qqmlbinding_p.h:105) ==15748== by 0x57E6156: QQmlNotifier::emitNotify(QQmlNotifierEndpoint*, void**) (qqmlnotifier.cpp:81) ==15748== by 0x57E6130: QQmlNotifier::emitNotify(QQmlNotifierEndpoint*, void**) (qqmlnotifier.cpp:76) ==15748== by 0x57E6130: QQmlNotifier::emitNotify(QQmlNotifierEndpoint*, void**) (qqmlnotifier.cpp:76) ==15748== by 0x5788FA3: QQmlData::signalEmitted(QAbstractDeclarativeData*, QObject*, int, void**) (qqmlengine.cpp:721) ==15748== by 0x6688232: QMetaObject::activate(QObject*, int, int, void**) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x57882A7: QQmlData::destroyed(QObject*) (qqmlengine.cpp:1658) ==15748== by 0x668FD7D: QObject::~QObject() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x55E8B64: QQmlDMAbstractItemModelData::~QQmlDMAbstractItemModelData() (qqmladaptormodel.cpp:95) ==15748== by 0x58643DC: QQmlDelegateModelPrivate::release(QObject*) (qqmldelegatemodel.cpp:520) ==15748== by 0x586440C: QQmlDelegateModel::release(QObject*) (qqmldelegatemodel.cpp:536) ==15748== by 0x5DFED4F: QQuickItemViewPrivate::releaseItem(FxViewItem*) (qquickitemview.cpp:2349) ==15748== by 0x5DBAB94: QQuickGridViewPrivate::addVisibleItems(double, double, double, double, bool) (qquickgridview.cpp:497) ==15748== by 0x5DFC94E: QQuickItemViewPrivate::refill(double, double) (qquickitemview.cpp:1751) ==15748== by 0x5DFF26A: QQuickItemViewPrivate::layout() (qquickitemview.cpp:1859) ==15748== by 0x5D275F7: QQuickWindowPrivate::polishItems() (qquickwindow.cpp:271) ==15748== by 0x5D02B7D: QSGThreadedRenderLoop::polishAndSync(QSGThreadedRenderLoop::Window*) (qsgthreadedrenderloop.cpp:1150) ==15748== by 0x5D03167: QSGThreadedRenderLoop::event(QEvent*) (qsgthreadedrenderloop.cpp:1235) ==15748== by 0x6659CDC: QCoreApplication::notify(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66599D4: QCoreApplication::notifyInternal(QObject*, QEvent*) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66B00CC: QTimerInfoList::activateTimers() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66B03F0: ??? (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x8EE2E43: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x8EE3087: g_main_context_iterate.isra.24 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x8EE312B: g_main_context_iteration (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4100.0) ==15748== by 0x66B06BB: QEventDispatcherGlib::processEvents(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x66578EA: QEventLoop::exec(QFlags) (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x665EF45: QCoreApplication::exec() (in /usr/lib/x86_64-linux-gnu/libQt5Core.so.5.3.0) ==15748== by 0x40711B: startShell(int, char const**, void*) (main.cpp:171) ==15748== by 0x407A74: main (main.cpp:227) Change-Id: I2c7d38fa5a2566520173bff7ad4e5f9c966d083e Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlobjectcreator.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index a8eeeeeddd..16c9dd7aa0 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -153,6 +153,10 @@ QQmlObjectCreator::~QQmlObjectCreator() if (ps) ps->d = 0; } + while (sharedState->componentAttached) { + QQmlComponentAttached *a = sharedState->componentAttached; + a->rem(); + } delete sharedState.data(); } } @@ -1253,6 +1257,11 @@ void QQmlObjectCreator::clear() while (!sharedState->allCreatedObjects.isEmpty()) delete sharedState->allCreatedObjects.pop(); + while (sharedState->componentAttached) { + QQmlComponentAttached *a = sharedState->componentAttached; + a->rem(); + } + phase = Done; } -- cgit v1.2.3 From c9b39637eed7cc4a8b02db5e0f86839c52348893 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 5 Jun 2014 07:11:54 +0200 Subject: Set locked state while locking for grab. Change-Id: If4b8fa77e6e3a288487a011e83791ad6a189675c Reviewed-by: Manish Sharma <83.manish@gmail.com> Reviewed-by: Laszlo Agocs --- src/quick/scenegraph/qsgthreadedrenderloop.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index ae8d135d83..296050ec2f 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -1277,10 +1277,12 @@ QImage QSGThreadedRenderLoop::grab(QQuickWindow *window) QImage result; w->thread->mutex.lock(); + m_locked = true; QSG_GUI_DEBUG(w->window, " - locking, posting grab event"); w->thread->postEvent(new WMGrabEvent(window, &result)); w->thread->waitCondition.wait(&w->thread->mutex); QSG_GUI_DEBUG(w->window, " - locking, grab done, unlocking"); + m_locked = false; w->thread->mutex.unlock(); QSG_GUI_DEBUG(w->window, " - grab complete"); -- cgit v1.2.3 From e6bf3d444f3818145d7807ad37b6a0ab9f8d4a47 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Tue, 3 Jun 2014 22:44:25 +0200 Subject: Update QtQuick import value to 2.3 The current documentation uses import QtQuick 2.2 which is wrong since there are new APIs like mipmap for the QML Image element. Task-number: QTBUG-39302 Change-Id: I3cc3a1522efd85090c3b4011429fa16b95e79435 Reviewed-by: J-P Nurmi Reviewed-by: Jerome Pasion --- src/qml/doc/src/qmltypereference.qdoc | 2 +- src/quick/doc/src/qmltypereference.qdoc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc index 61d4e67acb..0f98773b70 100644 --- a/src/qml/doc/src/qmltypereference.qdoc +++ b/src/qml/doc/src/qmltypereference.qdoc @@ -55,7 +55,7 @@ are also provided by the \c QtQuick namespace which may be imported as follows: \qml -import QtQuick 2.2 +import QtQuick 2.3 \endqml See the \l{Qt Quick} module documentation for more information about the \c diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 7fc9bea032..f048186d58 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -42,11 +42,11 @@ by this module, organized according to category and purpose. The types provided by the \l {Qt Quick} module are only available in a QML document if that document imports the \c QtQuick namespace. -The current version of the \c QtQuick module is version 2.2, and thus it may be +The current version of the \c QtQuick module is version 2.3, and thus it may be imported via the following statement: \qml -import QtQuick 2.2 +import QtQuick 2.3 \endqml See the \l {Qt Quick} module documentation for more @@ -321,12 +321,12 @@ set of Particle System types for Qt Quick 2 */ /*! -\qmlmodule QtQuick 2.2 +\qmlmodule QtQuick 2.3 \brief The Provides graphical primitives for use in QML. The \l{Qt Quick} module provides graphical primitive types. They can be used with the following import \code -import QtQuick 2.2 +import QtQuick 2.3 \endcode For a more detailed listing of types in the \c {QtQuick} import, see the \l{Qt Quick QML Types} page. -- cgit v1.2.3 From 714d9d95484907378b46292df7aec0832f557f1d Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Sat, 21 Jun 2014 10:56:00 +0200 Subject: Fix memory leak in QQmlComponent::createObject Regression introduced with 5.3.0. Prevent the leak of the object creator on repeated createObject calls by using a scoped pointer. Change-Id: Ib4fe7c9c6926c2390f7ae78f3287bb7da5f60527 Task-number: QTBUG-39742 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlcomponent.cpp | 4 ++-- src/qml/qml/qqmlcomponent_p.h | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index e9a3449a22..1da2f1c109 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -880,7 +880,7 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) enginePriv->referenceScarceResources(); QObject *rv = 0; - state.creator = new QQmlObjectCreator(context, cc, creationContext); + state.creator.reset(new QQmlObjectCreator(context, cc, creationContext)); rv = state.creator->create(start); if (!rv) state.errors = state.creator->errors; @@ -920,7 +920,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, Q_ASSERT(ddata->deferredData); QQmlData::DeferredData *deferredData = ddata->deferredData; QQmlContextData *creationContext = 0; - state->creator = new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext); + state->creator.reset(new QQmlObjectCreator(deferredData->context->parent, deferredData->compiledData, creationContext)); if (!state->creator->populateDeferredProperties(object)) state->errors << state->creator->errors; } diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index e8ae540148..2c70d7b100 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -106,15 +106,13 @@ public: struct ConstructionState { ConstructionState() - : creator(0) - , completePending(false) + : completePending(false) {} ~ConstructionState() { - delete creator; } - QQmlObjectCreator *creator; + QScopedPointer creator; QList errors; bool completePending; }; -- cgit v1.2.3 From 195b998175b629e6e915588e66991f74cffa4e48 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 20 Jun 2014 17:26:57 +0200 Subject: Fix crash when deleting component in Component.onComplete through loader This is a regression introduced with Qt 5.3.0. The recursion watcher code that is supposed to handle the test case of QTBUG-39775 can detect the recursion into the object creator. However the boolean that indicates the recursion is a member of a structure that's deleted afterwards. To avoid access to deleted memory, this patch simply reference counts data structure shared between the creators and also wraps the recursion watcher into a convenience class that also increases/decreases the reference count accordingly. Change-Id: I8d2e3e200ab1295e89d951e09f187d382a056d5a Task-number: QTBUG-39775 Reviewed-by: Lars Knoll --- src/qml/qml/qqmlobjectcreator.cpp | 17 ++++++++++++----- src/qml/qml/qqmlobjectcreator_p.h | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 16c9dd7aa0..36c7dfb0e9 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -91,7 +91,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile init(parentContext); sharedState = new QQmlObjectCreatorSharedState; - sharedState.setFlag(); // We own it, so we must delete it + topLevelCreator = true; sharedState->componentAttached = 0; sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount); sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount); @@ -115,6 +115,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile init(parentContext); sharedState = inheritedSharedState; + topLevelCreator = false; } void QQmlObjectCreator::init(QQmlContextData *providedParentContext) @@ -139,9 +140,9 @@ void QQmlObjectCreator::init(QQmlContextData *providedParentContext) QQmlObjectCreator::~QQmlObjectCreator() { - if (sharedState.flag()) { + if (topLevelCreator) { { - QRecursionWatcher watcher(sharedState.data()); + QQmlObjectCreatorRecursionWatcher watcher(this); } for (int i = 0; i < sharedState->allCreatedBindings.count(); ++i) { QQmlAbstractBinding *b = sharedState->allCreatedBindings.at(i); @@ -157,7 +158,6 @@ QQmlObjectCreator::~QQmlObjectCreator() QQmlComponentAttached *a = sharedState->componentAttached; a->rem(); } - delete sharedState.data(); } } @@ -1172,7 +1172,7 @@ QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interru Q_ASSERT(phase == ObjectsCreated || phase == Finalizing); phase = Finalizing; - QRecursionWatcher watcher(sharedState.data()); + QQmlObjectCreatorRecursionWatcher watcher(this); ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); { @@ -1334,3 +1334,10 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject * } + + +QQmlObjectCreatorRecursionWatcher::QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator) + : sharedState(creator->sharedState) + , watcher(creator->sharedState.data()) +{ +} diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 379a3b2970..ad2d67624f 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -57,7 +57,7 @@ struct QQmlTypeCompiler; class QQmlInstantiationInterrupt; struct QQmlVmeProfiler; -struct QQmlObjectCreatorSharedState +struct QQmlObjectCreatorSharedState : public QSharedData { QQmlContextData *rootContext; QQmlContextData *creationContext; @@ -128,7 +128,8 @@ private: const QVector &propertyCaches; const QVector &vmeMetaObjectData; QHash objectIndexToId; - QFlagPointer sharedState; + QExplicitlySharedDataPointer sharedState; + bool topLevelCreator; void *activeVMEDataForRootContext; QObject *_qobject; @@ -142,6 +143,19 @@ private: QQmlVMEMetaObject *_vmeMetaObject; QQmlListProperty _currentList; QV4::ExecutionContext *_qmlContext; + + friend struct QQmlObjectCreatorRecursionWatcher; +}; + +struct QQmlObjectCreatorRecursionWatcher +{ + QQmlObjectCreatorRecursionWatcher(QQmlObjectCreator *creator); + + bool hasRecursed() const { return watcher.hasRecursed(); } + +private: + QExplicitlySharedDataPointer sharedState; + QRecursionWatcher watcher; }; QT_END_NAMESPACE -- cgit v1.2.3 From 03140436555ad916fbbf77436d567595c614c595 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 30 May 2014 18:01:56 +0200 Subject: Doc: Add documentation for the Maroon in Trouble example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8b272894ef6374aeb6ec09275d7ce96d16a6be0f Reviewed-by: Topi Reiniƶ --- .../doc/images/qtquick-demo-maroon-med-3.jpg | Bin 0 -> 25541 bytes .../doc/images/qtquick-demo-maroon-med-4.jpg | Bin 0 -> 79678 bytes .../doc/images/qtquick-demo-maroon-med-5.jpg | Bin 0 -> 27911 bytes .../doc/images/qtquick-demo-maroon-med-6.jpg | Bin 0 -> 59198 bytes examples/quick/demos/maroon/doc/src/maroon.qdoc | 855 ++++++++++++++++++++- 5 files changed, 851 insertions(+), 4 deletions(-) create mode 100644 examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-3.jpg create mode 100644 examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-4.jpg create mode 100644 examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-5.jpg create mode 100644 examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-6.jpg diff --git a/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-3.jpg b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-3.jpg new file mode 100644 index 0000000000..a83e282d5f Binary files /dev/null and b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-3.jpg differ diff --git a/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-4.jpg b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-4.jpg new file mode 100644 index 0000000000..8a6063b7c7 Binary files /dev/null and b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-4.jpg differ diff --git a/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-5.jpg b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-5.jpg new file mode 100644 index 0000000000..e3e4a2ec89 Binary files /dev/null and b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-5.jpg differ diff --git a/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-6.jpg b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-6.jpg new file mode 100644 index 0000000000..ad6b4bf156 Binary files /dev/null and b/examples/quick/demos/maroon/doc/images/qtquick-demo-maroon-med-6.jpg differ diff --git a/examples/quick/demos/maroon/doc/src/maroon.qdoc b/examples/quick/demos/maroon/doc/src/maroon.qdoc index 59f6397dcf..4b364397c1 100644 --- a/examples/quick/demos/maroon/doc/src/maroon.qdoc +++ b/examples/quick/demos/maroon/doc/src/maroon.qdoc @@ -29,14 +29,861 @@ \title Qt Quick Demo - Maroon in Trouble \ingroup qtquickdemos \example demos/maroon - \brief A cute game designed for touchscreens. - \image qtquick-demo-maroon-med-1.png + \brief A Qt Quick game for touch devices that uses SpriteSequence, + ParticleSystem, Emitter, and Wander types to animate objects and the SoundEffect type to + play sound effects. + \image qtquick-demo-maroon-med-2.png - \e{Maroon in Trouble} demonstrates various QML and \l{Qt Quick} features - such as displaying custom components and playing sound effects. + \e{Maroon in Trouble} demonstrates QML features that are useful when + developing games: + + \list + \li Using custom QML types to create different screens for + different stages of the game. + \li Using the \l Item and \l Image types to construct a game background. + \li Using the SequentialAnimation, NumberAnimation, ParticleSystem, + \l Emitter, and \l Wander types to animate background objects. + \li Using the \l Timer and \l Repeater types to display a countdown + sequence before starting the game. + \li Using a custom QML type with custom properties to construct a game + board. + \li Using the SpriteSequence and \l Sprite types to add animated objects + to the game board. + \li Using a custom QML type that uses the \l Image type with some custom + properties to add a menu where the players can buy objects. + \li Using custom properties with private functions to keep track of game + statistics and a custom QML type to display them to the players. + \li Using the \l State type with JavaScript functions to manage game + states. + \li Using the \l SoundEffect type to play individual sound effects + depending on the object type and the action applied to the object. + \li Using signal handlers to specify keyboard shortcuts for some game + actions. + \li Using resource files to package game resources for deployment and + delivery. + \endlist \include examples-run.qdocinc + \section1 Adding Screens + + In the Maroon in Trouble app, we use the following custom types that + are each defined in a separate .qml file to create the game screens: + + \list + \li NewGameScreen.qml + \li GameCanvas.qml + \li GameOverScreen.qml + \endlist + + To use the custom types, we add an import statement to the main QML file, + maroon.qml that imports the folder called \c content where the types are + located: + + \quotefromfile demos/maroon/maroon.qml + \skipto content + \printuntil " + + We use the screen types at different stages of the game. The NewGameScreen + type is used to create the screen that appears when the players start the + app. In NewGameScreen.qml, we use an \l{Image} type to create a New Game + button that the players can press to start a new game. + + \image qtquick-demo-maroon-med-1.png + + Tapping the button initiates a countdown timer that triggers the creation + of the game canvas by using the GameCanvas type. Another \l{Timer} type + spawns mobs of fish inside bubbles that the players must free before they + reach the surface. The players can tap on the screen to open a menu where + they can buy different types of weapons (melee, ranged, and bombs) to burst + the bubbles. + + \image qtquick-demo-maroon-med-2.png + + When the game finishes, a screen created by using the GameOverScreen type + appears. On this screen, the players can see their score and start a new + game. + + \image qtquick-demo-maroon-med-3.jpg + + The screens are all created on the same background and use some of the same + images and animations. + + \section1 Constructing the Background + + In the maroon.qml file, we use an \l{Item} type with the id \c root and a + fixed width and height to create a main window for the game: + + \skipto Item + \printuntil passedSplash + + We declare two custom properties for the root item, \c gameState and + \c passedSplash that we will use later to manage game states. + + We use an \l{Image} item to display the game background image: + + \printuntil anchors.bottom + + We want to be able to load the background image only once at app startup + and still use different scenes for the game screens. Therefore, + background.png is three times the length of the root item and displays a + scene that stretches from the bottom of sea to the sky above the horizon. + + We use the \c anchors.bottom property to anchor the background image to the + bottom of the \l{Column} layout that we use to position the screens: + + \skipto Column + \printuntil GameOverScreen + + We set a negative value for the \c y property to set the first scene at the + bottom of the sea. We calculate the position by subtracting the height of + a screen from the \c height property. + + Within the column layout, we use an \l{Item} type to add objects to the + background. Within the item, we use \l{Row} layout objects to position + \l{Image} objects that display waves on the game canvas and the game over + screen: + + \printuntil } + \printuntil } + \dots + \skipto Row + \printuntil } + \printuntil } + + The second row of waves is positioned on the y axis with a slight offset to + the first row. We also use the \c opacity property to make the waves appear + lighter in color than the first two waves, which gives the background some + depth. + + We use \l{Image} objects to also display sunlight on the new game screen and + on the game canvas: + + \skipto Image + \printuntil anchors + \dots + \skipto Image + \printuntil anchors + + We set the \c opacity property of the images to \c 0.02 and \c 0.04 to give + some depth to the rays of sunshine. We use the \c y property to position the + images at fixed locations on the y axis and the + \c {anchors.horizontalCenter} property to center them horizontally in + relation to their parent. + + We use an \l {Image} type to display an image that adds a deepening shadow + to the background: + + \skipto Image + \printuntil } + + We set the \c opacity property of the image to \c 0.5 to make the background + visible behind the shadow. + + To make the background more interesting, we animate some of the objects we + added to it. + + \section1 Animating Background Objects + + We use NumberAnimation to move the waves horizontally across the screen in + opposite directions and SequentialAnimation with NumberAnimation to move + them up and down. + + We apply the number animation to the \c x property of \c wave as a property + value source to animate the x value from its current value to the + \c -(wave.width), over 16 seconds. We set the \c loops property to + \c {Animation.Infinite} to repeat the animation indefinitely: + + \quotefromfile demos/maroon/maroon.qml + \skipto wave.width + \printuntil } + + We apply the sequential animation to the \c y property of the image as a + property value source to animate the y value. We use one number animation + to animate the image from the y position of two below the value of y to two + above it, over 1600 milliseconds. We use another number animation to + subsequently animate the image in the opposite direction, again over 1600 + milliseconds. The animation is repeated indefinitely: + + \skipto SequentialAnimation + \printuntil } + \printuntil } + \printuntil } + + We use the easing curve of the type \c {Easing.InOutQuad} for a quintic + (t^5) function to accelerate the motion until halfway and then decelerate + it. + + We use sequential animation and number animation to animate \c wave2 + similarly to \c wave, but in the opposite direction: + + \skipto SequentialAnimation + \printuntil } + \printuntil } + \printuntil } + + We use sequential animation to rotate the rays of sunlight in degrees + clockwise around an origin point that we set to \c {Item.Top} in the + \c transformOrigin property. The animation is repeated indefinitely: + + \skipto transformOrigin + \printuntil to: -10 + \printuntil } + + We use one number animation to rotate the image from \c -10 degrees to + \c 10 degrees over 8 seconds and another to subsequently rotate it from + \c 10 degrees to \c -10 degrees over the same duration. + + We use the easing curve of the type \c {Easing.InOutSine} for a sinusoidal + (sin(t)) function to accelerate the motion until halfway and then decelerate + it. + + We use sequential animation and number animation to animate another + sunlight.png image similarly, but in the opposite direction: + + \skipto transformOrigin + \printuntil to: 10 + \printuntil } + + For examples of using SequentialAnimation and NumberAnimation on the \c x + and \c y properties and the \c width and \c height properties, see + NewGameScreen.qml. + + \section1 Emitting Particles + + In addition to animation, we use particles to generate motion on the game + screens. We use the ParticleSystem QML type in maroon.qml to make bubbles + appear at the bottom of the new game screen and game canvas and slowly float + towards the top on varying trajectories. + + To use the ParticleSystem type, we must import \l{Qt Quick Particles}: + + \quotefromfile demos/maroon/maroon.qml + \skipto Particles + \printuntil 0 + + To have the particles appear on the game background, we place the + ParticleSystem type within the \l{Image} type that displays the game + background: + + \skipto Image + \printuntil anchors.fill + + In the ParticleSystem, we use an \l{Emitter} type to emit particles from the + location of the emitter at the rate of two per second with the life span of + 15 seconds: + + \skipto Emitter + \printuntil sizeVariation + \printuntil } + + The \c acceleration property uses the PointDirection type to + specify random variation of the x and y coordinates, so that the bubbles + appear inside a rectangular area around the emitter that is anchored to the + bottom of the image. + + The \c size property sets the base size of the particles at the beginning of + their life to 24 pixels and the \c sizeVariation property randomly increases + or decreases the particle size by up to 16 pixels, so that we get bubbles in + different sizes. + + As emitters have no visualization, we use the ImageParticle type to render + the catch.png image at the particle location: + + \quotefromfile demos/maroon/maroon.qml + \skipto ImageParticle + \printuntil } + + A \l{Wander} type applies a random trajectory to the particles, so that the + bubbles follow random routes from the bottom to the top. + + \printuntil } + + For another example of using the ParticleSystem type, see the + GameOverScreen.qml file, where an ImageParticle type is used to make clouds + move across the sky. + + \section1 Using Timers + + \image qtquick-demo-maroon-med-4.jpg + + In maroon.qml, we use the \l{Timer} type with a \l{Repeater} type to display + a countdown sequence before using another timer to start a new game. Both + timers are started simultaneously in the \c "gameOn" state, that is when the + players tap the New Game button and \c passedSplash is \c true. This is + explained in more detail in \l{Managing Game States}. + + We use the \c countdownTimer to display the countdown sequence: + + \skipto Timer + \printuntil } + + The \c onTriggered signal handler is called when the timer is triggered to + increment the value of the the \c countdown custom property. + + We set the \c repeat property to \c true to specify that the timer is + triggered at the interval of 1 second as long as the value of \c countdown + is less than 5. + + The \c countdown property is defined in the root item with an initial value + of \c 10, so that \c countdownTimer is not running by default: + + \skipto countdown: + \printuntil 10 + + Each time the timer is triggered, an image from the countdown sequence is + displayed. We use a \l{Repeater} type to instantiate the \l{Image} delegate + in the context of the repeater's parent, \c canvasArea item, seeded with + data from the \c model: + + \quotefromfile demos/maroon/maroon.qml + \skipto Repeater + \printuntil scale + \printuntil } + \printuntil } + \printuntil } + \printuntil } + + We scale the images from \c 0.0 to \c 1.0 and use the \c visible property to + hide the images for the previous steps as the countdown progresses. We also + raise the opacity of the image that matches the current countdown step, + keeping the others nearly transparent. + + By animating the changes in the \c opacity and \c scale properties using a + \l Behavior type, we achieve a countdown sequence where numbers zoom in + towards the players. + + \section1 Constructing the Game Board + + To construct the game board, we use the GameCanvas custom type that is + defined in GameCanvas.qml. + + In maroon.qml, we use the GameCanvas type to display the game canvas + at the position of 32 on the x axis and 20 pixels from the bottom of + its parent item, \c canvasArea: + + \quotefromfile demos/maroon/maroon.qml + \skipto GameCanvas + \printuntil } + + We set the \c focus property to \c true to give \c canvas active focus on + startup. + + In GameCanvas.qml, we use an \l Item type and define custom properties for + it to create a grid of equally sized squares divided to 4 columns on 6 rows: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto Item + \printuntil canvas + + We use the custom properties to set the \c width and \c height of the + \c grid item as the amount of columns and rows multiplied by square size: + + \skipto width + \printuntil height + + We use an \l{Image} type with a MouseArea type to display a help button + that the players can tap to view an image that contains instructions for + playing the game: + + \skipuntil endGame + \skipto Image + \printuntil bottomMargin + \printuntil } + + We declare the \c goAway() private function to disable the mouse area and + make the image fully transparent and a \c comeBack() function to enable the + mouse area and make the button fully opaque. We use a \l {Behavior} type on + the \c opacity property to apply the default number animation when the value + of \c opacity changes. + + When the players tap the help button, the \c onClicked signal handler is + called to hide the help button by setting the \c {helpButton.visible} + property to \c false and to show the help image by setting the + \c {helpImage.visible} property to \c false. + + \image qtquick-demo-maroon-med-6.jpg + + We use anchoring to position the help button at the bottom center of the + game canvas. + + We use another \l{Image} type to to display the help image: + + \printuntil } + \printuntil } + + To hide the help image when the players tap it, the \c onClicked signal + handler within the MouseArea type is called to set the \c{helpImage.visible} + property to \c true. + + To ensure that the images are placed on top when they are visible, we set + a high value for their \c z property. + + The following sections describe how to use timers to add animated objects to + the game board and how to create a menu dialog from which the players can + add more objects to it. + + \section1 Animating Objects on the Game Board + + We use sprite animation to animate objects on the game board. The Qt Quick + \l{Sprite Animations}{sprite engine} is a stochastic state machine combined + with the ability to chop up images containing multiple frames of an + animation. + + \section2 Spawning Fish + + We use a \l{Timer} element with the \c tick() function in GameCanvas.qml to + spawn mobs of fish in waves at an increasing rate, starting at 16 + milliseconds: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto Timer + \printuntil } + + We use the MobBase custom type that is defined in MobBase.qml to + animate mobs of fish that swim inside bubbles. We use an \l{Item} type with + custom properties and private functions to create the fish and the bubbles + and to define the actions that can be applied to them: + + \quotefromfile demos/maroon/content/mobs/MobBase.qml + \skipto Item + \printuntil } + \dots + + We use a SpriteSequence type to animate the fish: + + \skipto SpriteSequence + \printuntil goalSprite + + The SpriteSequence type renders and controls a list of animations + defined by \l{Sprite} types: + + \skipto Sprite { + \printuntil name: "right" + \printuntil } + \printuntil } + + In the \c fishSprite sprite sequence, each sprite defines one frame within + the mob-idle.png file, which shows a fish facing right, front, and left: + + \image ../../content/gfx/mob-idle.png + + We use the \c frameWidth, \c frameHeight, and \c frameX properties to + determine that the first 64x64-pixel square of the image is framed in the + \c "left" sprite, the second in the \c "front" sprite, and the third in the + \c "right" sprite. For each sprite, the \c frameCount property is set to + \c 1 to specify that the sprite contains one frame. + + We use the \c frameDuration and \c frameDurationVariation properties to + specify that the duration of an animation can vary from \c 400 to \c 1200 + milliseconds. + + The \c to property specifies that the sprites have weighted transitions to + other sprites. The \c "left" and \c "right" sprites always transfer to the + \c "front" sprite. When the \c "front" animation finishes, the sprite engine + chooses \c "left" or \c "right" randomly, but at roughly equal proportions, + because they both have the weight \c 1. + + When the fish are set free, we want them to swim away in the direction they + are facing until they get off the screen. If they were facing front, we use + the \c jumpTo method with the JavaScript \c {Math.random()} method in the + \c die() private function to randomly jump to the \c "left" or \c "right" + sprite: + + \quotefromfile demos/maroon/content/mobs/MobBase.qml + \skipto die() + \printuntil } + + We then use the \c start() function to run a NumberAnimation that applies a + number animation to the x value from its current value to \c -360 or \c 360, + depending on whether the \c goingLeft custom property is \c true, in 300 + milliseconds: + + \skipto NumberAnimation + \printuntil } + + \section2 Bursting Bubbles + + We use another SpriteSequence to animate the bubbles so that they + become smaller and finally burst when they are attacked by a shooter or + a melee. For this effect, we set the value of the \c scale property to + decrease by \c 0.2 each time the custom \c hp property changes: + + \skipto SpriteSequence + \printuntil goalSprite + + We use a \l{Behavior} type to apply a NumberAnimation when the value of + \c scale changes. We use the \c{Easing.OutBack} easing type for a back + (overshooting cubic function: (s+1)*t^3 - s*t^2) easing out curve that + decelerates the motion to zero velocity in 150 milliseconds: + + \skipto Behavior + \printuntil } + \printuntil } + + The SpriteSequence consist of two sprites that display different images. The + first sprite, \c "big", uses the catch.png image to display an empty bubble: + + \skipto Sprite + \printuntil } + \printuntil } + + We set the \c to property to \c "burst" with the weight \c 0 to make the + second sprite, \c "burst", a valid goal for the \c jumpTo method that we use + in the \c die() private function to jump directly to the \c "burst" sprite + without playing the first sprite. + + In the \c "burst" sprite, we set the \c frameCount property to \c 3 and the + \c frameX property to \c 64 to specify that the animation starts at pixel + location 64 and loads each frame for the duration of 200 milliseconds. + + \skipto Sprite + \printuntil } + + Within the SpriteSequence, we use SequentialAnimation with NumberAnimation + to animate the transitions between the frames. To create a pulsating effect + on the bubbles, we apply a sequential animation on the \c width property + with two number animations to first increase the bubble width from + \c{* 1} to \c{* 1.1} over 800 milliseconds and then bring it back over 1 + second: + + \skipto SequentialAnimation + \printuntil } + \printuntil } + \printuntil } + + Similarly, we increase the bubble height from \c{* 1} to \c{* 1.15} over + 1200 milliseconds and then bring it back over 1 second: + + \skipto SequentialAnimation + \printuntil } + \printuntil } + \printuntil } + + We use yet another SpriteSequence to display the effect of squid ink on the + bubbles. For more examples of using sprite sequences, see the QML files in + the \c towers directory. + + \section1 Adding Dialogs + + \image qtquick-demo-maroon-med-5.jpg + + In GameCanvas.qml, we use an \l{Image} type with some custom properties to + create a menu where the players can buy tower objects: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto Image + \printuntil towerExists + + We set the \c visible property to \c false to hide the menu by default. The + \c z property is set to 1500 to ensure that the menu is displayed in front + of all other items when it is visible. + + We use a MouseArea type to open or close the menu when players tap on the + canvas: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto MouseArea + \printuntil } + \printuntil } + + We set the \c anchors.fill property to \c parent to allow the players to tap + anywhere on the game canvas. We use a condition in the \c onClicked + signal handler to call the \c {finish()} function if the menu is visible + and the \c {open()} function otherwise. + + The \c {finish()} function hides the menu by setting the \c shown custom + property to \c false: + + \skipto finish + \printuntil } + + The \c {open()} function displays the menu at the x and y position of the + mouse pointer: + + \printuntil } + + If \c gameRunning is \c true, we call the JavaScript \c row() function to + calculate the value of the \c targetRow custom property and the \c col() + function to calculate the value of the \c targetCol custom property. If + the value of \c targetRow equals \c 0, the y position is set to one square + above the mouse pointer. Otherwise, it is set to one square below the mouse + pointer. + + We use the \c towerIdx() function to set the value of the \c towerExists + custom property. + + We set the \c shown custom property to \c true to show the menu and call the + \c {helpButton.goAway()} function to hide the help button when the menu + opens. + + We use states and transitions to display the menu when the \c shown + property is \c true and the \c gameOver property is \c false: + + \printuntil OutElastic + \printuntil } + + To set the visibility of the menu to \c "visible" without animating the + property change, we use a PropertyAction type. We do want to animate the + changes in opacity and scale, though, so we use number animation to + animate the value of the \c scale property from \c 0.9 to \c 1 and the + value of \c opacity property from \c 0.7 to \c 1, over 500 milliseconds. + We use the \c {Easing.outElastic} easing type for an elastic (exponentially + decaying sine wave) function easing curve that decelerates from zero + velocity. + + To construct the menu, we use a BuildButton custom type that is defined in + BuildButton.qml. In GameCanvas.qml, we create one build button for each + tower object that the players can buy and position them in a \l{Row} layout + in front of the menu background image, dialog.png: + + \printuntil dialog-factory.png + \printuntil } + \printuntil } + \printuntil } + + For each build button, we set the values of \c towerType and \c index custom + properties that we define in BuildButton.qml. + + We use the \c canBuild custom property to prevent players from adding tower + objects in locations where tower objects already exist. + + We use the \c source property to display the image for the tower type. + + The \c onClicked signal handler is called to execute the \c finish() + function that closes the menu when the players tap an enabled build button. + + Build buttons are enabled when the players have enough coins to buy the + tower objects. We use an \l {Image} type in BuildButton.qml to display + images on the buttons: + + \quotefromfile demos/maroon/content/BuildButton.qml + \skipto Image + \printuntil } + + We use the \c opacity property to make the buttons appear enabled. If + \c canBuild is \c true and the value of the \c gameCanvas.coins property + is larger than or equal to the cost of a tower object, the images are fully + opaque, otherwise their opacity is set to \c 0.4. + + We use a \l{Text} type to display the cost of each tower item, as specified + by the the \c towerData variable, depending on \c towerType: + + \skipto Text + \printuntil } + + To display a pointer on the screen at the position where the tower object + will be added, we use the \l {Image} type. We use the \c visible property + to determine whether the dialog-pointer.png image should be positioned below + or above the menu. When the value of the \c col property equals the \c index + and the value or the \c row property is not \c 0, we anchor the image to the + bottom of its parent, BuildButton. + + When the value or the \c row property is \c 0, we anchor the image to the + top of BuildButton to position the pointer above the menu and use the + \c rotation property to rotate it by 180 degrees, so that it points upwards: + + \skipto Image + \printuntil } + \printuntil } + + \section1 Keeping Track of Game Statistics + + To keep track of the game statistics, we use the InfoBar custom type (that + is defined in InfoBar.qml) in maroon.qml: + + \quotefromfile demos/maroon/maroon.qml + \skipto InfoBar + \printuntil } + + We use the \c {anchors.bottom} and \c {anchors.bottomMargin} properties to + position the info bar at 6 points from the top of the game canvas. We bind + the \c width property of the info bar to that of its parent. + + In InfoBar.qml, we use an \l{Item} type to create the info bar. Within it, + we use a \l{Row} layout type to display the number of lives the players have + left, the number of fish that have been saved, and the amount of coins that + are available for use. + + We use the \c anchors property to position the rows in relationship to their + parent and to each other. In the first \l{Row} object, we use the + \c {anchors.left} and \c {anchors.leftMargin} properties to position the + heart icons at 10 points from the left border of the parent item: + + \quotefromfile demos/maroon/content/InfoBar.qml + \skipto Item + \printuntil } + \printuntil } + \printuntil } + + We use a \l{Repeater} type with a \c model and a \c delegate to display as + many hearts as the players have lives left. We use the \c spacing property + to leave 5 pixels between the displayed icons. + + In the second \l{Row} object, we use the \c {anchors.right} and + \c {anchors.rightMargin} properties to position the number of fish saved at + 20 points left of the third \l{Row} object that displays the number of coins + available (and has the id \c points): + + \skipto Row + \printuntil /^\}/ + + In these objects, we set spacing to 5 pixels to separate the icons from the + numbers that we display by using a \l{Text} type. + + In GameCanvas.qml, we define custom properties to hold the game statistics: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto score + \printuntil lives + + We declare the \c freshState() function to set the initial game statistics + when a new game starts: + + \skipto freshState() + \printuntil } + + We use the \c {Logic.gameState.score} variable in the \c die() function + that we declare in MobBase.qml to increase the score by one when the players + set a fish free: + + \quotefromfile demos/maroon/content/mobs/MobBase.qml + \skipto score + \printuntil ; + + \section1 Managing Game States + + In maroon.qml, we use a \l{State} type and JavaScript to switch between + screens according to the game state. The logic.js file contains definitions + for the functions. To use the functions in a QML file, we import logic.js as + the \c Logic namespace in that file: + + \quotefromfile demos/maroon/maroon.qml + \skipto logic.js + \printuntil Logic + + The base state displays the new game screen when the application starts. + In addition, we call the Component.onCompleted signal handler to initialize + a new game: + + \skipto newGameState + \printuntil ; + + In NewGameScreen.qml we use the \c onClicked signal handler to emit the + \c startButtonClicked() signal when the players tap the New Game button: + + \quotefromfile demos/maroon/content/NewGameScreen.qml + \skipto to: 150 + \skipto Image + \printuntil } + + In maroon.qml, we use the \c onStartButtonClicked signal handler to set the + \c passedSplash property of the \c root item to \c true: + + \quotefromfile demos/maroon/maroon.qml + \skipto NewGameScreen + \printuntil } + + We then use the \c passedSplash property in the \c when property of the + \c gameOn state to trigger the \c gameStarter timer: + + \skipto State { + \printuntil gameStarter + \printuntil } + + We also switch to the \c "gameOn" state and move to the y position + \c {-(height - 960)} to display the game canvas. + + In the \c gameStarter \l{Timer} object we use the \c onTriggered signal + handler to call the \c startGame() function that starts a new game: + + \quotefromfile demos/maroon/maroon.qml + \skipto property int + \skipto Timer + \printuntil } + + The game continues until \c gameState.gameOver is set to \c true and + \c gameState.gameRunning is set to \c false by calling the \c endGame() + function when the value of the \c gameState.lives property becomes less + than or equal to \c 0. + + In GameOverScreen.qml, we use a MouseArea type and an \c onClicked signal + handler within an \l{Image} type to return to the game canvas when the + players tap the New Game button: + + \quotefromfile demos/maroon/content/GameOverScreen.qml + \skipto opacity: 0.5 + \skipto Image + \printuntil } + \printuntil } + + The \c onClicked signal handler triggers a state change in maroon.qml to + display the game canvas: + + \quotefromfile demos/maroon/maroon.qml + \skipto target: gameStarter + \skipto State + \printuntil } + \printuntil } + + \section1 Playing Sound Effects + + The app can play sound effects if the \l{Qt Multimedia} module is installed. + In the SoundEffect.qml file, we proxy a SoundEffect type: + + \quotefromfile demos/maroon/content/SoundEffect.qml + \skipto Item + \printuntil } + \printuntil } + + We add the \c qtHaveModule() qmake command to the app .pro file, maroon.pro, + to check whether the \l{Qt Multimedia} module is present: + + \quotefromfile demos/maroon/maroon.pro + \skipto QT + \printuntil multimedia + + In each QML file that defines a custom type used on the game canvas, we + use a SoundEffect type to specify the audio file to play for that type + of objects. For example, in Bomb.qml, we specify the sound that a bomb + makes when it explodes: + + \quotefromfile demos/maroon/content/towers/Bomb.qml + \skipto SoundEffect + \printuntil } + + To play the sound effect when a bomb explodes, we call the \c sound.play() + function that we declare as a member of the private \c fire() function + within the TowerBase custom type: + + \quotefromfile demos/maroon/content/towers/Bomb.qml + \skipto fire() + \printuntil } + + For more examples of playing sound effects, see the QML files in the + \c towers directory and MobBase.qml. + + \section1 Adding Keyboard Shortcuts + + This is a touch example, so you should not really need to handle key + presses. However, we do not want you to have to spend more time playing the + game than you want to while testing it, so we use the \c {Keys.onPressed} + signal handler to specify keyboard shortcuts. You can press Shift+Up to + increment the values of the \c coins property to add coins, Shift+Left to + increment the value of \c lives, Shift+Down to increment the value of the + \c waveProgress property to spawn mobs of fish faster, and Shift+Right to + call the \c endGame() function to quit the game: + + \quotefromfile demos/maroon/content/GameCanvas.qml + \skipto Keys + \printuntil } + + \section1 Packaging Resources for Deployment + + To be able to run the app on mobile devices, we package all QML, JavaScript, + image, and sound files into a Qt resource file (.qrc). For more information, + see \l{The Qt Resource System}. + \sa {QML Applications} */ -- cgit v1.2.3 From 5da2576633bc0d0150a8607a30ab1f66f040bb19 Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Tue, 24 Jun 2014 23:35:22 +0100 Subject: Fix intermittent crash with older MinGW releases An alternate code-path was previously added to work around a bad signature for the SHParseDisplayName() function in older and non-w64 versions of the MinGW headers. This code-path incorrectly passed a single rather double indirect pointer to the third argument of that function causing it to produce corrupt data and subsequently crash. This change modifies the code to instead cast a pointer of the correct type to the incorrect type expected by the headers. Task-number: QTBUG-39793 Change-Id: I4d65dea4fc38d7e885468cd23434d8570c311fc2 Reviewed-by: Friedemann Kleint --- src/qml/qml/qqmlengine.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 0424c57f97..70d0c3ad40 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -2306,20 +2306,17 @@ static inline QString shellNormalizeFileName(const QString &name) // The correct declaration of the SHGetPathFromIDList symbol is // being used in mingw-w64 as of r6215, which is a v3 snapshot. #if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) - ITEMIDLIST file; - if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL))) - return name; - TCHAR buffer[MAX_PATH]; - if (!SHGetPathFromIDList(&file, buffer)) + ITEMIDLIST *file; + if (FAILED(SHParseDisplayName(nameC, NULL, reinterpret_cast(&file), 0, NULL))) return name; #else PIDLIST_ABSOLUTE file; if (FAILED(SHParseDisplayName(nameC, NULL, &file, 0, NULL))) return name; +#endif TCHAR buffer[MAX_PATH]; if (!SHGetPathFromIDList(file, buffer)) return name; -#endif QString canonicalName = QString::fromWCharArray(buffer); // Upper case drive letter if (canonicalName.size() > 2 && canonicalName.at(1) == QLatin1Char(':')) -- cgit v1.2.3 From 0ca2b46893f73ec1dff9440cd462f9c64b989335 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 17 Sep 2013 15:05:04 +0200 Subject: Avoid double deletion of QQuickWindow It's uncertain why 4fc0df58b8458052a818e3e970a97457882808e6 added the call to sendPostedEvents(0, QEvent::DeferredDelete) but now we can see that it easily results in the destructor calling itself, and therefore double-deleting its own d_ptr. removePostedEvents seems safer to ensure that the window cannot be doubly deleted, in spite of the qdoc warning that "You should never need to call this function." Task-number: QTBUG-33436 Change-Id: I4873ebe179dde551407eba1f6baac5f03ca7f177 Reviewed-by: J-P Nurmi Reviewed-by: Alan Alpert --- src/quick/items/qquickwindow.cpp | 1 + .../quick/qquickwindow/data/unloadSubWindow.qml | 22 +++++++++++++++++++++ tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 23 ++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/auto/quick/qquickwindow/data/unloadSubWindow.qml diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index e78f9141a8..6276bedc0b 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1093,6 +1093,7 @@ QQuickWindow::~QQuickWindow() d->windowManager->windowDestroyed(this); } + QCoreApplication::removePostedEvents(this, QEvent::DeferredDelete); QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); delete d->incubationController; d->incubationController = 0; #ifndef QT_NO_DRAGANDDROP diff --git a/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml b/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml new file mode 100644 index 0000000000..bf9df4867d --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/unloadSubWindow.qml @@ -0,0 +1,22 @@ +import QtQuick 2.3 +import QtQuick.Window 2.2 + +Window { + id: root + property var transientWindow + property Loader loader1: Loader { + sourceComponent: Item { + Loader { + id: loader2 + sourceComponent : Window { + id: inner + visible: true + Component.onCompleted: root.transientWindow = inner + } + } + Component.onDestruction: { + loader2.active = false; + } + } + } +} diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index b05146fa3a..b8f9102775 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include "../../shared/util.h" #include "../shared/visualtestutil.h" #include @@ -347,6 +348,8 @@ private slots: void crashWhenHoverItemDeleted(); + void unloadSubWindow(); + void qobjectEventFilter_touch(); void qobjectEventFilter_key(); void qobjectEventFilter_mouse(); @@ -1705,6 +1708,26 @@ void tst_qquickwindow::crashWhenHoverItemDeleted() } } +// QTBUG-33436 +void tst_qquickwindow::unloadSubWindow() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("unloadSubWindow.qml")); + QQuickWindow *window = qobject_cast(component.create()); + QVERIFY(window); + window->show(); + QTest::qWaitForWindowExposed(window); + QQuickWindow *transient = Q_NULLPTR; + QTRY_VERIFY(transient = window->property("transientWindow").value()); + QTest::qWaitForWindowExposed(transient); + + // Unload the inner window (in nested Loaders) and make sure it doesn't crash + QQuickLoader *loader = window->property("loader1").value(); + loader->setActive(false); + QTRY_VERIFY(!transient->isVisible()); +} + // QTBUG-32004 void tst_qquickwindow::qobjectEventFilter_touch() { -- cgit v1.2.3 From 87a5889029aed8c53a4b02a42804d036614db36b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 27 Jun 2014 15:14:33 +0200 Subject: Skip rssnews demo if xmlpatterns is not present Otherwise builds without the QtXmlPatterns module will fail. Change-Id: I11d0b84653f8d59787b09cd9c12977d18be92729 Reviewed-by: Jerome Pasion --- examples/quick/demos/demos.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/quick/demos/demos.pro b/examples/quick/demos/demos.pro index c1768ce721..9aac7bf6f7 100644 --- a/examples/quick/demos/demos.pro +++ b/examples/quick/demos/demos.pro @@ -5,8 +5,9 @@ SUBDIRS = samegame \ tweetsearch \ maroon \ photosurface \ - rssnews \ stocqt +qtHaveModule(xmlpatterns): SUBDIRS += rssnews + EXAMPLE_FILES = \ photoviewer -- cgit v1.2.3