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(-) (limited to 'examples') 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(-) (limited to 'examples') 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 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 (limited to 'examples') 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 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 (limited to 'examples') 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 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 (limited to 'examples') 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 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(-) (limited to 'examples') 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