summaryrefslogtreecommitdiffstats
path: root/src/declarative/fx
diff options
context:
space:
mode:
authorMichael Brasser <michael.brasser@nokia.com>2009-04-22 04:47:24 (GMT)
committerMichael Brasser <michael.brasser@nokia.com>2009-04-22 04:47:24 (GMT)
commit2366667fc97eb6a56203b2dd7dac776ff4164abd (patch)
treeb2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/fx
parent2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff)
downloadQt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip
Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz
Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/fx')
-rw-r--r--src/declarative/fx/fx.pri94
-rw-r--r--src/declarative/fx/qfxanchors.cpp857
-rw-r--r--src/declarative/fx/qfxanchors.h194
-rw-r--r--src/declarative/fx/qfxanchors_p.h105
-rw-r--r--src/declarative/fx/qfxanimatedimageitem.cpp211
-rw-r--r--src/declarative/fx/qfxanimatedimageitem.h100
-rw-r--r--src/declarative/fx/qfxanimatedimageitem_p.h77
-rw-r--r--src/declarative/fx/qfxblendedimage.cpp249
-rw-r--r--src/declarative/fx/qfxblendedimage.h105
-rw-r--r--src/declarative/fx/qfxblurfilter.cpp462
-rw-r--r--src/declarative/fx/qfxblurfilter.h82
-rw-r--r--src/declarative/fx/qfxcomponentinstance.cpp132
-rw-r--r--src/declarative/fx/qfxcomponentinstance.h89
-rw-r--r--src/declarative/fx/qfxcomponentinstance_p.h76
-rw-r--r--src/declarative/fx/qfxcontentwrapper.cpp129
-rw-r--r--src/declarative/fx/qfxcontentwrapper.h90
-rw-r--r--src/declarative/fx/qfxcontentwrapper_p.h71
-rw-r--r--src/declarative/fx/qfxflickable.cpp1113
-rw-r--r--src/declarative/fx/qfxflickable.h195
-rw-r--r--src/declarative/fx/qfxflickable_p.h166
-rw-r--r--src/declarative/fx/qfxfocuspanel.cpp104
-rw-r--r--src/declarative/fx/qfxfocuspanel.h81
-rw-r--r--src/declarative/fx/qfxfocusrealm.cpp72
-rw-r--r--src/declarative/fx/qfxfocusrealm.h67
-rw-r--r--src/declarative/fx/qfxgridview.cpp1469
-rw-r--r--src/declarative/fx/qfxgridview.h148
-rw-r--r--src/declarative/fx/qfxhighlightfilter.cpp315
-rw-r--r--src/declarative/fx/qfxhighlightfilter.h98
-rw-r--r--src/declarative/fx/qfximage.cpp935
-rw-r--r--src/declarative/fx/qfximage.h124
-rw-r--r--src/declarative/fx/qfximage_p.h117
-rw-r--r--src/declarative/fx/qfximageitem.cpp343
-rw-r--r--src/declarative/fx/qfximageitem.h100
-rw-r--r--src/declarative/fx/qfximageitem_p.h95
-rw-r--r--src/declarative/fx/qfxitem.cpp1751
-rw-r--r--src/declarative/fx/qfxitem.h285
-rw-r--r--src/declarative/fx/qfxitem_p.h182
-rw-r--r--src/declarative/fx/qfxkeyactions.cpp930
-rw-r--r--src/declarative/fx/qfxkeyactions.h319
-rw-r--r--src/declarative/fx/qfxkeyproxy.cpp116
-rw-r--r--src/declarative/fx/qfxkeyproxy.h78
-rw-r--r--src/declarative/fx/qfxlayouts.cpp1027
-rw-r--r--src/declarative/fx/qfxlayouts.h171
-rw-r--r--src/declarative/fx/qfxlayouts_p.h100
-rw-r--r--src/declarative/fx/qfxlistview.cpp1680
-rw-r--r--src/declarative/fx/qfxlistview.h157
-rw-r--r--src/declarative/fx/qfxmouseregion.cpp589
-rw-r--r--src/declarative/fx/qfxmouseregion.h162
-rw-r--r--src/declarative/fx/qfxmouseregion_p.h101
-rw-r--r--src/declarative/fx/qfxpainted.cpp193
-rw-r--r--src/declarative/fx/qfxpainted.h84
-rw-r--r--src/declarative/fx/qfxpainted_p.h84
-rw-r--r--src/declarative/fx/qfxparticles.cpp1063
-rw-r--r--src/declarative/fx/qfxparticles.h240
-rw-r--r--src/declarative/fx/qfxpath.cpp745
-rw-r--r--src/declarative/fx/qfxpath.h257
-rw-r--r--src/declarative/fx/qfxpath_p.h79
-rw-r--r--src/declarative/fx/qfxpathview.cpp841
-rw-r--r--src/declarative/fx/qfxpathview.h132
-rw-r--r--src/declarative/fx/qfxpathview_p.h132
-rw-r--r--src/declarative/fx/qfxpixmap.cpp284
-rw-r--r--src/declarative/fx/qfxpixmap.h92
-rw-r--r--src/declarative/fx/qfxrect.cpp851
-rw-r--r--src/declarative/fx/qfxrect.h140
-rw-r--r--src/declarative/fx/qfxrect_p.h107
-rw-r--r--src/declarative/fx/qfxreflectionfilter.cpp358
-rw-r--r--src/declarative/fx/qfxreflectionfilter.h96
-rw-r--r--src/declarative/fx/qfxrepeater.cpp354
-rw-r--r--src/declarative/fx/qfxrepeater.h88
-rw-r--r--src/declarative/fx/qfxrepeater_p.h81
-rw-r--r--src/declarative/fx/qfxscalegrid.cpp216
-rw-r--r--src/declarative/fx/qfxscalegrid.h120
-rw-r--r--src/declarative/fx/qfxshadowfilter.cpp202
-rw-r--r--src/declarative/fx/qfxshadowfilter.h86
-rw-r--r--src/declarative/fx/qfxtext.cpp958
-rw-r--r--src/declarative/fx/qfxtext.h153
-rw-r--r--src/declarative/fx/qfxtext_p.h132
-rw-r--r--src/declarative/fx/qfxtextedit.cpp804
-rw-r--r--src/declarative/fx/qfxtextedit.h187
-rw-r--r--src/declarative/fx/qfxtextedit_p.h102
-rw-r--r--src/declarative/fx/qfxtransform.cpp661
-rw-r--r--src/declarative/fx/qfxtransform.h274
-rw-r--r--src/declarative/fx/qfxvisualitemmodel.cpp690
-rw-r--r--src/declarative/fx/qfxvisualitemmodel.h120
-rw-r--r--src/declarative/fx/qfxwebview.cpp1079
-rw-r--r--src/declarative/fx/qfxwebview.h217
-rw-r--r--src/declarative/fx/qfxwidgetcontainer.cpp108
-rw-r--r--src/declarative/fx/qfxwidgetcontainer.h79
88 files changed, 28802 insertions, 0 deletions
diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri
new file mode 100644
index 0000000..b8b62b9
--- /dev/null
+++ b/src/declarative/fx/fx.pri
@@ -0,0 +1,94 @@
+HEADERS += \
+ fx/qfxanchors.h \
+ fx/qfxanchors_p.h \
+ fx/qfxanimatedimageitem.h \
+ fx/qfxblendedimage.h \
+ fx/qfxblurfilter.h \
+ fx/qfxcomponentinstance.h \
+ fx/qfxcomponentinstance_p.h \
+ fx/qfxcontentwrapper.h \
+ fx/qfxcontentwrapper_p.h \
+ fx/qfxflickable.h \
+ fx/qfxflickable_p.h \
+ fx/qfxfocuspanel.h \
+ fx/qfxfocusrealm.h \
+ fx/qfxgridview.h \
+ fx/qfxhighlightfilter.h \
+ fx/qfximage.h \
+ fx/qfximageitem.h \
+ fx/qfximageitem_p.h \
+ fx/qfximage_p.h \
+ fx/qfxitem.h \
+ fx/qfxitem_p.h \
+ fx/qfxkeyactions.h \
+ fx/qfxkeyproxy.h \
+ fx/qfxlayouts.h \
+ fx/qfxlayouts_p.h \
+ fx/qfxmouseregion.h \
+ fx/qfxmouseregion_p.h \
+ fx/qfxpainted.h \
+ fx/qfxpainted_p.h \
+ fx/qfxparticles.h \
+ fx/qfxpath.h \
+ fx/qfxpath_p.h \
+ fx/qfxpathview.h \
+ fx/qfxpathview_p.h \
+ fx/qfxrect.h \
+ fx/qfxrect_p.h \
+ fx/qfxreflectionfilter.h \
+ fx/qfxrepeater.h \
+ fx/qfxrepeater_p.h \
+ fx/qfxscalegrid.h \
+ fx/qfxshadowfilter.h \
+ fx/qfxtextedit.h \
+ fx/qfxtextedit_p.h \
+ fx/qfxtext.h \
+ fx/qfxtext_p.h \
+ fx/qfxtransform.h \
+ fx/qfxpixmap.cpp \
+ fx/qfxvisualitemmodel.h \
+ fx/qfxlistview.h \
+ fx/qfxwidgetcontainer.h \
+
+SOURCES += \
+ fx/qfxanchors.cpp \
+ fx/qfxanimatedimageitem.cpp \
+ fx/qfxblendedimage.cpp \
+ fx/qfxblurfilter.cpp \
+ fx/qfxcomponentinstance.cpp \
+ fx/qfxcontentwrapper.cpp \
+ fx/qfxflickable.cpp \
+ fx/qfxfocuspanel.cpp \
+ fx/qfxfocusrealm.cpp \
+ fx/qfxgridview.cpp \
+ fx/qfxhighlightfilter.cpp \
+ fx/qfximage.cpp \
+ fx/qfximageitem.cpp \
+ fx/qfxitem.cpp \
+ fx/qfxkeyactions.cpp \
+ fx/qfxkeyproxy.cpp \
+ fx/qfxlayouts.cpp \
+ fx/qfxmouseregion.cpp \
+ fx/qfxpainted.cpp \
+ fx/qfxparticles.cpp \
+ fx/qfxpath.cpp \
+ fx/qfxpathview.cpp \
+ fx/qfxrect.cpp \
+ fx/qfxreflectionfilter.cpp \
+ fx/qfxrepeater.cpp \
+ fx/qfxscalegrid.cpp \
+ fx/qfxshadowfilter.cpp \
+ fx/qfxtext.cpp \
+ fx/qfxtextedit.cpp \
+ fx/qfxtransform.cpp \
+ fx/qfxpixmap.cpp \
+ fx/qfxvisualitemmodel.cpp \
+ fx/qfxlistview.cpp \
+ fx/qfxwidgetcontainer.cpp \
+
+contains(QT_CONFIG, webkit) {
+ QT+=webkit
+ SOURCES += fx/qfxwebview.cpp
+ HEADERS += fx/qfxwebview.h
+}
+
diff --git a/src/declarative/fx/qfxanchors.cpp b/src/declarative/fx/qfxanchors.cpp
new file mode 100644
index 0000000..b7a7dd2
--- /dev/null
+++ b/src/declarative/fx/qfxanchors.cpp
@@ -0,0 +1,857 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxanchors_p.h"
+#include "qfxitem.h"
+#include <QDebug>
+#include <QtDeclarative/qmlinfo.h>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxAnchors,Anchors);
+
+//TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)?
+//TODO: baseline support
+//TODO: support non-parent, non-sibling (need to find lowest common ancestor)
+
+//### const item?
+//local position
+static qreal position(QFxItem *item, QFxAnchorLine::AnchorLine anchorLine)
+{
+ qreal ret = 0.0;
+ switch(anchorLine) {
+ case QFxAnchorLine::Left:
+ ret = item->x();
+ break;
+ case QFxAnchorLine::Right:
+ ret = item->x() + item->width();
+ break;
+ case QFxAnchorLine::Top:
+ ret = item->y();
+ break;
+ case QFxAnchorLine::Bottom:
+ ret = item->y() + item->height();
+ break;
+ case QFxAnchorLine::HCenter:
+ ret = item->x() + item->width()/2;
+ break;
+ case QFxAnchorLine::VCenter:
+ ret = item->y() + item->height()/2;
+ break;
+ case QFxAnchorLine::Baseline:
+ ret = item->y() + item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+//position when origin is 0,0
+static qreal adjustedPosition(QFxItem *item, QFxAnchorLine::AnchorLine anchorLine)
+{
+ int ret = 0;
+ switch(anchorLine) {
+ case QFxAnchorLine::Left:
+ ret = 0;
+ break;
+ case QFxAnchorLine::Right:
+ ret = item->width();
+ break;
+ case QFxAnchorLine::Top:
+ ret = 0;
+ break;
+ case QFxAnchorLine::Bottom:
+ ret = item->height();
+ break;
+ case QFxAnchorLine::HCenter:
+ ret = item->width()/2;
+ break;
+ case QFxAnchorLine::VCenter:
+ ret = item->height()/2;
+ break;
+ case QFxAnchorLine::Baseline:
+ ret = item->baselineOffset();
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ \internal
+ \class QFxAnchors
+ \ingroup layouts
+ \brief The QFxAnchors class provides a way to lay out items relative to other items.
+
+ \warning Currently, only anchoring to siblings or parent is supported.
+*/
+
+QFxAnchors::QFxAnchors(QObject *parent)
+ : QObject(*new QFxAnchorsPrivate(), parent)
+{
+
+}
+
+void QFxAnchors::fillChanged()
+{
+ Q_D(QFxAnchors);
+ if (!d->fill)
+ return;
+
+ if (d->fill == d->item->itemParent()) { //child-parent
+ d->item->setPos(QPointF(leftMargin(), topMargin()));
+ } else if (d->fill->itemParent() == d->item->itemParent()) { //siblings
+ d->item->setPos(QPointF(d->fill->x()+leftMargin(), d->fill->y()+topMargin()));
+ }
+ d->item->setWidth(d->fill->width()-leftMargin()-rightMargin());
+ d->item->setHeight(d->fill->height()-topMargin()-bottomMargin());
+}
+
+/*!
+ \property QFxAnchors::fill
+ \brief what item the item should fill.
+
+ This is a convenience property. It is the same as anchoring the left, right, top, and bottom
+ to another item's left, right, top, and bottom.
+*/
+QFxItem *QFxAnchors::fill() const
+{
+ Q_D(const QFxAnchors);
+ return d->fill;
+}
+
+void QFxAnchors::setFill(QFxItem *f)
+{
+ Q_D(QFxAnchors);
+ if(d->fill) {
+ QObject::disconnect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged()));
+ QObject::disconnect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged()));
+ }
+
+ d->fill = f;
+
+ if (d->fill) {
+ if (d->fill == d->item->itemParent()) { //child-parent
+ QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged()));
+ QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged()));
+ } else if (f->itemParent() == d->item->itemParent()) { //siblings
+ QObject::connect(d->fill, SIGNAL(leftChanged()), this, SLOT(fillChanged()));
+ QObject::connect(d->fill, SIGNAL(topChanged()), this, SLOT(fillChanged()));
+ QObject::connect(d->fill, SIGNAL(widthChanged()), this, SLOT(fillChanged()));
+ QObject::connect(d->fill, SIGNAL(heightChanged()), this, SLOT(fillChanged()));
+ } else {
+ qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling.";
+ }
+ }
+ QObject::connect(this, SIGNAL(leftMarginChanged()), this, SLOT(fillChanged()));
+ QObject::connect(this, SIGNAL(topMarginChanged()), this, SLOT(fillChanged()));
+ QObject::connect(this, SIGNAL(rightMarginChanged()), this, SLOT(fillChanged()));
+ QObject::connect(this, SIGNAL(bottomMarginChanged()), this, SLOT(fillChanged()));
+ fillChanged(); //### can/should we defer until component completion?
+}
+
+/*!
+ \property QFxAnchors::centeredIn
+ \brief what item the item should stay centered in the middle of.
+
+ This is a convenience property. It is the same as anchoring the horizontalCenter
+ and verticalCenter to another item's horizontalCenter and verticalCenter.
+*/
+QFxItem *QFxAnchors::centeredIn() const
+{
+ Q_D(const QFxAnchors);
+ return d->centeredIn;
+}
+
+void QFxAnchors::setCenteredIn(QFxItem* c)
+{
+ Q_D(QFxAnchors);
+ if(!c){
+ qmlInfo(d->item) << "Cannot center in null item.";
+ return;
+ }
+ if(c != d->item->itemParent() && c->itemParent() != d->item->itemParent()){
+ qmlInfo(d->item) << "Can't anchor to an item that isn't a parent or sibling.";
+ return;
+ }
+ d->centeredIn = c;
+ setHorizontalCenter(c->horizontalCenter());
+ setVerticalCenter(c->verticalCenter());
+}
+
+void QFxAnchorsPrivate::connectVHelper(const QFxAnchorLine &edge, const char *slotString)
+{
+ //### should we do disconnects first? (will it be called more than once?)
+ Q_Q(QFxAnchors);
+ if (edge.item == item->itemParent()) { //child-parent
+ switch(edge.anchorLine) {
+ case QFxAnchorLine::Bottom:
+ case QFxAnchorLine::VCenter:
+ QObject::connect(edge.item, SIGNAL(heightChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::Top: //no connection needed
+ default:
+ break;
+ }
+ } else if (edge.item->itemParent() == item->itemParent()) { //siblings
+ switch(edge.anchorLine) {
+ case QFxAnchorLine::Top:
+ QObject::connect(edge.item, SIGNAL(topChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::Bottom:
+ QObject::connect(edge.item, SIGNAL(bottomChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::VCenter:
+ QObject::connect(edge.item, SIGNAL(vcenterChanged()), q, slotString);
+ break;
+ default:
+ break;
+ }
+ } else {
+ qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling.";
+ }
+}
+
+void QFxAnchors::connectVAnchors()
+{
+ Q_D(QFxAnchors);
+ if (!d->checkVValid())
+ return;
+
+ if (d->usedAnchors & HasTopAnchor) {
+ const char *slotStr = SLOT(updateTopAnchor());
+
+ //Handle stretching connections (if we have multiple horizontal anchors)
+ QFxAnchorLine *edge = 0;
+ if (d->usedAnchors & HasBottomAnchor) {
+ edge = &d->bottom;
+ connect(this, SIGNAL(bottomMarginChanged()), this, slotStr);
+ } else if (d->usedAnchors & HasVCenterAnchor) {
+ edge = &d->vCenter;
+ connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr);
+ }
+ if (edge) {
+ //we need to stretch
+ d->connectVHelper(*edge, slotStr);
+ }
+
+ //Handle top
+ d->connectVHelper(d->top, slotStr);
+ connect(this, SIGNAL(topMarginChanged()), this, slotStr);
+ updateTopAnchor();
+ } else if (d->usedAnchors & HasBottomAnchor) {
+ const char *slotStr = SLOT(updateBottomAnchor());
+
+ //Handle stretching connections (if we have multiple horizontal anchors)
+ if (d->usedAnchors & HasVCenterAnchor) {
+ d->connectVHelper(d->vCenter, slotStr);
+ connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr);
+ }
+
+ //Handle bottom
+ d->connectVHelper(d->bottom, slotStr);
+ connect(this, SIGNAL(bottomMarginChanged()), this, slotStr);
+ updateBottomAnchor();
+ } else if (d->usedAnchors & HasVCenterAnchor) {
+ //Handle vCenter
+ const char *slotStr = SLOT(updateVCenterAnchor());
+ d->connectVHelper(d->vCenter, slotStr);
+ connect(this, SIGNAL(verticalCenterOffsetChanged()), this, slotStr);
+ updateVCenterAnchor();
+ }
+}
+
+void QFxAnchorsPrivate::connectHHelper(const QFxAnchorLine &edge, const char *slotString)
+{
+ //### should we do disconnects first? (will it be called more than once?)
+ Q_Q(QFxAnchors);
+ if (edge.item == item->itemParent()) { //child-parent
+ switch(edge.anchorLine) {
+ case QFxAnchorLine::Right:
+ case QFxAnchorLine::HCenter:
+ QObject::connect(edge.item, SIGNAL(widthChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::Left: //no connection needed
+ default:
+ break;
+ }
+ } else if (edge.item->itemParent() == item->itemParent()) { //siblings
+ switch(edge.anchorLine) {
+ case QFxAnchorLine::Left:
+ QObject::connect(edge.item, SIGNAL(leftChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::Right:
+ QObject::connect(edge.item, SIGNAL(rightChanged()), q, slotString);
+ break;
+ case QFxAnchorLine::HCenter:
+ QObject::connect(edge.item, SIGNAL(hcenterChanged()), q, slotString);
+ break;
+ default:
+ break;
+ }
+ } else {
+ qmlInfo(item) << "Can't anchor to an item that isn't a parent or sibling.";
+ }
+}
+
+void QFxAnchors::connectHAnchors()
+{
+ Q_D(QFxAnchors);
+ if (!d->checkHValid())
+ return;
+
+ if (d->usedAnchors & HasLeftAnchor) {
+ const char *slotStr = SLOT(updateLeftAnchor());
+
+ //Handle stretching connections (if we have multiple horizontal anchors)
+ QFxAnchorLine *edge = 0;
+ if (d->usedAnchors & HasRightAnchor) {
+ edge = &d->right;
+ connect(this, SIGNAL(rightMarginChanged()), this, slotStr);
+ } else if (d->usedAnchors & HasHCenterAnchor) {
+ edge = &d->hCenter;
+ connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr);
+ }
+ if (edge) {
+ //we need to stretch
+ d->connectHHelper(*edge, slotStr);
+ }
+
+ //Handle left
+ d->connectHHelper(d->left, slotStr);
+ connect(this, SIGNAL(leftMarginChanged()), this, slotStr);
+ updateLeftAnchor();
+ } else if (d->usedAnchors & HasRightAnchor) {
+ const char *slotStr = SLOT(updateRightAnchor());
+
+ //Handle stretching connections (if we have multiple horizontal anchors)
+ if (d->usedAnchors & HasHCenterAnchor) {
+ d->connectHHelper(d->hCenter, slotStr);
+ connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr);
+ }
+
+ //Handle right
+ d->connectHHelper(d->right, slotStr);
+ connect(this, SIGNAL(rightMarginChanged()), this, slotStr);
+ updateRightAnchor();
+ } else if (d->usedAnchors & HasHCenterAnchor) {
+ //Handle hCenter
+ const char *slotStr = SLOT(updateHCenterAnchor());
+ d->connectHHelper(d->hCenter, slotStr);
+ connect(this, SIGNAL(horizontalCenterOffsetChanged()), this, slotStr);
+ updateHCenterAnchor();
+ }
+}
+
+bool QFxAnchorsPrivate::calcStretch(const QFxAnchorLine &edge1,
+ const QFxAnchorLine &edge2,
+ int offset1,
+ int offset2,
+ QFxAnchorLine::AnchorLine line,
+ int &stretch)
+{
+ bool edge1IsParent = (edge1.item == item->itemParent());
+ bool edge2IsParent = (edge2.item == item->itemParent());
+ bool edge1IsSibling = (edge1.item->itemParent() == item->itemParent());
+ bool edge2IsSibling = (edge2.item->itemParent() == item->itemParent());
+
+ bool invalid = false;
+ if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) {
+ stretch = ((int)position(edge2.item, edge2.anchorLine) + offset2)
+ - ((int)position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsParent && edge1IsSibling) {
+ stretch = ((int)position(edge2.item, edge2.anchorLine) + offset2)
+ - ((int)position(item->itemParent(), line)
+ + (int)position(edge1.item, edge1.anchorLine) + offset1);
+ } else if (edge2IsSibling && edge1IsParent) {
+ stretch = ((int)position(item->itemParent(), line) + (int)position(edge2.item, edge2.anchorLine) + offset2)
+ - ((int)position(edge1.item, edge1.anchorLine) + offset1);
+ } else
+ invalid = true;
+
+ return invalid;
+}
+
+void QFxAnchors::updateTopAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasTopAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ int height = 0;
+ if (d->usedAnchors & HasBottomAnchor) {
+ invalid = d->calcStretch(d->top, d->bottom, d->topMargin, -d->bottomMargin, QFxAnchorLine::Top, height);
+ } else if (d->usedAnchors & HasVCenterAnchor) {
+ invalid = d->calcStretch(d->top, d->vCenter, d->topMargin, d->vCenterOffset, QFxAnchorLine::Top, height);
+ height *= 2;
+ }
+ if (!invalid)
+ d->item->setHeight(height);
+
+ //Handle top
+ if (d->top.item == d->item->itemParent()) {
+ d->item->setY(adjustedPosition(d->top.item, d->top.anchorLine) + d->topMargin);
+ } else if (d->top.item->itemParent() == d->item->itemParent()) {
+ d->item->setY(position(d->top.item, d->top.anchorLine) + d->topMargin);
+ }
+ }
+}
+
+void QFxAnchors::updateBottomAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasBottomAnchor) {
+ //Handle stretching (top + bottom case is handled in updateLeftAnchor)
+ if (d->usedAnchors & HasVCenterAnchor) {
+ int height = 0;
+ bool invalid = d->calcStretch(d->vCenter, d->bottom, d->vCenterOffset, -d->bottomMargin,
+ QFxAnchorLine::Top, height);
+ if (!invalid)
+ d->item->setHeight(height*2);
+ }
+
+ //Handle bottom
+ if (d->bottom.item == d->item->itemParent()) {
+ d->item->setY(adjustedPosition(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin);
+ } else if (d->bottom.item->itemParent() == d->item->itemParent()) {
+ d->item->setY(position(d->bottom.item, d->bottom.anchorLine) - d->item->height() - d->bottomMargin);
+ }
+ }
+}
+
+void QFxAnchors::updateVCenterAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasVCenterAnchor) {
+ //(stetching handled in other update functions)
+
+ //Handle vCenter
+ if (d->vCenter.item == d->item->itemParent()) {
+ d->item->setY(adjustedPosition(d->vCenter.item, d->vCenter.anchorLine)
+ - d->item->height()/2 + d->vCenterOffset);
+ } else if (d->vCenter.item->itemParent() == d->item->itemParent()) {
+ d->item->setY(position(d->vCenter.item, d->vCenter.anchorLine) - d->item->height()/2 + d->vCenterOffset);
+ }
+ }
+}
+
+void QFxAnchors::updateLeftAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasLeftAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ int width = 0;
+ if (d->usedAnchors & HasRightAnchor) {
+ invalid = d->calcStretch(d->left, d->right, d->leftMargin, -d->rightMargin, QFxAnchorLine::Left, width);
+ } else if (d->usedAnchors & HasHCenterAnchor) {
+ invalid = d->calcStretch(d->left, d->hCenter, d->leftMargin, d->hCenterOffset, QFxAnchorLine::Left, width);
+ width *= 2;
+ }
+ if (!invalid)
+ d->item->setWidth(width);
+
+ //Handle left
+ if (d->left.item == d->item->itemParent()) {
+ d->item->setX(adjustedPosition(d->left.item, d->left.anchorLine) + d->leftMargin);
+ } else if (d->left.item->itemParent() == d->item->itemParent()) {
+ d->item->setX(position(d->left.item, d->left.anchorLine) + d->leftMargin);
+ }
+ }
+}
+
+void QFxAnchors::updateRightAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasRightAnchor) {
+ //Handle stretching (left + right case is handled in updateLeftAnchor)
+ if (d->usedAnchors & HasHCenterAnchor) {
+ int width = 0;
+ bool invalid = d->calcStretch(d->hCenter, d->right, d->hCenterOffset, -d->rightMargin,
+ QFxAnchorLine::Left, width);
+ if (!invalid)
+ d->item->setWidth(width*2);
+ }
+
+ //Handle right
+ if (d->right.item == d->item->itemParent()) {
+ d->item->setX(adjustedPosition(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin);
+ } else if (d->right.item->itemParent() == d->item->itemParent()) {
+ d->item->setX(position(d->right.item, d->right.anchorLine) - d->item->width() - d->rightMargin);
+ }
+ }
+}
+
+void QFxAnchors::updateHCenterAnchor()
+{
+ Q_D(QFxAnchors);
+ if (d->usedAnchors & HasHCenterAnchor) {
+ //Handle hCenter
+ if (d->hCenter.item == d->item->itemParent()) {
+ d->item->setX(adjustedPosition(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset);
+ } else if (d->hCenter.item->itemParent() == d->item->itemParent()) {
+ d->item->setX(position(d->hCenter.item, d->hCenter.anchorLine) - d->item->width()/2 + d->hCenterOffset);
+ }
+ }
+}
+
+QFxAnchorLine QFxAnchors::top() const
+{
+ Q_D(const QFxAnchors);
+ return d->top;
+}
+
+void QFxAnchors::setTop(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkVAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasTopAnchor;
+
+ d->checkVValid();
+
+ d->top = edge;
+}
+
+QFxAnchorLine QFxAnchors::bottom() const
+{
+ Q_D(const QFxAnchors);
+ return d->bottom;
+}
+
+void QFxAnchors::setBottom(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkVAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasBottomAnchor;
+
+ d->checkVValid();
+
+ d->bottom = edge;
+
+}
+
+QFxAnchorLine QFxAnchors::verticalCenter() const
+{
+ Q_D(const QFxAnchors);
+ return d->vCenter;
+}
+
+void QFxAnchors::setVerticalCenter(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkVAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasVCenterAnchor;
+
+ d->checkVValid();
+
+ d->vCenter = edge;
+}
+
+QFxAnchorLine QFxAnchors::left() const
+{
+ Q_D(const QFxAnchors);
+ return d->left;
+}
+
+void QFxAnchors::setLeft(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkHAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasLeftAnchor;
+
+ d->checkHValid();
+
+ d->left = edge;
+}
+
+QFxAnchorLine QFxAnchors::right() const
+{
+ Q_D(const QFxAnchors);
+ return d->right;
+}
+
+void QFxAnchors::setRight(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkHAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasRightAnchor;
+
+ d->checkHValid();
+
+ d->right = edge;
+
+}
+
+QFxAnchorLine QFxAnchors::horizontalCenter() const
+{
+ Q_D(const QFxAnchors);
+ return d->hCenter;
+}
+
+void QFxAnchors::setHorizontalCenter(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkHAnchorValid(edge))
+ return;
+
+ d->usedAnchors |= HasHCenterAnchor;
+
+ d->checkHValid();
+
+ d->hCenter = edge;
+}
+
+int QFxAnchors::leftMargin() const
+{
+ Q_D(const QFxAnchors);
+ return d->leftMargin;
+}
+
+void QFxAnchors::setLeftMargin(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->leftMargin == offset)
+ return;
+ d->leftMargin = offset;
+ emit leftMarginChanged();
+}
+
+int QFxAnchors::rightMargin() const
+{
+ Q_D(const QFxAnchors);
+ return d->rightMargin;
+}
+
+void QFxAnchors::setRightMargin(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->rightMargin == offset)
+ return;
+ d->rightMargin = offset;
+ emit rightMarginChanged();
+}
+
+int QFxAnchors::horizontalCenterOffset() const
+{
+ Q_D(const QFxAnchors);
+ return d->hCenterOffset;
+}
+
+void QFxAnchors::setHorizontalCenterOffset(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->hCenterOffset == offset)
+ return;
+ d->hCenterOffset = offset;
+ emit horizontalCenterOffsetChanged();
+}
+
+int QFxAnchors::topMargin() const
+{
+ Q_D(const QFxAnchors);
+ return d->topMargin;
+}
+
+void QFxAnchors::setTopMargin(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->topMargin == offset)
+ return;
+ d->topMargin = offset;
+ emit topMarginChanged();
+}
+
+int QFxAnchors::bottomMargin() const
+{
+ Q_D(const QFxAnchors);
+ return d->bottomMargin;
+}
+
+void QFxAnchors::setBottomMargin(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->bottomMargin == offset)
+ return;
+ d->bottomMargin = offset;
+ emit bottomMarginChanged();
+}
+
+int QFxAnchors::verticalCenterOffset() const
+{
+ Q_D(const QFxAnchors);
+ return d->vCenterOffset;
+}
+
+void QFxAnchors::setVerticalCenterOffset(int offset)
+{
+ Q_D(QFxAnchors);
+ if (d->vCenterOffset == offset)
+ return;
+ d->vCenterOffset = offset;
+ emit verticalCenterOffsetChanged();
+}
+
+#if 0
+/*!
+ \property QFxAnchors::baseline
+ \brief what the baseline of the item should be anchored to (aligned with).
+
+ The baseline of a Text item is the imaginary line on which the text sits. Controls containing
+ text usually set their baseline to the baseline of their text.
+
+ For non-text items, a default baseline offset of two-thirds of the item's height is used
+ to determine the baseline.
+*/
+int QFxAnchors::baseline() const
+{
+ return d->item->baseline();
+}
+
+void QFxAnchors::setBaseline(int baseline)
+{
+ d->usedAnchors |= HasBaselineAnchor;
+
+ if (d->usedAnchors & HasTopAnchor && d->usedAnchors & HasBottomAnchor) {
+ qmlInfo(d->item) << "Can't specify top, bottom, and baseline anchors";
+ return;
+ }
+
+ if (d->usedAnchors & HasTopAnchor) {
+ int hoffset = baseline - d->item->baseline();
+ d->item->setHeight(d->item->height() + hoffset);
+ } else {
+ if (d->usedAnchors & HasBottomAnchor) {
+ int hoffset = d->item->baseline() - baseline;
+ d->item->setHeight(d->item->height() + hoffset);
+ }
+
+ int boffset = d->item->baseline() - d->item->top();
+ QFxItem *parentItem = d->item->itemParent();
+ if (parentItem)
+ d->item->setY(baseline - boffset - parentItem->top());
+ else
+ d->item->setY(baseline - boffset);
+ }
+}
+#endif
+
+QFxAnchors::UsedAnchors QFxAnchors::usedAnchors() const
+{
+ Q_D(const QFxAnchors);
+ return d->usedAnchors;
+}
+
+void QFxAnchors::setItem(QFxItem *item)
+{
+ Q_D(QFxAnchors);
+ d->item = item;
+}
+
+bool QFxAnchorsPrivate::checkHValid() const
+{
+ if (usedAnchors & QFxAnchors::HasLeftAnchor &&
+ usedAnchors & QFxAnchors::HasRightAnchor &&
+ usedAnchors & QFxAnchors::HasHCenterAnchor) {
+ qmlInfo(item) << "Can't specify left, right, and hcenter anchors";
+ return false;
+ }
+
+ return true;
+}
+
+bool QFxAnchorsPrivate::checkHAnchorValid(QFxAnchorLine anchor) const
+{
+ if (anchor.anchorLine & QFxAnchorLine::Vertical_Mask) {
+ qmlInfo(item) << "Can't anchor a horizontal edge to a vertical edge.";
+ return false;
+ }else if(anchor.item == item){
+ qmlInfo(item) << "Can't anchor item to self.";
+ return false;
+ }
+
+ return true;
+}
+
+bool QFxAnchorsPrivate::checkVValid() const
+{
+ if (usedAnchors & QFxAnchors::HasTopAnchor &&
+ usedAnchors & QFxAnchors::HasBottomAnchor &&
+ usedAnchors & QFxAnchors::HasVCenterAnchor) {
+ qmlInfo(item) << "Can't specify top, bottom, and vcenter anchors";
+ return false;
+ }
+
+ return true;
+}
+
+bool QFxAnchorsPrivate::checkVAnchorValid(QFxAnchorLine anchor) const
+{
+ if (anchor.anchorLine & QFxAnchorLine::Horizontal_Mask) {
+ qmlInfo(item) << "Can't anchor a vertical edge to a horizontal edge.";
+ return false;
+ }else if(anchor.item == item){
+ qmlInfo(item) << "Can't anchor item to self.";
+ return false;
+ }
+
+ return true;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxanchors.h b/src/declarative/fx/qfxanchors.h
new file mode 100644
index 0000000..3a250b9
--- /dev/null
+++ b/src/declarative/fx/qfxanchors.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXANCHORS_H
+#define QFXANCHORS_H
+
+#include <qfxglobal.h>
+#include <QObject>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxItem;
+class QFxAnchorsPrivate;
+
+class QFxAnchorLine
+{
+public:
+ QFxAnchorLine() : item(0), anchorLine(Left)
+ {
+ }
+
+ enum AnchorLine {
+ Left = 0x01,
+ Right = 0x02,
+ Top = 0x04,
+ Bottom = 0x08,
+ HCenter = 0x10,
+ VCenter = 0x20,
+ Baseline = 0x40,
+ Horizontal_Mask = Left | Right | HCenter,
+ Vertical_Mask = Top | Bottom | VCenter | Baseline
+ };
+
+ QFxItem *item;
+ AnchorLine anchorLine;
+};
+
+Q_DECLARE_METATYPE(QFxAnchorLine);
+
+class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFxAnchorLine left READ left WRITE setLeft);
+ Q_PROPERTY(QFxAnchorLine right READ right WRITE setRight);
+ Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter);
+ Q_PROPERTY(QFxAnchorLine top READ top WRITE setTop);
+ Q_PROPERTY(QFxAnchorLine bottom READ bottom WRITE setBottom);
+ Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter);
+ Q_PROPERTY(int leftMargin READ leftMargin WRITE setLeftMargin NOTIFY leftMarginChanged);
+ Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin NOTIFY rightMarginChanged);
+ Q_PROPERTY(int horizontalCenterOffset READ horizontalCenterOffset WRITE setHorizontalCenterOffset NOTIFY horizontalCenterOffsetChanged());
+ Q_PROPERTY(int topMargin READ topMargin WRITE setTopMargin NOTIFY topMarginChanged);
+ Q_PROPERTY(int bottomMargin READ bottomMargin WRITE setBottomMargin NOTIFY bottomMarginChanged);
+ Q_PROPERTY(int verticalCenterOffset READ verticalCenterOffset WRITE setVerticalCenterOffset NOTIFY verticalCenterOffsetChanged());
+ Q_PROPERTY(QFxItem *fill READ fill WRITE setFill);
+ Q_PROPERTY(QFxItem *centeredIn READ centeredIn WRITE setCenteredIn);
+
+public:
+ QFxAnchors(QObject *parent=0);
+
+ enum UsedAnchor {
+ HasLeftAnchor = 0x01,
+ HasRightAnchor = 0x02,
+ HasTopAnchor = 0x04,
+ HasBottomAnchor = 0x08,
+ HasHCenterAnchor = 0x10,
+ HasVCenterAnchor = 0x20,
+ HasBaselineAnchor = 0x40
+ };
+ Q_DECLARE_FLAGS(UsedAnchors, UsedAnchor);
+
+ QFxAnchorLine left() const;
+ void setLeft(const QFxAnchorLine &edge);
+
+ QFxAnchorLine right() const;
+ void setRight(const QFxAnchorLine &edge);
+
+ QFxAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QFxAnchorLine &edge);
+
+ QFxAnchorLine top() const;
+ void setTop(const QFxAnchorLine &edge);
+
+ QFxAnchorLine bottom() const;
+ void setBottom(const QFxAnchorLine &edge);
+
+ QFxAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QFxAnchorLine &edge);
+
+ int leftMargin() const;
+ void setLeftMargin(int);
+
+ int rightMargin() const;
+ void setRightMargin(int);
+
+ int horizontalCenterOffset() const;
+ void setHorizontalCenterOffset(int);
+
+ int topMargin() const;
+ void setTopMargin(int);
+
+ int bottomMargin() const;
+ void setBottomMargin(int);
+
+ int verticalCenterOffset() const;
+ void setVerticalCenterOffset(int);
+
+ QFxItem *fill() const;
+ void setFill(QFxItem *);
+
+ QFxItem *centeredIn() const;
+ void setCenteredIn(QFxItem *);
+
+ UsedAnchors usedAnchors() const;
+
+ void setItem(QFxItem *item);
+
+ void connectHAnchors();
+ void connectVAnchors();
+
+Q_SIGNALS:
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+
+private Q_SLOTS:
+ void fillChanged();
+ void updateLeftAnchor();
+ void updateRightAnchor();
+ void updateHCenterAnchor();
+ void updateTopAnchor();
+ void updateBottomAnchor();
+ void updateVCenterAnchor();
+
+private:
+ //### should item be a friend? (and make some of the public methods private or protected)
+ Q_DISABLE_COPY(QFxAnchors)
+ Q_DECLARE_PRIVATE(QFxAnchors)
+};
+
+QML_DECLARE_TYPE(QFxAnchors);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxanchors_p.h b/src/declarative/fx/qfxanchors_p.h
new file mode 100644
index 0000000..3a5d1c7
--- /dev/null
+++ b/src/declarative/fx/qfxanchors_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXANCHORS_P_H
+#define QFXANCHORS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxanchors.h"
+#include "private/qobject_p.h"
+
+
+QT_BEGIN_NAMESPACE
+class QFxAnchorsPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QFxAnchors)
+public:
+ QFxAnchorsPrivate()
+ : item(0), usedAnchors(0), fill(0), centeredIn(0), leftMargin(0), rightMargin(0),
+ topMargin(0), bottomMargin(0), vCenterOffset(0), hCenterOffset(0)
+ {
+ }
+
+ void init()
+ {
+ }
+
+ bool checkHValid() const;
+ bool checkVValid() const;
+ bool checkHAnchorValid(QFxAnchorLine anchor) const;
+ bool checkVAnchorValid(QFxAnchorLine anchor) const;
+ void connectHHelper(const QFxAnchorLine &anchorLine, const char *slotString);
+ void connectVHelper(const QFxAnchorLine &anchorLine, const char *slotString);
+ bool calcStretch(const QFxAnchorLine &edge1, const QFxAnchorLine &edge2, int offset1, int offset2, QFxAnchorLine::AnchorLine line, int &stretch);
+
+ QFxItem *item;
+ QFxAnchors::UsedAnchors usedAnchors;
+
+ QFxItem *fill;
+ QFxItem *centeredIn;
+
+ QFxAnchorLine left;
+ QFxAnchorLine right;
+ QFxAnchorLine top;
+ QFxAnchorLine bottom;
+ QFxAnchorLine vCenter;
+ QFxAnchorLine hCenter;
+
+ int leftMargin;
+ int rightMargin;
+ int topMargin;
+ int bottomMargin;
+ int vCenterOffset;
+ int hCenterOffset;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxanimatedimageitem.cpp b/src/declarative/fx/qfxanimatedimageitem.cpp
new file mode 100644
index 0000000..cc11b56
--- /dev/null
+++ b/src/declarative/fx/qfxanimatedimageitem.cpp
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QMovie>
+#include <QtDeclarative/qmlcontext.h>
+#include <QtDeclarative/qmlengine.h>
+#include "qfxanimatedimageitem.h"
+#include "qfxanimatedimageitem_p.h"
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFxAnimatedImageItem
+ \internal
+*/
+
+/*!
+ \qmlclass AnimatedImage
+ \inherits Image
+
+ This item provides for playing animations stored as images containing a series of frames,
+ such as GIF files. The full list of supported formats can be determined with
+ QMovie::supportedFormats().
+
+ \table
+ \row
+ \o \image animatedimageitem.gif
+ \o
+ \code
+<Item width="{anim.width}" height="{anim.height+8}">
+ <AnimatedImage id="anim" file="pics/games-anim.gif"/>
+ <Rect color="red" width="4" height="8" y="{anim.height}"
+ x="{(anim.width-width)*anim.currentFrame/(anim.frameCount-1)}"/>
+</Item>
+ \endcode
+ \endtable
+*/
+QML_DEFINE_TYPE(QFxAnimatedImageItem, AnimatedImage);
+
+QFxAnimatedImageItem::QFxAnimatedImageItem(QFxItem *parent)
+ : QFxImage(*(new QFxAnimatedImageItemPrivate), parent)
+{
+}
+
+QFxAnimatedImageItem::QFxAnimatedImageItem(QFxAnimatedImageItemPrivate &dd, QFxItem *parent)
+ : QFxImage(dd, parent)
+{
+}
+
+QFxAnimatedImageItem::~QFxAnimatedImageItem()
+{
+ Q_D(QFxAnimatedImageItem);
+ delete d->_movie;
+}
+
+/*!
+ \qmlproperty bool AnimatedImage::playing
+ This property holds whether the animated image is playing or not
+
+ Defaults to true, so as to start playing immediately.
+*/
+bool QFxAnimatedImageItem::isPlaying() const
+{
+ Q_D(const QFxAnimatedImageItem);
+ if(!d->_movie)
+ return false;
+ return d->_movie->state()==QMovie::Running;
+}
+
+void QFxAnimatedImageItem::setPlaying(bool play)
+{
+ Q_D(QFxAnimatedImageItem);
+ if(!d->_movie)
+ return;
+ if(play)
+ d->_movie->start();
+ else
+ d->_movie->stop();
+}
+
+/*!
+ \qmlproperty int AnimatedImage::currentFrame
+ \qmlproperty int AnimatedImage::frameCount
+
+ currentFrame is the frame that is currently visible. Watching when this changes can
+ allow other things to animate at the same time as the image. frameCount is the number
+ of frames in the animation. For some animation formats, frameCount is unknown and set to zero.
+*/
+int QFxAnimatedImageItem::currentFrame() const
+{
+ Q_D(const QFxAnimatedImageItem);
+ if(!d->_movie)
+ return -1;
+ return d->_movie->currentFrameNumber();
+}
+
+void QFxAnimatedImageItem::setCurrentFrame(int frame)
+{
+ Q_D(QFxAnimatedImageItem);
+ if(!d->_movie)
+ return;
+ d->_movie->jumpToFrame(frame);
+}
+
+int QFxAnimatedImageItem::frameCount() const
+{
+ Q_D(const QFxAnimatedImageItem);
+ if(!d->_movie)
+ return 0;
+ return d->_movie->frameCount();
+}
+
+void QFxAnimatedImageItem::setSource(const QString &url)
+{
+ Q_D(QFxAnimatedImageItem);
+ if(url == d->source)
+ return;
+
+ delete d->_movie;
+ d->_movie = 0;
+
+ if(d->reply) {
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+
+ d->source = url;
+ d->url = itemContext()->resolvedUrl(url);
+
+ if(url.isEmpty()) {
+ delete d->_movie;
+ d->status = Idle;
+ } else {
+ d->status = Loading;
+ QNetworkRequest req(d->url);
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ d->reply = itemContext()->engine()->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()),
+ this, SLOT(movieRequestFinished()));
+ }
+
+ emit statusChanged(d->status);
+}
+
+void QFxAnimatedImageItem::movieRequestFinished()
+{
+ Q_D(QFxAnimatedImageItem);
+ d->_movie = new QMovie(d->reply);
+ if(!d->_movie->isValid()){
+ qWarning() << "Error Reading File " << d->url;
+ delete d->_movie;
+ d->_movie = 0;
+ return;
+ }
+ connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)),
+ this, SIGNAL(playingChanged()));
+ connect(d->_movie, SIGNAL(frameChanged(int)),
+ this, SLOT(movieUpdate()));
+ d->_movie->setCacheMode(QMovie::CacheAll);
+ d->_movie->start();
+ setPixmap(d->_movie->currentPixmap());
+}
+
+void QFxAnimatedImageItem::movieUpdate()
+{
+ Q_D(QFxAnimatedImageItem);
+ setPixmap(d->_movie->currentPixmap());
+ emit frameChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxanimatedimageitem.h b/src/declarative/fx/qfxanimatedimageitem.h
new file mode 100644
index 0000000..121fe62
--- /dev/null
+++ b/src/declarative/fx/qfxanimatedimageitem.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXANIMATEDIMAGEITEM_H
+#define QFXANIMATEDIMAGEITEM_H
+
+#include <qfximage.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QMovie;
+class QFxAnimatedImageItemPrivate;
+
+class Q_DECLARATIVE_EXPORT QFxAnimatedImageItem : public QFxImage
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool playing READ isPlaying WRITE setPlaying NOTIFY playingChanged)
+ Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY frameChanged)
+ Q_PROPERTY(int frameCount READ frameCount)
+public:
+ QFxAnimatedImageItem(QFxItem *parent=0);
+ ~QFxAnimatedImageItem();
+
+ bool isPlaying() const;
+ void setPlaying(bool play);
+
+ int currentFrame() const;
+ void setCurrentFrame(int frame);
+
+ int frameCount() const;
+
+ // Extends QFxImage's src property*/
+ virtual void setSource(const QString&);
+
+Q_SIGNALS:
+ void playingChanged();
+ void frameChanged();
+
+private Q_SLOTS:
+ void movieUpdate();
+ void movieRequestFinished();
+
+protected:
+ QFxAnimatedImageItem(QFxAnimatedImageItemPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxAnimatedImageItem)
+ Q_DECLARE_PRIVATE(QFxAnimatedImageItem)
+};
+
+QML_DECLARE_TYPE(QFxAnimatedImageItem);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxanimatedimageitem_p.h b/src/declarative/fx/qfxanimatedimageitem_p.h
new file mode 100644
index 0000000..cb5da63
--- /dev/null
+++ b/src/declarative/fx/qfxanimatedimageitem_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXANIMATEDIMAGE_P_H
+#define QFXANIMATEDIMAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfximage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QMovie;
+
+class QFxAnimatedImageItemPrivate : public QFxImagePrivate
+{
+ Q_DECLARE_PUBLIC(QFxAnimatedImageItem)
+
+public:
+ QFxAnimatedImageItemPrivate()
+ : _movie(0)
+ {
+ }
+
+ QMovie *_movie;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXANIMATEDIMAGE_P_H
diff --git a/src/declarative/fx/qfxblendedimage.cpp b/src/declarative/fx/qfxblendedimage.cpp
new file mode 100644
index 0000000..773018f
--- /dev/null
+++ b/src/declarative/fx/qfxblendedimage.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxblendedimage.h"
+#include <QtDeclarative/qmlcontext.h>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <glbasicshaders.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QFxBlendedImage
+ \brief The QFxBlendedImage blends two different images depending on a blend ratio.
+
+ This class can be used to simulate blur on slow devices by setting secondaryFile with
+ a pre-rendered blurred version of primaryFile.
+
+ Note that this class will only work under OpenGL. On the software canvas it will display
+ only the primary image unless the blend is > 0.75, in which case it will display only the
+ secondary image.
+*/
+QFxBlendedImage::QFxBlendedImage(QFxItem *parent)
+: QFxItem(parent), _blend(0), dirty(false)
+{
+#if defined(QFX_RENDER_OPENGL2)
+ setOptions(HasContents);
+#endif
+}
+
+/*!
+ \property QFxBlendedImage::primaryUrl
+ \brief the URL of the first image to be displayed in this item.
+*/
+QString QFxBlendedImage::primaryUrl() const
+{
+ return primSrc;
+}
+
+void QFxBlendedImage::primaryLoaded()
+{
+ primPix = QFxPixmap(primUrl);
+ dirty = true;
+ update();
+}
+
+void QFxBlendedImage::setPrimaryUrl(const QString &url)
+{
+ if (primSrc == url)
+ return;
+ if (!primSrc.isEmpty())
+ QFxPixmap::cancelGet(primUrl,this,SLOT(primaryLoaded()));
+ primSrc = url;
+ primUrl = itemContext()->resolvedUrl(url);
+ if (!primSrc.isEmpty())
+ QFxPixmap::get(itemContext()->engine(), primUrl,this,SLOT(primaryLoaded()));
+}
+
+/*!
+ \property QFxBlendedImage::secondaryFile
+ \brief the URL of the second image to be displayed in this item.
+*/
+QString QFxBlendedImage::secondaryUrl() const
+{
+ return secSrc;
+}
+
+void QFxBlendedImage::secondaryLoaded()
+{
+ secPix = QFxPixmap(secUrl);
+ dirty = true;
+ update();
+}
+
+void QFxBlendedImage::setSecondaryUrl(const QString &url)
+{
+ if (secSrc == url)
+ return;
+ if (!secSrc.isEmpty())
+ QFxPixmap::cancelGet(secUrl,this,SLOT(secondaryLoaded()));
+ secSrc = url;
+ secUrl = itemContext()->resolvedUrl(url);
+ if (!secSrc.isEmpty())
+ QFxPixmap::get(itemContext()->engine(), secUrl,this,SLOT(secondaryLoaded()));
+}
+
+/*!
+ \property QFxBlendedImage::blend
+ \brief the ratio used to blend the two images.
+
+ If blend has a value of 0, only the first image will be displayed.
+ If blend has a value of 1, only the second image will be displayed.
+*/
+qreal QFxBlendedImage::blend() const
+{
+ return _blend;
+}
+
+void QFxBlendedImage::setBlend(qreal b)
+{
+ _blend = b;
+ update();
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+
+void QFxBlendedImage::paintContents(QPainter &p)
+{
+ if (primSrc.isNull() && secSrc.isNull())
+ return;
+ if (_blend < 0.75)
+ p.drawImage(0, 0, primPix);
+ else
+ p.drawImage(0, 0, secPix);
+}
+
+#elif defined(QFX_RENDER_OPENGL2)
+
+void QFxBlendedImage::paintGLContents(GLPainter &p)
+{
+ static DualTextureBlendShader *shader = 0;
+ if(!shader)
+ shader = new DualTextureBlendShader();
+
+ if(dirty) {
+ prim.clear();
+ sec.clear();
+ prim.setImage(primPix);
+ sec.setImage(secPix);
+
+ dirty = false;
+ }
+
+ if(prim.isNull() || sec.isNull()) {
+
+ return;
+ }
+
+ GLfloat vertices[8];
+ GLfloat texVertices[8];
+
+ float widthV = width();
+ float heightV = height();
+ if(!widthV)
+ widthV = qMax(primPix.width(), secPix.width());
+ if(!heightV)
+ heightV = qMax(primPix.height(), secPix.height());
+
+ vertices[0] = 0; vertices[1] = heightV;
+ vertices[2] = widthV; vertices[3] = heightV;
+ vertices[4] = 0; vertices[5] = 0;
+ vertices[6] = widthV; vertices[7] = 0;
+
+ texVertices[0] = 0; texVertices[1] = 0;
+ texVertices[2] = 1; texVertices[3] = 0;
+ texVertices[4] = 0; texVertices[5] = 1;
+ texVertices[6] = 1; texVertices[7] = 1;
+
+ if(_blend == 0 || _blend == 1) {
+ QGLShaderProgram *tshader = p.useTextureShader();
+
+ GLTexture *tex = 0;
+
+ if(_blend == 0)
+ tex = &prim;
+ else
+ tex = &sec;
+
+ tshader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2);
+ tshader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2);
+
+ glBindTexture(GL_TEXTURE_2D, tex->texture());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ tshader->disableAttributeArray(SingleTextureShader::Vertices);
+ tshader->disableAttributeArray(SingleTextureShader::TextureCoords);
+ } else {
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, prim.texture());
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, sec.texture());
+
+ shader->enable();
+ shader->setOpacity(1);
+ qreal b = _blend;
+ if(b > 1) b = 1;
+ else if(b < 0) b = 0;
+ shader->setBlend(b);
+ shader->setTransform(p.activeTransform);
+
+ shader->setAttributeArray(DualTextureBlendShader::Vertices, vertices, 2);
+ shader->setAttributeArray(DualTextureBlendShader::TextureCoords, texVertices, 2);
+ shader->setAttributeArray(DualTextureBlendShader::BlendTextureCoords, texVertices, 2);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(DualTextureBlendShader::Vertices);
+ shader->disableAttributeArray(DualTextureBlendShader::TextureCoords);
+ shader->disableAttributeArray(DualTextureBlendShader::BlendTextureCoords);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+ }
+}
+#endif
+
+QML_DEFINE_TYPE(QFxBlendedImage,BlendedImage);
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxblendedimage.h b/src/declarative/fx/qfxblendedimage.h
new file mode 100644
index 0000000..96d3135
--- /dev/null
+++ b/src/declarative/fx/qfxblendedimage.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXBLENDEDIMAGE_H
+#define QFXBLENDEDIMAGE_H
+
+#include <qfxitem.h>
+#if defined(QFX_RENDER_OPENGL2)
+#include <gltexture.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QFxBlendedImage : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString primaryUrl READ primaryUrl WRITE setPrimaryUrl)
+ Q_PROPERTY(QString secondaryUrl READ secondaryUrl WRITE setSecondaryUrl)
+ Q_PROPERTY(qreal blend READ blend WRITE setBlend)
+public:
+ QFxBlendedImage(QFxItem *parent=0);
+
+ QString primaryUrl() const;
+ void setPrimaryUrl(const QString &);
+ QString secondaryUrl() const;
+ void setSecondaryUrl(const QString &);
+
+ qreal blend() const;
+ void setBlend(qreal);
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#elif defined(QFX_RENDER_OPENGL2)
+ void paintGLContents(GLPainter &);
+#endif
+
+private Q_SLOTS:
+ void primaryLoaded();
+ void secondaryLoaded();
+
+private:
+ QString primSrc;
+ QString secSrc;
+ QUrl primUrl;
+ QUrl secUrl;
+
+ qreal _blend;
+ bool dirty;
+#if defined(QFX_RENDER_OPENGL2)
+ GLTexture prim;
+ GLTexture sec;
+#endif
+ QFxPixmap primPix;
+ QFxPixmap secPix;
+};
+QML_DECLARE_TYPE(QFxBlendedImage);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXBLENDEDIMAGE_H
diff --git a/src/declarative/fx/qfxblurfilter.cpp b/src/declarative/fx/qfxblurfilter.cpp
new file mode 100644
index 0000000..8cc9380
--- /dev/null
+++ b/src/declarative/fx/qfxblurfilter.cpp
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxblurfilter.h"
+#include <private/qsimplecanvasitem_p.h>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <glsave.h>
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glbasicshaders.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+class QFxBlurFilterPrivate
+{
+public:
+ QFxBlurFilterPrivate()
+ : radius(0)
+ {
+ }
+ qreal radius;
+};
+
+/*!
+ \qmlclass Blur
+ \brief The Blur filter blurs an item and its contents.
+ \inherits Filter
+
+ Blurring reduces the clarity of a visual element. The following example
+ shows an icon at a blur radius of 0, 5 and 10.
+
+ \table
+ \row
+ \o
+ \code
+ <HorizontalLayout>
+ <Image src="icon.png">
+ <filter><Blur radius="0" /></filter>
+ </Image>
+ <Image src="icon.png">
+ <filter><Blur radius="5" /></filter>
+ </Image>
+ <Image src="icon.png">
+ <filter><Blur radius="10" /></filter>
+ </Image>
+ </HorizontalLayout>
+ \endcode
+ \row
+ \o \image blur_example.png
+ \endtable
+
+ Bluring is only supported when Qt Declarative is compiled for OpenGL ES 2.0.
+ Otherwise the Blur filter has no effect.
+ */
+/*!
+ \internal
+ \class QFxBlurFilter
+ \ingroup effects
+ \brief The QFxBlurFilter class allows you to blur an item.
+*/
+
+QFxBlurFilter::QFxBlurFilter(QObject *parent)
+: QSimpleCanvasFilter(parent), d(new QFxBlurFilterPrivate)
+{
+}
+
+QFxBlurFilter::~QFxBlurFilter()
+{
+ delete d; d = 0;
+}
+
+/*!
+ \qmlproperty real Blur::radius
+
+ Sets the blur kernel radius. The larger the radius the more blurry the item will appear. A radius of 0 (or less) is equivalent to no blur.
+ */
+
+/*!
+ \property QFxBlurFilter::radius
+ \brief the radius of the blur.
+*/
+qreal QFxBlurFilter::radius() const
+{
+ return d->radius;
+}
+
+void QFxBlurFilter::setRadius(qreal radius)
+{
+ if(d->radius == radius) return;
+ d->radius = radius;
+ emit radiusChanged(radius);
+ update();
+}
+
+QRectF QFxBlurFilter::itemBoundingRect(const QRectF &r) const
+{
+ QRectF rv = r;
+ if(d->radius > 0)
+ rv.adjust(-d->radius, -d->radius, d->radius, d->radius);
+ return rv;
+}
+
+#include <math.h>
+void QFxBlurFilter::filterGL(QSimpleCanvasItem::GLPainter &p)
+{
+#if defined(QFX_RENDER_OPENGL2)
+#if 1
+ if(d->radius <= 0) {
+ renderToScreen();
+ return;
+ }
+ float radius = d->radius;
+ QSimpleCanvasItem *item = this->item();
+
+ QRect r = item->itemBoundingRect();
+ float blurScale = 1.0;
+ QRect tr = QRect(QPoint(0, 0), r.size() * blurScale);
+ radius *= blurScale;
+
+ QGLFramebufferObject *fbo = renderToFBO(blurScale);
+ if(!fbo)
+ return;
+
+ float height = r.height();
+ float width = r.width();
+
+ float texWidth = float(tr.width()) / float(fbo->width());
+ float texHeight = float(tr.height()) / float(fbo->height());
+
+ int steps = int(::ceil(radius));
+ int dispSteps = int(::ceil(d->radius));
+ float xstep = texWidth * radius / float(steps * fbo->width());
+ float xinc = steps / float(fbo->width());
+
+ glDisable(GL_BLEND);
+
+ // Render x pass
+ QSize xSize(tr.width() + 2 * steps, tr.height());
+ QGLFramebufferObject *xBlur = acquireFBO(xSize);
+ float xWidth = float(xSize.width()) / float(xBlur->width());
+ float xHeight = float(xSize.height()) / float(xBlur->height());
+ {
+ xBlur->bind();
+
+ GLSaveViewport sv; GLSaveScissor ss;
+ glClearColor(0,0,0,0);
+ glDisable(GL_SCISSOR_TEST);
+ glViewport(0, 0, xBlur->width(), xBlur->height());
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ float vert[] = { 0, xHeight,
+ xWidth, xHeight,
+ 0, 0,
+ xWidth, 0 };
+ float texVert[] = { -xinc, 0,
+ texWidth + xinc, 0,
+ -xinc, texHeight,
+ texWidth + xinc, texHeight };
+
+ QMatrix4x4 trans;
+ trans.translate(-1, -1);
+ trans.scale(2, 2);
+ BlurTextureShader *shader = item->basicShaders()->blurTexture();
+ shader->enable();
+ shader->setTransform(trans);
+ if(steps > 1) {
+ shader->setStep(xstep * 2);
+ shader->setSteps(steps / 2);
+ } else {
+ shader->setStep(xstep);
+ shader->setSteps(steps);
+ }
+ shader->setMode(BlurTextureShader::Horizontal);
+
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+
+ shader->setAttributeArray(BlurTextureShader::Vertices, vert, 2);
+ shader->setAttributeArray(BlurTextureShader::TextureCoords, texVert, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(BlurTextureShader::Vertices);
+ shader->disableAttributeArray(BlurTextureShader::TextureCoords);
+ xBlur->release();
+ }
+
+ // Render y pass
+ QSize ySize(xSize.width(), tr.height() + 2 * steps);
+ QGLFramebufferObject *yBlur = acquireFBO(ySize);
+
+ float yWidth = float(ySize.width()) / float(yBlur->width());
+ float yHeight = float(ySize.height()) / float(yBlur->height());
+ float ystep = radius / float(steps * xBlur->height());
+ float yinc = steps / float(xBlur->height());
+ {
+ yBlur->bind();
+
+ GLSaveViewport sv; GLSaveScissor ss;
+ glClearColor(0,0,0,0);
+ glDisable(GL_SCISSOR_TEST);
+ glViewport(0, 0, yBlur->width(), yBlur->height());
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ float vert[] = { 0, yHeight,
+ yWidth, yHeight,
+ 0, 0,
+ yWidth, 0 };
+ float texVert[] = { 0, -yinc,
+ xWidth, -yinc,
+ 0, xHeight + yinc,
+ xWidth, xHeight + yinc };
+
+ QMatrix4x4 trans;
+ trans.translate(-1, -1);
+ trans.scale(2, 2);
+ BlurTextureShader *shader = item->basicShaders()->blurTexture();
+ shader->enable();
+ shader->setTransform(trans);
+ if(steps > 1) {
+ shader->setStep(ystep * 2);
+ shader->setSteps(steps / 2);
+ } else {
+ shader->setStep(ystep);
+ shader->setSteps(steps);
+ }
+ shader->setMode(BlurTextureShader::Vertical);
+
+ glBindTexture(GL_TEXTURE_2D, xBlur->texture());
+
+ shader->setAttributeArray(BlurTextureShader::Vertices, vert, 2);
+ shader->setAttributeArray(BlurTextureShader::TextureCoords, texVert, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(BlurTextureShader::Vertices);
+ shader->disableAttributeArray(BlurTextureShader::TextureCoords);
+ yBlur->release();
+ }
+
+ glEnable(GL_BLEND);
+
+ // Render display pass
+ {
+ glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ float vert[] = { -dispSteps, height + dispSteps,
+ width + dispSteps, height + dispSteps,
+ -dispSteps, -dispSteps,
+ width + dispSteps, -dispSteps };
+ float texVert[] = { 0, 0,
+ yWidth, 0,
+ 0, yHeight,
+ yWidth, yHeight };
+ SingleTextureShader *shader = item->basicShaders()->singleTexture();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+
+ glBindTexture(GL_TEXTURE_2D, yBlur->texture());
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, texVert, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ releaseFBO(yBlur);
+ releaseFBO(xBlur);
+ releaseFBO(fbo);
+#else
+#if 0
+ if(d->radius <= 0) {
+ renderToScreen();
+ return;
+ }
+ QSimpleCanvasItem *item = this->item();
+
+ QRect r = item->itemBoundingRect();
+
+ float scale = 0.5;
+ float scalePercent = scale / d->radius;
+ QGLFramebufferObject *fbo = renderToFBO(scalePercent);
+ if(!fbo)
+ return;
+
+ QGLFramebufferObject *xfbo = acquireFBO(QSize(scale * r.width(), fbo->height()));
+ QGLFramebufferObject *yfbo = acquireFBO(QSize(scale * r.width(), scale * r.height()));
+
+
+ BlurTextureShader *shader = item->basicShaders()->blurTexture();
+ shader->enable();
+ shader->setTransform(QMatrix4x4());
+
+ // Render up - x
+ {
+ shader->setMode(BlurTextureShader::Horizontal);
+ shader->setStep(1. / float(xfbo->width()));
+
+ GLSaveViewport vp;
+ xfbo->bind();
+ glClearColor(0,0,0,0);
+ glViewport(0, 0, xfbo->width(), xfbo->height());
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ float oWidth = -1. + 2. * float(r.width()) * scale / float(xfbo->width());
+ float oHeight = -1. + 2. * float(r.height()) * scalePercent / float(xfbo->height());
+ float vert[] = {
+ -1, -1,
+ oWidth, -1,
+ -1, oHeight,
+
+ -1, oHeight,
+ oWidth, oHeight,
+ oWidth, -1
+ };
+
+ float tWidth = r.width() * scalePercent / fbo->width();
+ float tHeight = r.height() * scalePercent / fbo->height();
+ float texVert[] = {
+ 0, 0,
+ tWidth, 0,
+ 0, tHeight,
+
+ 0, tHeight,
+ tWidth, tHeight,
+ tWidth, 0
+ };
+
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+ shader->setAttributeArray(BlurTextureShader::Vertices, vert, 2);
+ shader->setAttributeArray(BlurTextureShader::TextureCoords, texVert, 2);
+
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ xfbo->release();
+ }
+
+ // Render up - y
+ {
+ shader->setMode(BlurTextureShader::Vertical);
+ shader->setStep(1. / float(yfbo->height()));
+
+ GLSaveViewport vp;
+ yfbo->bind();
+ glClearColor(0,0,0,0);
+ glViewport(0, 0, yfbo->width(), yfbo->height());
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ float oWidth = -1. + 2. * r.width() * scale / yfbo->width();
+ float oHeight = -1. + 2. * r.height() * scale / yfbo->height();
+ float vert[] = {
+ -1, -1,
+ oWidth, -1,
+ -1, oHeight,
+
+ -1, oHeight,
+ oWidth, oHeight,
+ oWidth, -1
+ };
+
+ float tWidth = r.width() * scale / xfbo->width();
+ float tHeight = r.height() * scalePercent / xfbo->height();
+ float texVert[] = {
+ 0, 0,
+ tWidth, 0,
+ 0, tHeight,
+
+ 0, tHeight,
+ tWidth, tHeight,
+ tWidth, 0
+ };
+
+ glBindTexture(GL_TEXTURE_2D, xfbo->texture());
+ shader->setAttributeArray(BlurTextureShader::Vertices, vert, 2);
+ shader->setAttributeArray(BlurTextureShader::TextureCoords, texVert, 2);
+
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ yfbo->release();
+ }
+
+ shader->disableAttributeArray(BlurTextureShader::Vertices);
+ shader->disableAttributeArray(BlurTextureShader::TextureCoords);
+
+ float width = r.width();
+ float height = r.height();
+ //paint to screen
+ {
+ float texWidth = r.width() * scale / float(yfbo->width());
+ float texHeight = r.height() * scale / float(yfbo->height());
+
+ GLfloat vertices[] = { 0, height,
+ width, height,
+ 0, 0,
+ width, 0 };
+ GLfloat texVertices[] = { 0, 0,
+ texWidth, 0,
+ 0, texHeight,
+ texWidth, texHeight };
+
+ glBindTexture(GL_TEXTURE_2D, yfbo->texture());
+
+ SingleTextureOpacityShader *shader =
+ item->basicShaders()->singleTextureOpacity();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+ shader->setOpacity(p.activeOpacity);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::TextureCoords, texVertices, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::Vertices);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::TextureCoords);
+ }
+
+
+ releaseFBO(fbo);
+ releaseFBO(xfbo);
+ releaseFBO(yfbo);
+#endif
+#endif
+#else
+ Q_UNUSED(p);
+#endif
+
+}
+
+QML_DEFINE_TYPE(QFxBlurFilter,Blur);
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxblurfilter.h b/src/declarative/fx/qfxblurfilter.h
new file mode 100644
index 0000000..7a2b5b9
--- /dev/null
+++ b/src/declarative/fx/qfxblurfilter.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXBLURFILTER_H
+#define QFXBLURFILTER_H
+
+#include <qsimplecanvasfilter.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxBlurFilterPrivate;
+class Q_DECLARATIVE_EXPORT QFxBlurFilter : public QSimpleCanvasFilter
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged)
+public:
+ QFxBlurFilter(QObject *parent=0);
+ virtual ~QFxBlurFilter();
+
+ qreal radius() const;
+ void setRadius(qreal);
+
+Q_SIGNALS:
+ void radiusChanged(qreal);
+
+protected:
+ virtual QRectF itemBoundingRect(const QRectF &) const;
+ virtual void filterGL(QSimpleCanvasItem::GLPainter &p);
+
+private:
+ QFxBlurFilterPrivate *d;
+};
+QML_DECLARE_TYPE(QFxBlurFilter);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXBLURFILTER_H
diff --git a/src/declarative/fx/qfxcomponentinstance.cpp b/src/declarative/fx/qfxcomponentinstance.cpp
new file mode 100644
index 0000000..d561d05
--- /dev/null
+++ b/src/declarative/fx/qfxcomponentinstance.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxcomponentinstance.h"
+#include "qfxcomponentinstance_p.h"
+#include <qfxperf.h>
+#include <qfxcontentwrapper.h>
+#include <QtDeclarative/qmlinfo.h>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxComponentInstance,ComponentInstance);
+
+/*!
+ \internal
+ \class QFxComponentInstance
+ \qmlclass ComponentInstance
+
+ \brief The QFxComponentInstance class provides a way to instantiate an item from a component.
+ */
+
+/*!
+ \qmlclass ComponentInstance QFxComponentInstance
+ \brief The ComponentInstance element allows you to instantiate an arbitrary component.
+*/
+QFxComponentInstance::QFxComponentInstance(QFxItem *parent)
+ : QFxItem(*(new QFxComponentInstancePrivate), parent)
+{
+ setOptions(IsFocusRealm);
+}
+
+QFxComponentInstance::QFxComponentInstance(QFxComponentInstancePrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ setOptions(IsFocusRealm);
+}
+
+QmlComponent *QFxComponentInstance::component() const
+{
+ Q_D(const QFxComponentInstance);
+ return d->component;
+}
+
+void QFxComponentInstance::setComponent(QmlComponent *c)
+{
+ Q_D(QFxComponentInstance);
+ if(d->component) {
+ qmlInfo(this) << "component is a write-once property.";
+ return;
+ }
+ d->component = c;
+ create();
+}
+
+void QFxComponentInstance::create()
+{
+ Q_D(QFxComponentInstance);
+ if(d->component) {
+ QObject *obj= d->component->create(itemContext());
+ if(obj) {
+ QFxItem *objitem = qobject_cast<QFxItem *>(obj);
+ if(objitem) {
+ d->instance = objitem;
+ objitem->setItemParent(this);
+ objitem->setFocus(true);
+ connect(objitem, SIGNAL(widthChanged()), this, SLOT(updateSize()));
+ connect(objitem, SIGNAL(heightChanged()), this, SLOT(updateSize()));
+ updateSize();
+ emit instanceChanged();
+ } else {
+ delete obj;
+ }
+ }
+ }
+}
+
+void QFxComponentInstance::updateSize()
+{
+ QFxItem *i = instance();
+ if(i) {
+ if(!widthValid())
+ setImplicitWidth(i->width());
+ if(!heightValid())
+ setImplicitHeight(i->height());
+ }
+}
+
+QFxItem *QFxComponentInstance::instance() const
+{
+ Q_D(const QFxComponentInstance);
+ return d->instance;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxcomponentinstance.h b/src/declarative/fx/qfxcomponentinstance.h
new file mode 100644
index 0000000..64af355
--- /dev/null
+++ b/src/declarative/fx/qfxcomponentinstance.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXCOMPONENTINSTANCE_H
+#define QFXCOMPONENTINSTANCE_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxComponentInstancePrivate;
+class Q_DECLARATIVE_EXPORT QFxComponentInstance : public QFxItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QmlComponent *component READ component WRITE setComponent)
+ Q_PROPERTY(QFxItem *instance READ instance);
+ Q_CLASSINFO("DefaultProperty", "component")
+public:
+ QFxComponentInstance(QFxItem *parent=0);
+
+ QmlComponent *component() const;
+ void setComponent(QmlComponent *);
+
+ QFxItem *instance() const;
+
+Q_SIGNALS:
+ void instanceChanged();
+
+private slots:
+ void updateSize();
+
+private:
+ void create();
+
+protected:
+ QFxComponentInstance(QFxComponentInstancePrivate &dd, QFxItem *parent);
+
+private:
+ Q_DECLARE_PRIVATE(QFxComponentInstance)
+};
+QML_DECLARE_TYPE(QFxComponentInstance);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXCOMPONENTINSTANCE_H
diff --git a/src/declarative/fx/qfxcomponentinstance_p.h b/src/declarative/fx/qfxcomponentinstance_p.h
new file mode 100644
index 0000000..defeb74
--- /dev/null
+++ b/src/declarative/fx/qfxcomponentinstance_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXCOMPONENTINSTANCE_P_H
+#define QFXCOMPONENTINSTANCE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+
+
+QT_BEGIN_NAMESPACE
+class QFxComponentInstancePrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxComponentInstance)
+
+public:
+ QFxComponentInstancePrivate()
+ : component(0), instance(0)
+ {
+ }
+
+ QmlComponent *component;
+ QFxItem *instance;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXCOMPONENTINSTANCE_P_H
diff --git a/src/declarative/fx/qfxcontentwrapper.cpp b/src/declarative/fx/qfxcontentwrapper.cpp
new file mode 100644
index 0000000..80710ca
--- /dev/null
+++ b/src/declarative/fx/qfxcontentwrapper.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxcontentwrapper.h"
+#include "qfxcontentwrapper_p.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxContentWrapper,ContentWrapper);
+
+QFxContentWrapper::QFxContentWrapper(QFxItem *parent)
+: QFxItem(*(new QFxContentWrapperPrivate), parent)
+{
+}
+
+QFxContentWrapper::QFxContentWrapper(QFxContentWrapperPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+}
+
+QList<QFxItem *> *QFxContentWrapper::content()
+{
+ Q_D(QFxContentWrapper);
+ return &(d->_content);
+}
+
+void QFxContentWrapper::componentComplete()
+{
+ QFxItem::componentComplete();
+ if (content()->size() < 1)
+ return;
+
+ QList<QSimpleCanvasItem *> nodes;
+ nodes.append(this);
+ QFxItem *target = findContent(nodes);
+ if (!target)
+ return;
+ target = target->itemParent();
+
+ QList<QFxItem*> myContent(*content());
+ for(int ii = 0; ii < myContent.count(); ++ii)
+ myContent.at(ii)->setParent(target);
+}
+
+QFxItem *QFxContentWrapper::findContent(QList<QSimpleCanvasItem *> &nodes)
+{
+ QSimpleCanvasItem *item = nodes.takeFirst();
+ if (qobject_cast<QFxContent*>(item))
+ return static_cast<QFxItem *>(item);
+ nodes << item->children();
+ if (nodes.isEmpty())
+ return 0;
+ return findContent(nodes);
+}
+
+QML_DEFINE_TYPE(QFxContent,Content);
+
+/*!
+ \qmlclass Content QFxContent
+ \ingroup utility
+ \brief Content is used as a placeholder for the content of a component.
+ \inherits Item
+
+ In some cases the content of a component is not defined by the component itself.
+ For example, the items placed in a group box need to be specified external to
+ the where the group box component itself is defined.
+ In cases like these Content can be used to specify at what location in the component
+ the content should be placed. It is used in conjuntion with the content property of
+ the component instance: any items listed as content will be placed in the location
+ specified by Content.
+
+ Example:
+ \code
+ <!--GroupBox component definition-->
+ <Rect width="{parent.width}" color="white" pen.width="2" pen.color="#adaeb0" radius="10" clip="false" height="{contents.height}">
+ <VerticalLayout id="layout" width="{parent.width}">
+ <Content/>
+ </VerticalLayout>
+ </Rect>
+
+ <!--component use-->
+ <GroupBox>
+ <content>
+ <Text text="First Item"/>
+ ...
+ </content>
+ </GroupBox>
+ \endcode
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxcontentwrapper.h b/src/declarative/fx/qfxcontentwrapper.h
new file mode 100644
index 0000000..5d5a7e1
--- /dev/null
+++ b/src/declarative/fx/qfxcontentwrapper.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXCONTENTWRAPPER_H
+#define QFXCONTENTWRAPPER_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxContentWrapperPrivate;
+class Q_DECLARATIVE_EXPORT QFxContentWrapper : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QList<QFxItem *>* content READ content DESIGNABLE false)
+ Q_CLASSINFO("DefaultProperty", "content")
+public:
+ QFxContentWrapper(QFxItem *parent=0);
+
+ QList<QFxItem *> *content();
+
+private:
+ void create();
+ QFxItem *findContent(QList<QSimpleCanvasItem *> &nodes);
+
+protected:
+ void componentComplete();
+ QFxContentWrapper(QFxContentWrapperPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DECLARE_PRIVATE(QFxContentWrapper)
+};
+QML_DECLARE_TYPE(QFxContentWrapper);
+
+class Q_DECLARATIVE_EXPORT QFxContent : public QFxItem
+{
+ Q_OBJECT
+public:
+ QFxContent(QFxItem *parent=0) : QFxItem(parent) {}
+};
+QML_DECLARE_TYPE(QFxContent);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXCONTENTWRAPPER_H
diff --git a/src/declarative/fx/qfxcontentwrapper_p.h b/src/declarative/fx/qfxcontentwrapper_p.h
new file mode 100644
index 0000000..4f42e00
--- /dev/null
+++ b/src/declarative/fx/qfxcontentwrapper_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXCONTENTWRAPPER_P_H
+#define QFXCONTENTWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+#include "qfxcontentwrapper.h"
+
+
+QT_BEGIN_NAMESPACE
+class QFxContentWrapperPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxContentWrapper);
+public:
+ QFxContentWrapperPrivate() { }
+
+ QList<QFxItem *> _content;
+};
+
+QT_END_NAMESPACE
+#endif // QFXCONTENTWRAPPER_P_H
diff --git a/src/declarative/fx/qfxflickable.cpp b/src/declarative/fx/qfxflickable.cpp
new file mode 100644
index 0000000..7e13036
--- /dev/null
+++ b/src/declarative/fx/qfxflickable.cpp
@@ -0,0 +1,1113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxflickable.h"
+#include "qfxflickable_p.h"
+
+#include <QGraphicsSceneMouseEvent>
+#include <gfxeasing.h>
+#include <QPointer>
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+
+ElasticValue::ElasticValue(GfxValue &val)
+ : _value(val)
+{
+ _to = _value.value();
+ _myValue = _to;
+ _velocity = 0;
+}
+
+void ElasticValue::setValue(qreal to)
+{
+ if (_to != to) {
+ _to = to;
+ _startTime.start();
+ if (state() != Running)
+ start();
+ }
+}
+
+void ElasticValue::clear()
+{
+ stop();
+ _velocity = 0.0;
+ _myValue = _value.value();
+}
+
+void ElasticValue::updateCurrentTime(int)
+{
+ const qreal Tension = 0.1;
+ int elapsed = _startTime.restart();
+ if (!elapsed)
+ return;
+ qreal dist = _to - _value.value();
+ qreal move = Tension * dist * qAbs(dist);
+ if (elapsed < 100 && _velocity != 0.0)
+ move = (elapsed * move + (100 - elapsed) * _velocity) / 100;
+ _myValue += move * elapsed / 1000;
+ _value.setValue(qRound(_myValue)); // moving sub-pixel can be ugly.
+// _value.setValue(_myValue);
+ _velocity = move;
+ if (qAbs(_velocity) < 5.0)
+ clear();
+ emit updated();
+}
+
+QFxFlickablePrivate::QFxFlickablePrivate()
+ : _flick(new QFxItem), _moveX(_flick, &QFxItem::setX), _moveY(_flick, &QFxItem::setY)
+ , vWidth(-1), vHeight(-1), overShoot(true), flicked(false), moving(false), stealMouse(false)
+ , pressed(false), maxVelocity(-1), locked(false), dragMode(QFxFlickable::Hard)
+ , elasticY(_moveY), elasticX(_moveX), velocityDecay(100), xVelocity(this), yVelocity(this)
+ , vTime(0), atXEnd(false), atXBeginning(true), pageXPosition(0.), pageWidth(0.)
+ , atYEnd(false), atYBeginning(true), pageYPosition(0.), pageHeight(0.)
+{
+ fixupXEvent = GfxEvent::gfxEvent<QFxFlickablePrivate, &QFxFlickablePrivate::fixupX>(&_moveX, this);
+ fixupYEvent = GfxEvent::gfxEvent<QFxFlickablePrivate, &QFxFlickablePrivate::fixupY>(&_moveY, this);
+}
+
+void QFxFlickablePrivate::init()
+{
+ Q_Q(QFxFlickable);
+ _flick->setParent(q);
+ QObject::connect(&_tl, SIGNAL(updated()), q, SLOT(ticked()));
+ QObject::connect(&_tl, SIGNAL(completed()), q, SLOT(movementEnding()));
+ q->setAcceptedMouseButtons(Qt::NoButton);
+ q->setOptions(QSimpleCanvasItem::MouseFilter | QSimpleCanvasItem::MouseEvents);
+ QObject::connect(_flick, SIGNAL(leftChanged()), q, SIGNAL(positionChanged()));
+ QObject::connect(_flick, SIGNAL(topChanged()), q, SIGNAL(positionChanged()));
+ QObject::connect(&elasticX, SIGNAL(updated()), q, SLOT(ticked()));
+ QObject::connect(&elasticY, SIGNAL(updated()), q, SLOT(ticked()));
+}
+
+void QFxFlickablePrivate::fixupX()
+{
+ Q_Q(QFxFlickable);
+ if(!q->xflick() || _moveX.timeLine())
+ return;
+
+ vTime = _tl.time();
+
+ if(_moveX.value() > q->minXExtent() || q->maxXExtent() > 0) {
+ _tl.move(_moveX, q->minXExtent(), GfxEasing(GfxEasing::InOutQuad), 200);
+ flicked = false;
+ //emit flickingChanged();
+ } else if(_moveX.value() < q->maxXExtent()) {
+ _tl.move(_moveX, q->maxXExtent(), GfxEasing(GfxEasing::InOutQuad), 200);
+ flicked = false;
+ //emit flickingChanged();
+ }
+}
+
+void QFxFlickablePrivate::fixupY()
+{
+ Q_Q(QFxFlickable);
+ if(!q->yflick() || _moveY.timeLine())
+ return;
+
+ vTime = _tl.time();
+
+ if(_moveY.value() > q->minYExtent() || (q->maxYExtent() > q->minYExtent())) {
+ _tl.move(_moveY, q->minYExtent(), GfxEasing(GfxEasing::InOutQuad), 200);
+ //emit flickingChanged();
+ } else if(_moveY.value() < q->maxYExtent()) {
+ _tl.move(_moveY, q->maxYExtent(), GfxEasing(GfxEasing::InOutQuad), 200);
+ //emit flickingChanged();
+ } else {
+ flicked = false;
+ }
+}
+
+void QFxFlickablePrivate::updateBeginningEnd()
+{
+ Q_Q(QFxFlickable);
+ bool pageChange = false;
+ bool atBoundaryChange = false;
+
+ // Vertical
+ const int viewheight = q->height();
+ const int maxyextent = int(-q->maxYExtent());
+ const qreal ypos = -_moveY.value();
+ qreal pagePos = ((ypos * 100.0) / (maxyextent + viewheight)) / 100.0;
+ qreal pageSize = ((viewheight * 100.0) / (maxyextent + viewheight)) / 100.0;
+ bool atBeginning = (ypos <= 0.0);
+ bool atEnd = (maxyextent <= ypos);
+
+ if (pageSize != pageHeight) {
+ pageHeight = pageSize;
+ pageChange = true;
+ }
+ if (pagePos != pageYPosition) {
+ pageYPosition = pagePos;
+ pageChange = true;
+ }
+ if (atBeginning != atYBeginning) {
+ atYBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != atYEnd) {
+ atYEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ // Horizontal
+ const int viewwidth = q->width();
+ const int maxxextent = int(-q->maxXExtent());
+ const qreal xpos = -_moveX.value();
+ pagePos = ((xpos * 100.0) / (maxxextent + viewwidth)) / 100.0;
+ pageSize = ((viewwidth * 100.0) / (maxxextent + viewwidth)) / 100.0;
+ atBeginning = (xpos <= 0.0);
+ atEnd = (maxxextent <= xpos);
+
+ if (pageSize != pageWidth) {
+ pageWidth = pageSize;
+ pageChange = true;
+ }
+ if (pagePos != pageXPosition) {
+ pageXPosition = pagePos;
+ pageChange = true;
+ }
+ if (atBeginning != atXBeginning) {
+ atXBeginning = atBeginning;
+ atBoundaryChange = true;
+ }
+ if (atEnd != atXEnd) {
+ atXEnd = atEnd;
+ atBoundaryChange = true;
+ }
+
+ if (pageChange)
+ emit q->pageChanged();
+ if (atBoundaryChange)
+ emit q->isAtBoundaryChanged();
+}
+
+static const int FlickThreshold = 5;
+
+QML_DEFINE_TYPE(QFxFlickable,Flickable);
+
+/*!
+ \qmlclass Flickable
+ \brief The Flickable element provides a surface that can be "flicked".
+ \inherits Item
+
+ Flickable places its children on a surface that can be dragged and flicked.
+
+ \code
+ <Flickable width="200" height="200" viewportWidth="{image.width}" viewportHeight="{image.height}">
+ <Image id="image" file="bigimage.png"/>
+ </Flickable>
+ \endcode
+
+ \image flickable.gif
+
+ \note Flickable does not automatically clip its contents. If
+ it is not full-screen it is likely that \c clip should be set
+ to true.
+
+ \note Due to an implementation detail items placed inside a flickable cannot anchor to it by
+ id, use 'parent' instead.
+*/
+
+/*!
+ \internal
+ \class QFxFlickable
+ \brief The QFxFlickable class provides a view that can be "flicked".
+
+ \ingroup widgets
+
+ QFxFlickable allows its children to be dragged and flicked.
+
+\code
+<Flickable width="320" height="480" viewportWidth="{image.width}" viewportHeight="{image.height}">
+ <Image id="image" file="bigimage.png"/>
+</Flickable>
+\endcode
+
+ Note that QFxFlickable does not automatically clip its contents. If
+ it is not full-screen it is likely that QFxItem::clip should be set
+ to true.
+
+*/
+
+QFxFlickable::QFxFlickable(QFxItem *parent)
+ : QFxItem(*(new QFxFlickablePrivate), parent)
+{
+ Q_D(QFxFlickable);
+ d->init();
+}
+
+QFxFlickable::QFxFlickable(QFxFlickablePrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxFlickable);
+ d->init();
+}
+
+QFxFlickable::~QFxFlickable()
+{
+}
+
+/*!
+ \qmlproperty int Flickable::xPosition
+ \qmlproperty int Flickable::yPosition
+
+ These properties hold the surface coordinate currently at the top-left
+ corner of the Flickable. For example, if you flick an image up 100 pixels,
+ \c yPosition will be 100.
+*/
+
+/*!
+ \property QFxFlickable::xPosition
+ \brief the x position of the view.
+
+ The xPosition represents the left-most visible coordinate in the view.
+*/
+qreal QFxFlickable::xPosition() const
+{
+ Q_D(const QFxFlickable);
+ return -d->_moveX.value();
+}
+
+void QFxFlickable::setXPosition(qreal pos)
+{
+ Q_D(QFxFlickable);
+ pos = qRound(pos);
+ if (-pos != d->_moveX.value()) {
+ d->_tl.reset(d->_moveX);
+ d->_moveX.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+/*!
+ \property QFxFlickable::yPosition
+ \brief the y position of the view.
+
+ The yPosition represents the top-most visible coordinate in the view.
+*/
+qreal QFxFlickable::yPosition() const
+{
+ Q_D(const QFxFlickable);
+ return -d->_moveY.value();
+}
+
+void QFxFlickable::setYPosition(qreal pos)
+{
+ Q_D(QFxFlickable);
+ pos = qRound(pos);
+ if (-pos != d->_moveY.value()) {
+ d->_tl.reset(d->_moveY);
+ d->_moveY.setValue(-pos);
+ viewportMoved();
+ }
+}
+
+/*!
+ \qmlproperty bool Flickable::locked
+
+ A user cannot drag or flick a Flickable that is locked.
+
+ This property is useful for temporarily disabling flicking. This allows
+ special interaction with Flickable's children: for example, you might want to
+ freeze a flickable map while viewing detailed information on a location popup that is a child of the Flickable.
+*/
+
+/*!
+ \property QFxFlickable::locked
+ \brief determines whether the user can move the view.
+
+ If the Flickable is locked, the user cannot move the view.
+*/
+bool QFxFlickable::isLocked() const
+{
+ Q_D(const QFxFlickable);
+ return d->locked;
+}
+
+void QFxFlickable::setLocked(bool lock)
+{
+ Q_D(QFxFlickable);
+ d->locked = lock;
+}
+
+/*!
+ \qmlproperty enumeration Flickable::dragMode
+ This property contains the kind of 'physics' applied when dragging the surface.
+
+ Two modes are supported:
+ \list
+ \i Hard - the view follows the user's input exactly.
+ \i Elastic - the view moves elastically in response to the user's input.
+ \endlist
+*/
+
+/*!
+ \property QFxFlickable::dragMode
+ \brief sets the kind of 'physics' applied when dragging the view.
+
+ Two modes are supported:
+ \list
+ \i Hard - the view follows the user's input exactly.
+ \i Elastic - the view moves elastically in response to the user's input.
+ \endlist
+*/
+QFxFlickable::DragMode QFxFlickable::dragMode() const
+{
+ Q_D(const QFxFlickable);
+ return d->dragMode;
+}
+
+void QFxFlickable::setDragMode(DragMode mode)
+{
+ Q_D(QFxFlickable);
+ d->dragMode = mode;
+}
+
+/*!
+ \qmlproperty real Flickable::xVelocity
+ \qmlproperty real Flickable::yVelocity
+
+ The instantaneous velocity of movement along the x and y axes, in pixels/sec.
+*/
+
+/*!
+ \property QFxFlickable::xVelocity
+ \brief provides the instantaneous velocity of movement in the x-axis (pixels/sec).
+*/
+qreal QFxFlickable::xVelocity() const
+{
+ Q_D(const QFxFlickable);
+ return d->xVelocity.value();
+}
+
+/*!
+ \property QFxFlickable::yVelocity
+ \brief provides the instantaneous velocity of movement in the y-axis (pixels/sec).
+*/
+qreal QFxFlickable::yVelocity() const
+{
+ Q_D(const QFxFlickable);
+ return d->yVelocity.value();
+}
+
+/*!
+ \qmlproperty bool Flickable::atXBeginning
+ \qmlproperty bool Flickable::atXEnd
+ \qmlproperty bool Flickable::atYBeginning
+ \qmlproperty bool Flickable::atYEnd
+
+ These properties are true if the flickable view is positioned at the beginning,
+ or end respecively.
+*/
+bool QFxFlickable::isAtXEnd() const
+{
+ Q_D(const QFxFlickable);
+ return d->atXEnd;
+}
+
+bool QFxFlickable::isAtXBeginning() const
+{
+ Q_D(const QFxFlickable);
+ return d->atXBeginning;
+}
+
+bool QFxFlickable::isAtYEnd() const
+{
+ Q_D(const QFxFlickable);
+ return d->atYEnd;
+}
+
+bool QFxFlickable::isAtYBeginning() const
+{
+ Q_D(const QFxFlickable);
+ return d->atYBeginning;
+}
+
+/*!
+ \qmlproperty real Flickable::pageXPosition
+ \qmlproperty real Flickable::pageWidth
+ \qmlproperty real Flickable::pageYPosition
+ \qmlproperty real Flickable::pageHeight
+
+ These properties describe the position and size of the currently viewed page.
+ The page size is defined as the percentage of the full view currently visible,
+ scaled to 0.0 - 1.0. The page position is also in the range 0.0 (beginning) to
+ 1.0 (end).
+
+ These properties are typically used to draw a scrollbar, for example:
+ \code
+ <Rect opacity="0.5" anchors.right="{MyListView.right-2}" width="6"
+ y="{MyListView.pageYPosition * MyListView.height}"
+ height="{MyListView.pageHeight * MyListView.height}"/>
+ \endcode
+*/
+qreal QFxFlickable::pageWidth() const
+{
+ Q_D(const QFxFlickable);
+ return d->pageWidth;
+}
+
+qreal QFxFlickable::pageXPosition() const
+{
+ Q_D(const QFxFlickable);
+ return d->pageXPosition;
+}
+
+qreal QFxFlickable::pageHeight() const
+{
+ Q_D(const QFxFlickable);
+ return d->pageHeight;
+}
+
+qreal QFxFlickable::pageYPosition() const
+{
+ Q_D(const QFxFlickable);
+ return d->pageYPosition;
+}
+
+void QFxFlickable::ticked()
+{
+ viewportMoved();
+}
+
+QFxItem *QFxFlickable::viewport()
+{
+ Q_D(QFxFlickable);
+ return d->_flick;
+}
+
+qreal QFxFlickable::visibleX() const
+{
+ Q_D(const QFxFlickable);
+ return -d->_moveX.value();
+}
+
+qreal QFxFlickable::visibleY() const
+{
+ Q_D(const QFxFlickable);
+ return -d->_moveY.value();
+}
+
+void QFxFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ if (!d->locked && d->_tl.isActive() && (qAbs(d->velocityX) > 10 || qAbs(d->velocityY) > 10))
+ d->stealMouse = true; // If we've been flicked then steal the click.
+ else
+ d->stealMouse = false;
+ d->pressed = true;
+ d->_tl.clear();
+ d->velocityX = -1;
+ d->velocityY = -1;
+ d->lastPos = QPoint();
+ d->lastPosTime.start();
+ d->pressPos = event->pos();
+ d->pressX = d->_moveX.value();
+ d->pressY = d->_moveY.value();
+ d->flicked = false;
+ d->pressTime.start();
+ if (d->dragMode == Elastic) {
+ d->elasticX.clear();
+ d->elasticY.clear();
+ }
+ d->velocityTime.start();
+}
+
+void QFxFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ if (d->locked || d->lastPosTime.isNull())
+ return;
+ bool rejectY = false;
+ bool rejectX = false;
+ bool moved = false;
+
+ if(yflick()) {
+ int dy = int(event->pos().y() - d->pressPos.y());
+ if (qAbs(dy) > FlickThreshold || d->pressTime.elapsed() > 200) {
+ qreal newY = dy + d->pressY;
+ const qreal minY = minYExtent();
+ const qreal maxY = maxYExtent();
+ if(newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if(newY < maxY && maxY - minY < 0)
+ newY = maxY + (newY - maxY) / 2;
+ if(overShoot() || (newY <= minY && newY >= maxY)) {
+ if (d->dragMode == Hard)
+ d->_moveY.setValue(newY);
+ else
+ d->elasticY.setValue(newY);
+ moved = true;
+ } else if (!overShoot())
+ rejectY = true;
+ if (qAbs(dy) > FlickThreshold)
+ d->stealMouse = true;
+ }
+ }
+
+ if(xflick()) {
+ int dx = int(event->pos().x() - d->pressPos.x());
+ if (qAbs(dx) > FlickThreshold || d->pressTime.elapsed() > 200) {
+ qreal newX = dx + d->pressX;
+ if(overShoot() || (newX <= minXExtent() && newX >= maxXExtent())) {
+ if (d->dragMode == Hard)
+ d->_moveX.setValue(newX);
+ else
+ d->elasticX.setValue(newX);
+ moved = true;
+ } else if (!overShoot())
+ rejectX = true;
+ if (qAbs(dx) > FlickThreshold)
+ d->stealMouse = true;
+ }
+ }
+
+ if(!d->lastPos.isNull()) {
+ qreal elapsed = qreal(d->lastPosTime.restart()) / 1000.;
+ if(elapsed <= 0)
+ elapsed = 1;
+ if(yflick()) {
+ qreal diff = event->pos().y() - d->lastPos.y();
+ d->velocityY = diff / elapsed;
+ }
+
+ if(xflick()) {
+ qreal diff = event->pos().x() - d->lastPos.x();
+ d->velocityX = diff / elapsed;
+ }
+ }
+
+ if(rejectY) d->velocityY = 0;
+ if(rejectX) d->velocityX = 0;
+
+ if (moved) {
+ viewportMoved();
+ movementStarting();
+ }
+
+ d->lastPos = event->pos();
+}
+
+void QFxFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_D(QFxFlickable);
+ d->pressed = false;
+ if (d->lastPosTime.isNull())
+ return;
+
+ if (d->dragMode == Elastic) {
+ d->elasticY.clear();
+ d->elasticX.clear();
+ }
+
+ d->vTime = d->_tl.time();
+ if(qAbs(d->velocityY) > 10) {
+ qreal maxDistance = -1;
+ // -ve velocity means list is moving up
+ if(d->velocityY > 0) {
+ if(d->_moveY.value() < minYExtent())
+ maxDistance = qAbs(minYExtent() -d->_moveY.value() + (d->overShoot?30:0));
+ } else {
+ if(d->_moveY.value() > maxYExtent())
+ maxDistance = qAbs(maxYExtent() - d->_moveY.value()) + (d->overShoot?30:0);
+ }
+ if(maxDistance > 0) {
+ qreal v = d->velocityY;
+ if(d->maxVelocity != -1 && d->maxVelocity < qAbs(v)) {
+ if(v < 0)
+ v = -d->maxVelocity;
+ else
+ v = d->maxVelocity;
+ }
+ d->_tl.accel(d->_moveY, v, 500, maxDistance);
+ d->_tl.execute(d->fixupYEvent);
+ d->flicked = true;
+ emit flickingChanged();
+ emit flickStarted();
+ } else {
+ d->fixupY();
+ }
+ } else {
+ d->fixupY();
+ }
+ if(qAbs(d->velocityX) > 10) {
+ qreal maxDistance = -1;
+ // -ve velocity means list is moving up
+ if(d->velocityX > 0) {
+ if(d->_moveX.value() < minXExtent())
+ maxDistance = qAbs(minXExtent()) -d->_moveX.value() + (d->overShoot?30:0);
+ } else {
+ if(d->_moveX.value() > maxXExtent())
+ maxDistance = qAbs(maxXExtent() - d->_moveX.value()) + (d->overShoot?30:0);
+ }
+ if(maxDistance > 0) {
+ qreal v = d->velocityX;
+ if(d->maxVelocity != -1 && d->maxVelocity < qAbs(v)) {
+ if(v < 0)
+ v = -d->maxVelocity;
+ else
+ v = d->maxVelocity;
+ }
+ d->_tl.accel(d->_moveX, v, 500, maxDistance);
+ d->_tl.execute(d->fixupXEvent);
+ d->flicked = true;
+ emit flickingChanged();
+ emit flickStarted();
+ } else {
+ d->fixupX();
+ }
+ } else {
+ d->fixupX();
+ }
+ d->stealMouse = false;
+ d->lastPosTime = QTime();
+
+ if(!d->_tl.isActive())
+ movementEnding();
+}
+
+qreal QFxFlickable::minYExtent() const
+{
+ return 0.0;
+}
+
+qreal QFxFlickable::minXExtent() const
+{
+ return 0.0;
+}
+
+/* returns -ve */
+qreal QFxFlickable::maxXExtent() const
+{
+ return width() - vWidth();
+}
+/* returns -ve */
+qreal QFxFlickable::maxYExtent() const
+{
+ return height() - vHeight();
+}
+
+void QFxFlickable::viewportMoved()
+{
+ Q_D(QFxFlickable);
+ //XXX should look at moveX here as well
+ if (d->flicked && (d->_moveY.value() > minYExtent() + (d->overShoot?30:0)
+ || d->_moveY.value() < maxYExtent() - (d->overShoot?30:0))){
+ d->flicked = false;
+ emit flickingChanged();
+ emit flickEnded();
+ d->_tl.reset(d->_moveY);
+ d->fixupY();
+ }
+
+ int elapsed = d->velocityTime.elapsed();
+
+ if (elapsed) {
+ qreal prevY = d->lastFlickablePosition.x();
+ qreal prevX = d->lastFlickablePosition.y();
+ d->velocityTimeline.clear();
+ if(d->pressed) {
+ qreal xVelocity = (prevX - d->_moveX.value()) * 1000 / elapsed;
+ qreal yVelocity = (prevY - d->_moveY.value()) * 1000 / elapsed;
+ d->velocityTimeline.move(d->xVelocity, xVelocity, d->velocityDecay);
+ d->velocityTimeline.move(d->xVelocity, 0, d->velocityDecay);
+ d->velocityTimeline.move(d->yVelocity, yVelocity, d->velocityDecay);
+ d->velocityTimeline.move(d->yVelocity, 0, d->velocityDecay);
+ } else {
+ if (d->_tl.time() != d->vTime) {
+ qreal xVelocity = (prevX - d->_moveX.value()) * 1000 / (d->_tl.time() - d->vTime);
+ qreal yVelocity = (prevY - d->_moveY.value()) * 1000 / (d->_tl.time() - d->vTime);
+ d->xVelocity.setValue(xVelocity);
+ d->yVelocity.setValue(yVelocity);
+ }
+ d->vTime = d->_tl.time();
+ }
+ }
+
+ d->lastFlickablePosition = QPointF(d->_moveY.value(), d->_moveX.value());
+ d->velocityTime.restart();
+ d->updateBeginningEnd();
+}
+
+void QFxFlickablePrivate::data_removeAt(int)
+{
+ // ###
+}
+
+int QFxFlickablePrivate::data_count() const
+{
+ // ###
+ return 0;
+}
+
+void QFxFlickablePrivate::data_append(QObject *o)
+{
+ Q_Q(QFxFlickable);
+ QFxItem *i = qobject_cast<QFxItem *>(o);
+ if(i)
+ _flick->children()->append(i);
+ else
+ o->setParent(q);
+}
+
+void QFxFlickablePrivate::data_insert(int, QObject *)
+{
+ // ###
+}
+
+QObject *QFxFlickablePrivate::data_at(int) const
+{
+ // ###
+ return 0;
+}
+
+void QFxFlickablePrivate::data_clear()
+{
+ // ###
+}
+
+
+QmlList<QObject *> *QFxFlickable::flickableData()
+{
+ Q_D(QFxFlickable);
+ return &d->data;
+}
+
+QmlList<QFxItem *> *QFxFlickable::flickableChildren()
+{
+ Q_D(QFxFlickable);
+ return d->_flick->children();
+}
+
+/*!
+ \qmlproperty bool Flickable::overShoot
+ This property holds the number of pixels the surface may overshoot the
+ Flickable's boundaries when flicked.
+
+ If overShoot is non-zero the contents can be flicked beyond the boundary
+ of the Flickable before being moved back to the boundary. This provides
+ the feeling that the edges of the view are soft, rather than a hard
+ physical boundary.
+*/
+
+/*!
+ \property QFxFlickable::overShoot
+ \brief the number of pixels the view may overshoot the boundaries when flicked.
+
+ If overShoot is non-zero the contents can be flicked beyond the boundary
+ of the view before being moved back to the boundary. This provides
+ the feeling that the edges of the view are soft, rather than a hard
+ physical boundary.
+*/
+bool QFxFlickable::overShoot() const
+{
+ Q_D(const QFxFlickable);
+ return d->overShoot;
+}
+
+void QFxFlickable::setOverShoot(bool o)
+{
+ Q_D(QFxFlickable);
+ d->overShoot = o;
+}
+
+/*!
+ \qmlproperty int Flickable::viewportWidth
+ \qmlproperty int Flickable::viewportHeight
+
+ The dimensions of the viewport (the surface controlled by Flickable). Typically this
+ should be set to the combined size of the items placed in the Flickable.
+
+ \code
+ <Flickable width="320" height="480" viewportWidth="{image.width}" viewportHeight="{image.height}">
+ <Image id="image" file="bigimage.png"/>
+ </Flickable>
+ \endcode
+*/
+
+/*!
+ \property QFxFlickable::viewportWidth
+ \brief the width of the view.
+*/
+int QFxFlickable::viewportWidth() const
+{
+ Q_D(const QFxFlickable);
+ return d->vWidth;
+}
+
+void QFxFlickable::setViewportWidth(int w)
+{
+ Q_D(QFxFlickable);
+ if (d->vWidth == w)
+ return;
+ d->vWidth = w;
+ if(w < 0)
+ d->_flick->setWidth(width());
+ else
+ d->_flick->setWidth(w);
+ emit viewportWidthChanged();
+ d->updateBeginningEnd();
+}
+
+void QFxFlickable::setWidth(int w)
+{
+ Q_D(QFxFlickable);
+ QFxItem::setWidth(w);
+ if(d->vWidth < 0) {
+ d->_flick->setWidth(w);
+ emit viewportWidthChanged();
+ d->updateBeginningEnd();
+ }
+}
+
+void QFxFlickable::setHeight(int h)
+{
+ Q_D(QFxFlickable);
+ QFxItem::setHeight(h);
+ if(d->vHeight < 0) {
+ d->_flick->setHeight(h);
+ emit viewportHeightChanged();
+ d->updateBeginningEnd();
+ }
+}
+
+/*!
+ \property QFxFlickable::viewportHeight
+ \brief the height of the view.
+*/
+int QFxFlickable::viewportHeight() const
+{
+ Q_D(const QFxFlickable);
+ return d->vHeight;
+}
+
+void QFxFlickable::setViewportHeight(int h)
+{
+ Q_D(QFxFlickable);
+ if (d->vHeight == h)
+ return;
+ d->vHeight = h;
+ if(h < 0)
+ d->_flick->setHeight(height());
+ else
+ d->_flick->setHeight(h);
+ emit viewportHeightChanged();
+ d->updateBeginningEnd();
+}
+
+int QFxFlickable::vWidth() const
+{
+ Q_D(const QFxFlickable);
+ if(d->vWidth < 0)
+ return width();
+ else
+ return d->vWidth;
+}
+
+int QFxFlickable::vHeight() const
+{
+ Q_D(const QFxFlickable);
+ if(d->vHeight < 0)
+ return height();
+ else
+ return d->vHeight;
+}
+
+bool QFxFlickable::xflick() const
+{
+ return vWidth() != width();
+}
+
+bool QFxFlickable::yflick() const
+{
+ return vHeight() != height();
+}
+
+bool QFxFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height()));
+ QFxItem *grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if ((d->stealMouse || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if (grabber && d->stealMouse && !grabber->keepMouseGrab())
+ mouseGrabberItem()->ungrabMouse();
+
+ return d->stealMouse;
+ } else if (!d->lastPosTime.isNull()) {
+ d->lastPosTime = QTime();
+ }
+ return false;
+}
+
+bool QFxFlickable::mouseFilter(QGraphicsSceneMouseEvent *e)
+{
+ if(!isVisible())
+ return false;
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ {
+ bool ret = sendMouseEvent(e);
+ if (e->type() == QEvent::GraphicsSceneMouseRelease)
+ return ret;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/*!
+ \qmlproperty int Flickable::maximumFlickVelocity
+ This property holds the maximum velocity that the user can flick the view.
+*/
+
+/*!
+ \property QFxFlickable::maximumFlickVelocity
+ \brief the maximum velocity that the user can flick the view.
+*/
+int QFxFlickable::maximumFlickVelocity() const
+{
+ Q_D(const QFxFlickable);
+ return d->maxVelocity;
+}
+
+void QFxFlickable::setMaximumFlickVelocity(int v)
+{
+ Q_D(QFxFlickable);
+ if(v == d->maxVelocity)
+ return;
+ d->maxVelocity = v;
+}
+
+bool QFxFlickable::isFlicking() const
+{
+ Q_D(const QFxFlickable);
+ return d->flicked;
+}
+
+int QFxFlickable::velocityDecay() const
+{
+ Q_D(const QFxFlickable);
+ return d->velocityDecay;
+}
+
+void QFxFlickable::setVelocityDecay(int decay)
+{
+ Q_D(QFxFlickable);
+ Q_ASSERT(decay >= 0);
+ if(decay == d->velocityDecay)
+ return;
+ d->velocityDecay = decay;
+ emit velocityDecayChanged(decay);
+}
+
+bool QFxFlickable::isMoving() const
+{
+ Q_D(const QFxFlickable);
+ return d->moving;
+}
+
+void QFxFlickable::movementStarting()
+{
+ Q_D(QFxFlickable);
+ if(!d->moving) {
+ d->moving = true;
+ emit movingChanged();
+ emit movementStarted();
+ }
+}
+
+void QFxFlickable::movementEnding()
+{
+ Q_D(QFxFlickable);
+ if(d->moving) {
+ d->moving = false;
+ emit movingChanged();
+ emit movementEnded();
+ }
+ if (d->flicked) {
+ d->flicked = false;
+ emit flickingChanged();
+ emit flickEnded();
+ }
+ d->xVelocity.setValue(0);
+}
+
+void QFxFlickablePrivate::updateVelocity()
+{
+ Q_Q(QFxFlickable);
+ emit q->velocityChanged(q->xVelocity(), q->yVelocity());
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxflickable.h b/src/declarative/fx/qfxflickable.h
new file mode 100644
index 0000000..1281788
--- /dev/null
+++ b/src/declarative/fx/qfxflickable.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXFLICKABLE_H
+#define QFXFLICKABLE_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxFlickablePrivate;
+class Q_DECLARATIVE_EXPORT QFxFlickable : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool overShoot READ overShoot WRITE setOverShoot)
+ Q_PROPERTY(int viewportWidth READ viewportWidth WRITE setViewportWidth NOTIFY viewportWidthChanged)
+ Q_PROPERTY(int viewportHeight READ viewportHeight WRITE setViewportHeight NOTIFY viewportHeightChanged)
+ Q_PROPERTY(qreal xPosition READ xPosition WRITE setXPosition NOTIFY positionChanged);
+ Q_PROPERTY(qreal yPosition READ yPosition WRITE setYPosition NOTIFY positionChanged);
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged)
+ Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged)
+ Q_PROPERTY(int velocityDecay READ velocityDecay WRITE setVelocityDecay NOTIFY velocityDecayChanged)
+ Q_PROPERTY(int maximumFlickVelocity READ maximumFlickVelocity WRITE setMaximumFlickVelocity)
+ Q_PROPERTY(bool locked READ isLocked WRITE setLocked)
+ Q_PROPERTY(DragMode dragMode READ dragMode WRITE setDragMode)
+ Q_PROPERTY(qreal xVelocity READ xVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(qreal yVelocity READ yVelocity NOTIFY velocityChanged)
+ Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged);
+ Q_PROPERTY(bool atYEnd READ isAtYEnd NOTIFY isAtBoundaryChanged);
+ Q_PROPERTY(bool atXBeginning READ isAtXBeginning NOTIFY isAtBoundaryChanged);
+ Q_PROPERTY(bool atYBeginning READ isAtYBeginning NOTIFY isAtBoundaryChanged);
+ Q_PROPERTY(qreal pageXPosition READ pageXPosition NOTIFY pageChanged);
+ Q_PROPERTY(qreal pageYPosition READ pageYPosition NOTIFY pageChanged);
+ Q_PROPERTY(qreal pageWidth READ pageWidth NOTIFY pageChanged);
+ Q_PROPERTY(qreal pageHeight READ pageHeight NOTIFY pageChanged);
+
+ Q_PROPERTY(QmlList<QObject *>* flickableData READ flickableData);
+ Q_PROPERTY(QmlList<QFxItem *>* flickableChildren READ flickableChildren);
+ Q_CLASSINFO("DefaultProperty", "flickableData")
+
+public:
+ QFxFlickable(QFxItem *parent=0);
+ ~QFxFlickable();
+
+ QmlList<QObject *> *flickableData();
+ QmlList<QFxItem *> *flickableChildren();
+
+ bool overShoot() const;
+ void setOverShoot(bool);
+
+ int viewportWidth() const;
+ void setViewportWidth(int);
+
+ int viewportHeight() const;
+ void setViewportHeight(int);
+
+ qreal xPosition() const;
+ void setXPosition(qreal pos);
+
+ qreal yPosition() const;
+ void setYPosition(qreal pos);
+
+ bool isMoving() const;
+ bool isFlicking() const;
+
+ int velocityDecay() const;
+ void setVelocityDecay(int);
+
+ int maximumFlickVelocity() const;
+ void setMaximumFlickVelocity(int);
+
+ bool isLocked() const;
+ void setLocked(bool);
+
+ Q_ENUMS(DragMode);
+ enum DragMode { Hard, Elastic };
+ DragMode dragMode() const;
+ void setDragMode(DragMode mode);
+
+ qreal xVelocity() const;
+ qreal yVelocity() const;
+
+ bool isAtXEnd() const;
+ bool isAtXBeginning() const;
+ qreal pageXPosition() const;
+ qreal pageWidth() const;
+
+ bool isAtYEnd() const;
+ bool isAtYBeginning() const;
+ qreal pageYPosition() const;
+ qreal pageHeight() const;
+
+ virtual void setWidth(int);
+ virtual void setHeight(int);
+ QFxItem *viewport();
+
+Q_SIGNALS:
+ void viewportWidthChanged();
+ void viewportHeightChanged();
+ void positionChanged();
+ void movingChanged();
+ void flickingChanged();
+ void movementStarted();
+ void movementEnded();
+ void flickStarted();
+ void flickEnded();
+ void velocityDecayChanged(int);
+ void velocityChanged(qreal, qreal);
+ void isAtBoundaryChanged();
+ void pageChanged();
+
+protected:
+ virtual bool mouseFilter(QGraphicsSceneMouseEvent *);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+
+ qreal visibleX() const;
+ qreal visibleY() const;
+
+protected Q_SLOTS:
+ virtual void ticked();
+ void movementStarting();
+ void movementEnding();
+
+protected:
+ virtual qreal minXExtent() const;
+ virtual qreal minYExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual qreal maxYExtent() const;
+ int vWidth() const;
+ int vHeight() const;
+ virtual void viewportMoved();
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+
+ bool xflick() const;
+ bool yflick() const;
+
+protected:
+ QFxFlickable(QFxFlickablePrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxFlickable)
+ Q_DECLARE_PRIVATE(QFxFlickable)
+};
+QML_DECLARE_TYPE(QFxFlickable);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxflickable_p.h b/src/declarative/fx/qfxflickable_p.h
new file mode 100644
index 0000000..ddbfb31
--- /dev/null
+++ b/src/declarative/fx/qfxflickable_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXFLICKABLE_P_H
+#define QFXFLICKABLE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdatetime.h"
+#include "qfxflickable.h"
+#include "qfxitem_p.h"
+#include "qml.h"
+#include "gfxvalueproxy.h"
+#include "private/qmlanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class ElasticValue : public QAbstractAnimation {
+ Q_OBJECT
+public:
+ ElasticValue(GfxValue &);
+ void setValue(qreal to);
+ void clear();
+
+ virtual int duration() const { return 10000; }
+
+protected:
+ virtual void updateCurrentTime(int);
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ qreal _to;
+ qreal _myValue;
+ qreal _velocity;
+ GfxValue &_value;
+ QTime _startTime;
+};
+
+class QFxFlickablePrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxFlickable)
+
+public:
+ QFxFlickablePrivate();
+ void init();
+ virtual void fixupX();
+ virtual void fixupY();
+ void updateBeginningEnd();
+
+public:
+ QFxItem *_flick;
+ GfxValueProxy<QFxItem> _moveX;
+ GfxValueProxy<QFxItem> _moveY;
+ QmlTimeLine _tl;
+ int vWidth;
+ int vHeight;
+ bool overShoot;
+ bool flicked;
+ bool moving;
+ bool stealMouse;
+ bool pressed;
+ QTime lastPosTime;
+ QPointF lastPos;
+ QPointF pressPos;
+ qreal pressX;
+ qreal pressY;
+ qreal velocityX;
+ qreal velocityY;
+ QTime pressTime;
+ GfxEvent fixupXEvent;
+ GfxEvent fixupYEvent;
+ int maxVelocity;
+ bool locked;
+ QFxFlickable::DragMode dragMode;
+ ElasticValue elasticY;
+ ElasticValue elasticX;
+ QTime velocityTime;
+ QPointF lastFlickablePosition;
+ int velocityDecay;
+
+ void updateVelocity();
+ struct Velocity : public GfxValue
+ {
+ Velocity(QFxFlickablePrivate *p)
+ : parent(p) {}
+ virtual void setValue(qreal v) {
+ GfxValue::setValue(v);
+ parent->updateVelocity();
+ }
+ QFxFlickablePrivate *parent;
+ };
+ Velocity xVelocity;
+ Velocity yVelocity;
+ int vTime;
+ QmlTimeLine velocityTimeline;
+ bool atXEnd;
+ bool atXBeginning;
+ qreal pageXPosition;
+ qreal pageWidth;
+ bool atYEnd;
+ bool atYBeginning;
+ qreal pageYPosition;
+ qreal pageHeight;
+
+ // flickableData property
+ void data_removeAt(int);
+ int data_count() const;
+ void data_append(QObject *);
+ void data_insert(int, QObject *);
+ QObject *data_at(int) const;
+ void data_clear();
+ QML_DECLARE_LIST_PROXY(QFxFlickablePrivate, QObject *, data);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/fx/qfxfocuspanel.cpp b/src/declarative/fx/qfxfocuspanel.cpp
new file mode 100644
index 0000000..1bca424
--- /dev/null
+++ b/src/declarative/fx/qfxfocuspanel.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxfocuspanel.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxFocusPanel,FocusPanel);
+
+/*!
+ \qmlclass FocusPanel
+ \brief The FocusPanel element explicitly creates a focus panel.
+ \inherits Item
+
+ Focus panels assist in keyboard focus handling when building QML
+ applications. All the details are covered in the
+ \l {qmlfocus}{keyboard focus documentation}.
+*/
+
+/*!
+ \internal
+ \class QFxFocusPanel
+*/
+
+QFxFocusPanel::QFxFocusPanel(QFxItem *parent) :
+ QFxItem(parent)
+{
+ setOptions(IsFocusPanel);
+}
+
+QFxFocusPanel::~QFxFocusPanel()
+{
+}
+
+/*!
+ \qmlproperty bool FocusPanel::active
+
+ Sets whether the element is the active focus panel.
+*/
+
+bool QFxFocusPanel::isActive() const
+{
+ QSimpleCanvas *canvas = QSimpleCanvasItem::canvas();
+ if(canvas)
+ return canvas->activeFocusPanel() == this;
+ else
+ return false;
+}
+
+void QFxFocusPanel::setActive(bool a)
+{
+ setActiveFocusPanel(a);
+}
+
+void QFxFocusPanel::activePanelInEvent()
+{
+ QFxItem::activePanelInEvent();
+ emit activeChanged();
+}
+
+void QFxFocusPanel::activePanelOutEvent()
+{
+ QFxItem::activePanelOutEvent();
+ emit activeChanged();
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxfocuspanel.h b/src/declarative/fx/qfxfocuspanel.h
new file mode 100644
index 0000000..38f7a15
--- /dev/null
+++ b/src/declarative/fx/qfxfocuspanel.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXFOCUSPANEL_H
+#define QFXFOCUSPANEL_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxFocusPanel : public QFxItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
+public:
+ QFxFocusPanel(QFxItem *parent=0);
+ virtual ~QFxFocusPanel();
+
+ bool isActive() const;
+ void setActive(bool);
+
+Q_SIGNALS:
+ void activeChanged();
+
+protected:
+ virtual void activePanelInEvent();
+ virtual void activePanelOutEvent();
+
+private:
+ Q_DISABLE_COPY(QFxFocusPanel)
+};
+
+QML_DECLARE_TYPE(QFxFocusPanel);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXFOCUSPANEL_H
diff --git a/src/declarative/fx/qfxfocusrealm.cpp b/src/declarative/fx/qfxfocusrealm.cpp
new file mode 100644
index 0000000..da3f1b2
--- /dev/null
+++ b/src/declarative/fx/qfxfocusrealm.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxfocusrealm.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxFocusRealm,FocusRealm);
+
+/*!
+ \qmlclass FocusRealm
+ \brief The FocusRealm element explicitly creates a focus realm.
+ \inherits Item
+
+ Focus realms assist in keyboard focus handling when building reusable QML
+ components. All the details are covered in the
+ \l {qmlfocus}{keyboard focus documentation}.
+*/
+
+/*!
+ \internal
+ \class QFxFocusRealm
+*/
+
+QFxFocusRealm::QFxFocusRealm(QFxItem *parent) :
+ QFxItem(parent)
+{
+ setOptions(IsFocusRealm);
+}
+
+QFxFocusRealm::~QFxFocusRealm()
+{
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxfocusrealm.h b/src/declarative/fx/qfxfocusrealm.h
new file mode 100644
index 0000000..6c35405
--- /dev/null
+++ b/src/declarative/fx/qfxfocusrealm.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXFOCUSREALM_H
+#define QFXFOCUSREALM_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxFocusRealm : public QFxItem
+{
+ Q_OBJECT
+public:
+ QFxFocusRealm(QFxItem *parent=0);
+ virtual ~QFxFocusRealm();
+};
+
+QML_DECLARE_TYPE(QFxFocusRealm);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXFOCUSREALM_H
diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp
new file mode 100644
index 0000000..f9a9f8c
--- /dev/null
+++ b/src/declarative/fx/qfxgridview.cpp
@@ -0,0 +1,1469 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxvisualitemmodel.h"
+#include "qlistmodelinterface.h"
+#include "qmlfollow.h"
+#include "private/qfxflickable_p.h"
+#include "qfxgridview.h"
+
+QT_BEGIN_NAMESPACE
+
+class QFxGridViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QFxGridViewAttached(QObject *parent)
+ : QObject(parent), m_isCurrent(false), m_delayRemove(false) {}
+ ~QFxGridViewAttached() {
+ attachedProperties.remove(parent());
+ }
+
+ Q_PROPERTY(QFxGridView *view READ view);
+ QFxGridView *view() { return m_view; }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged);
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged);
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ static QFxGridViewAttached *properties(QObject *obj) {
+ if(!attachedProperties.contains(obj)) {
+ QFxGridViewAttached *rv = new QFxGridViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ return rv;
+ }
+ return attachedProperties.value(obj);
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+signals:
+ void currentItemChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+
+public:
+ QFxGridView *m_view;
+ bool m_isCurrent;
+ bool m_delayRemove;
+
+ static QHash<QObject*, QFxGridViewAttached*> attachedProperties;
+};
+
+QHash<QObject*, QFxGridViewAttached*> QFxGridViewAttached::attachedProperties;
+
+
+//----------------------------------------------------------------------------
+
+class FxGridItem
+{
+public:
+ FxGridItem(QFxItem *i, QFxGridView *v) : item(i), view(v) {
+ attached = QFxGridViewAttached::properties(item);
+ attached->m_view = view;
+ }
+ ~FxGridItem() {}
+
+ qreal rowPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->y() : item->x()); }
+ qreal colPos() const { return (view->flow() == QFxGridView::LeftToRight ? item->x() : item->y()); }
+ qreal endRowPos() const {
+ return (view->flow() == QFxGridView::LeftToRight
+ ? item->y() + (item->height() > 0 ? item->height() : 1)
+ : item->x() + (item->width() > 0 ? item->width() : 1)) - 1;
+ }
+ void setPosition(qreal col, qreal row) {
+ if (view->flow() == QFxGridView::LeftToRight) {
+ item->setPos(QPointF(col, row));
+ } else {
+ item->setPos(QPointF(row, col));
+ }
+ }
+
+ QFxItem *item;
+ QFxGridView *view;
+ QFxGridViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QFxGridViewPrivate : public QFxFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QFxGridView);
+
+public:
+ QFxGridViewPrivate()
+ : model(0), currentItem(0), tmpCurrent(0), flow(QFxGridView::LeftToRight)
+ , visiblePos(0), visibleIndex(0) , currentIndex(-1)
+ , cellWidth(100), cellHeight(100), columns(1)
+ , highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0)
+ , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true)
+ , fixCurrentVisibility(false) {}
+
+ void init();
+ void clear();
+ FxGridItem *getItem(int modelIndex);
+ FxGridItem *createItem(int modelIndex);
+ void releaseItem(FxGridItem *item);
+ void refill(qreal from, qreal to);
+
+ void updateGrid();
+ void layout(bool removed=false);
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void updateCurrent(int modelIndex);
+
+ FxGridItem *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxGridItem *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ qreal position() const {
+ Q_Q(const QFxGridView);
+ return flow == QFxGridView::LeftToRight ? q->yPosition() : q->xPosition();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QFxGridView);
+ if (flow == QFxGridView::LeftToRight)
+ q->setYPosition(pos);
+ else
+ q->setXPosition(pos);
+ }
+ int size() const {
+ Q_Q(const QFxGridView);
+ return flow == QFxGridView::LeftToRight ? q->height() : q->width();
+ }
+ qreal startPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty())
+ pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize();
+ return pos;
+ }
+
+ qreal endPosition() const {
+ qreal pos = 0;
+ if (model && model->count())
+ pos = rowPosAt(model->count() - 1) + rowSize();
+ return pos;
+ }
+
+ bool isValid() const {
+ return model && model->count() && (!ownModel || model->delegate());
+ }
+
+ int rowSize() const {
+ return flow == QFxGridView::LeftToRight ? cellHeight : cellWidth;
+ }
+ int colSize() const {
+ return flow == QFxGridView::LeftToRight ? cellWidth : cellHeight;
+ }
+
+ qreal colPosAt(int modelIndex) const {
+ if (FxGridItem *item = visibleItem(modelIndex))
+ return item->colPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = (visibleIndex - modelIndex) % columns;
+ int col = visibleItems.first()->colPos() / colSize();
+ col = (columns - count + col) % columns;
+ return col * colSize();
+ } else {
+ int count = columns - 1 - (modelIndex - visibleItems.last()->index - 1) % columns;
+ return visibleItems.last()->colPos() - count * colSize();
+ }
+ }
+ return 0;
+ }
+ qreal rowPosAt(int modelIndex) const {
+ if (FxGridItem *item = visibleItem(modelIndex))
+ return item->rowPos();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int firstCol = visibleItems.first()->colPos() / colSize();
+ int col = visibleIndex - modelIndex + (columns - firstCol - 1);
+ int rows = col / columns;
+ return visibleItems.first()->rowPos() - rows * rowSize();
+ } else {
+ int count = modelIndex - visibleItems.last()->index;
+ int col = visibleItems.last()->colPos() + count * colSize();
+ int rows = col / (columns * colSize());
+ return visibleItems.last()->rowPos() + rows * rowSize();
+ }
+ }
+ return 0;
+ }
+
+ // Map a model index to visibleItems list index.
+ // These may differ if removed items are still present in the visible list,
+ // e.g. doing a removal animation
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItem *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i + visibleIndex;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxGridItem *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ qDebug() << "index" << visibleIndex << i << listItem->index;
+ for (int j = 0; j < visibleItems.count(); j++)
+ qDebug() << " index" << j << "item index" << visibleItems.at(j)->index;
+ abort();
+ }
+ }
+ }
+
+ QFxVisualItemModel *model;
+ QVariant modelVariant;
+ QList<FxGridItem*> visibleItems;
+ FxGridItem *currentItem;
+ QFxItem *tmpCurrent;
+ QFxGridView::Flow flow;
+ int visiblePos;
+ int visibleIndex;
+ int currentIndex;
+ int cellWidth;
+ int cellHeight;
+ int columns;
+ QmlComponent *highlightComponent;
+ FxGridItem *highlight;
+ FxGridItem *trackedItem;
+ enum MovementReason { Other, Key, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QmlFollow *highlightXAnimator;
+ QmlFollow *highlightYAnimator;
+
+ int keyPressed : 1;
+ int ownModel : 1;
+ int wrap : 1;
+ int autoHighlight : 1;
+ int fixCurrentVisibility : 1;
+};
+
+void QFxGridViewPrivate::init()
+{
+ Q_Q(QFxGridView);
+ q->setOptions(QFxGridView::IsFocusRealm);
+}
+
+void QFxGridViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visiblePos = 0;
+ visibleIndex = 0;
+ if (currentItem) {
+ FxGridItem *tmpItem = currentItem;
+ currentItem = 0;
+ currentIndex = -1;
+ releaseItem(tmpItem);
+ }
+ createHighlight();
+ trackedItem = 0;
+}
+
+FxGridItem *QFxGridViewPrivate::getItem(int modelIndex)
+{
+ if (currentItem && modelIndex == currentIndex)
+ return currentItem;
+ if (FxGridItem *listItem = visibleItem(modelIndex))
+ return listItem;
+ return createItem(modelIndex);
+}
+
+FxGridItem *QFxGridViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QFxGridView);
+ // create object
+ FxGridItem *listItem = 0;
+ if (QFxItem *item = model->item(modelIndex, false)) {
+ listItem = new FxGridItem(item, q);
+ listItem->index = modelIndex;
+ // complete
+ model->completeItem();
+ listItem->item->setZ(modelIndex + 1);
+ listItem->item->setParent(q->viewport());
+ }
+ return listItem;
+}
+
+
+void QFxGridViewPrivate::releaseItem(FxGridItem *item)
+{
+ Q_Q(QFxGridView);
+ if (item != currentItem) {
+ if (trackedItem == item) {
+ QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+ model->release(item->item);
+ delete item;
+ }
+}
+
+void QFxGridViewPrivate::refill(qreal from, qreal to)
+{
+ Q_Q(QFxGridView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+
+ from -= buffer;
+ to += buffer;
+ bool changed = false;
+
+ int colPos = 0;
+ int rowPos = 0;
+ int modelIndex = 0;
+ if (visibleItems.count()) {
+ rowPos = visibleItems.last()->rowPos();
+ colPos = visibleItems.last()->colPos() + colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+
+ FxGridItem *item = 0;
+ while (modelIndex < model->count() && rowPos <= to) {
+ //qDebug() << "refill: append item" << modelIndex;
+ item = getItem(modelIndex);
+ item->setPosition(colPos, rowPos);
+ visibleItems.append(item);
+ colPos += colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ ++modelIndex;
+ changed = true;
+ }
+
+ if (visibleItems.count()) {
+ rowPos = visibleItems.first()->rowPos();
+ colPos = visibleItems.first()->colPos() - colSize();
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ rowPos -= rowSize();
+ }
+ }
+ while (visibleIndex > 0 && rowPos + rowSize() - 1 >= from){
+ //qDebug() << "refill: prepend item" << visibleIndex-1 << "top pos" << rowPos << colPos;
+ item = getItem(visibleIndex-1);
+ --visibleIndex;
+ item->setPosition(colPos, rowPos);
+ visibleItems.prepend(item);
+ colPos -= colSize();
+ if (colPos < 0) {
+ colPos = colSize() * (columns - 1);
+ rowPos -= rowSize();
+ }
+ changed = true;
+ }
+
+ while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endRowPos() < from) {
+ if (item->attached->delayRemove())
+ break;
+ //qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->rowPos() > to) {
+ if (item->attached->delayRemove())
+ break;
+ //qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ if (changed) {
+ if (flow == QFxGridView::LeftToRight)
+ q->setViewportHeight(endPosition() - startPosition());
+ else
+ q->setViewportWidth(endPosition() - startPosition());
+ }
+}
+
+void QFxGridViewPrivate::updateGrid()
+{
+ Q_Q(QFxGridView);
+ columns = (int)qMax((flow == QFxGridView::LeftToRight ? q->width() : q->height()) / colSize(), 1.);
+ if (isValid()) {
+ if (flow == QFxGridView::LeftToRight)
+ q->setViewportHeight(endPosition() - startPosition());
+ else
+ q->setViewportWidth(endPosition() - startPosition());
+ }
+}
+
+void QFxGridViewPrivate::layout(bool removed)
+{
+ Q_Q(QFxGridView);
+ if (visibleItems.count()) {
+ qreal rowPos = visibleItems.first()->rowPos();
+ qreal colPos = visibleItems.first()->colPos();
+ if (visibleIndex % columns != 0) {
+ if (removed)
+ rowPos -= rowSize();
+ colPos = (visibleIndex % columns) * colSize();
+ visibleItems.first()->setPosition(colPos, rowPos);
+ } else if (colPos != 0) {
+ colPos = 0;
+ visibleItems.first()->setPosition(colPos, rowPos);
+ }
+ for (int i = 1; i < visibleItems.count(); ++i) {
+ FxGridItem *item = visibleItems.at(i);
+ colPos += colSize();
+ if (colPos > colSize() * (columns-1)) {
+ colPos = 0;
+ rowPos += rowSize();
+ }
+ item->setPosition(colPos, rowPos);
+ }
+ }
+ q->refill();
+ q->trackedPositionChanged();
+ updateHighlight();
+ if (flow == QFxGridView::LeftToRight) {
+ q->setViewportHeight(endPosition() - startPosition());
+ fixupY();
+ } else {
+ q->setViewportWidth(endPosition() - startPosition());
+ fixupX();
+ }
+}
+
+void QFxGridViewPrivate::updateTrackedItem()
+{
+ Q_Q(QFxGridView);
+ FxGridItem *item = currentItem;
+ if (highlight)
+ item = highlight;
+
+ if (trackedItem && item != trackedItem) {
+ QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+
+ if (!trackedItem && item) {
+ trackedItem = item;
+ QObject::connect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::connect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged()));
+ q->trackedPositionChanged();
+ }
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QFxGridViewPrivate::createHighlight()
+{
+ Q_Q(QFxGridView);
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ delete highlight->item;
+ delete highlight;
+ highlight = 0;
+ delete highlightXAnimator;
+ delete highlightYAnimator;
+ highlightXAnimator = 0;
+ highlightYAnimator = 0;
+ }
+
+ if (!highlightComponent)
+ return;
+
+ if (currentItem) {
+ QmlContext *highlightContext = new QmlContext(q->itemContext());
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ highlightContext->setParent(nobj);
+ QFxItem *item = qobject_cast<QFxItem *>(nobj);
+ if (item) {
+ item->setParent(q->viewport());
+ highlight = new FxGridItem(item, q);
+ highlightXAnimator = new QmlFollow(q);
+ highlightXAnimator->setTarget(QmlMetaProperty(highlight->item, QLatin1String("x")));
+ highlightXAnimator->setSpring(3);
+ highlightXAnimator->setDamping(0.3);
+ highlightXAnimator->setEnabled(autoHighlight);
+ highlightYAnimator = new QmlFollow(q);
+ highlightYAnimator->setTarget(QmlMetaProperty(highlight->item, QLatin1String("y")));
+ highlightYAnimator->setSpring(3);
+ highlightYAnimator->setDamping(0.3);
+ highlightYAnimator->setEnabled(autoHighlight);
+ } else {
+ delete highlightContext;
+ }
+ }
+ }
+}
+
+void QFxGridViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ updateTrackedItem();
+ if (currentItem && autoHighlight && highlight) {
+ // auto-update highlight
+ highlightXAnimator->setSourceValue(currentItem->item->x());
+ highlightYAnimator->setSourceValue(currentItem->item->y());
+ highlight->item->setWidth(currentItem->item->width());
+ highlight->item->setHeight(currentItem->item->height());
+ }
+}
+
+void QFxGridViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QFxGridView);
+ if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ FxGridItem *item = currentItem;
+ currentItem = 0;
+ currentIndex = 0;
+ updateHighlight();
+ releaseItem(item);
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ if (tmpCurrent) {
+ delete tmpCurrent;
+ tmpCurrent = 0;
+ }
+ int oldCurrentIndex = currentIndex;
+ FxGridItem *oldCurrentItem = currentItem;
+ currentIndex = -1;
+ currentItem = visibleItem(modelIndex);
+ if (!currentItem) {
+ currentItem = getItem(modelIndex);
+ currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
+ }
+ currentIndex = modelIndex;
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && oldCurrentItem->item != currentItem->item)
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ updateHighlight();
+ emit q->currentIndexChanged();
+ // Release the old current item
+ if (oldCurrentItem && !visibleItem(oldCurrentIndex))
+ releaseItem(oldCurrentItem);
+}
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass GridView
+ \inherits Flickable
+ \brief The GridView element provides a grid view of items provided by a model.
+
+ The model is typically provided by a QAbstractListModel "C++ model object",
+ but can also be created directly in XML.
+
+ The items are laid out top to bottom (vertically) or left to right (horizontally)
+ and may be flicked to scroll.
+
+ The below example creates a very simple grid, using an XML model.
+ \code
+ <resources>
+ <ListModel id="contactModel">
+ <Contact>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+ <Component id="contactDelegate">
+ <Rect pen.color="blue" z="-1" height="20" width="80" color="white" radius="2">
+ <Text id="name" text="{firstName + ' ' + lastName}" font.size="11"/>
+ </Rect>
+ </Component>
+ </resources>
+
+ <GridView id="Grid" width="160" height="240" cellWidth="80" cellHeight="20" clip="true"
+ model="{contactModel}" delegate="{contactDelegate}"/>
+ \endcode
+*/
+QFxGridView::QFxGridView(QFxItem *parent)
+ : QFxFlickable(*(new QFxGridViewPrivate), parent)
+{
+ Q_D(QFxGridView);
+ d->init();
+}
+
+QFxGridView::~QFxGridView()
+{
+ Q_D(QFxGridView);
+ if (d->ownModel)
+ delete d->model;
+}
+
+/*!
+ \qmlproperty model GridView::model
+ This property holds the model providing data for the grid.
+
+ The model provides a set of data that is used to create the items for the view.
+ For large or dynamic datasets the model is usually provided by a C++ model object.
+ The C++ model object must be a \l QListModelInterface subclass, a \l VisualModel,
+ or a simple list.
+
+ Models can also be created directly in XML, using the \l ListModel element. For example:
+ \code
+ <ListModel id="contactModel">
+ <Contact>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+
+ <GridView model="{contactModel}" .../>
+ \endcode
+*/
+QVariant QFxGridView::model() const
+{
+ Q_D(const QFxGridView);
+ return d->modelVariant;
+}
+
+void QFxGridView::setModel(const QVariant &model)
+{
+ Q_D(QFxGridView);
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ }
+ d->clear();
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QFxVisualItemModel *vim = 0;
+ if (object && (vim = qobject_cast<QFxVisualItemModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel(itemContext());
+ d->ownModel = true;
+ }
+ d->model->setModel(model);
+ }
+ if (d->model) {
+ if (d->currentIndex >= d->model->count() || d->currentIndex < 0)
+ setCurrentIndex(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ refill();
+ emit countChanged();
+ }
+}
+
+/*!
+ \qmlproperty component GridView::delegate
+
+ The delegate provides a template describing what each item in the view should look and act like.
+
+ Here is an example delegate:
+ \code
+ <Component id="contactDelegate">
+ <Item id="wrapper">
+ <Image id="pic" width="100" height="100" file="{portrait}"/>
+ <Text id="name" text="{firstName + ' ' + lastName}"
+ anchors.left="{pic.right}" anchors.leftMargin="5"/>
+ </Item>
+ </Component>
+ ...
+ <GridView delegate="{contactDelegate}" .../>
+ \endcode
+*/
+QmlComponent *QFxGridView::delegate() const
+{
+ Q_D(const QFxGridView);
+ return d->model ? d->model->delegate() : 0;
+}
+
+void QFxGridView::setDelegate(QmlComponent *delegate)
+{
+ Q_D(QFxGridView);
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel(itemContext());
+ d->ownModel = true;
+ }
+ d->model->setDelegate(delegate);
+ d->updateCurrent(d->currentIndex);
+ refill();
+}
+
+/*!
+ \qmlproperty int GridView::currentIndex
+ \qmlproperty Item GridView::current
+
+ \c currentIndex holds the index of the current item.
+ \c current is the current item. Note that the position of the current item
+ may only be approximate until it becomes visible in the view.
+*/
+int QFxGridView::currentIndex() const
+{
+ Q_D(const QFxGridView);
+ return d->currentIndex;
+}
+
+void QFxGridView::setCurrentIndex(int index)
+{
+ Q_D(QFxGridView);
+ if (d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0)
+ d->updateCurrent(index);
+ else
+ d->currentIndex = index;
+}
+
+QFxItem *QFxGridView::currentItem()
+{
+ Q_D(QFxGridView);
+ if (!d->currentItem) {
+ // Always return something valid
+ if (!d->tmpCurrent)
+ d->tmpCurrent = new QFxItem(viewport());
+ return d->tmpCurrent;
+ }
+ return d->currentItem->item;
+}
+
+/*!
+ \qmlproperty int GridView::count
+ This property holds the number of items in the view.
+*/
+int QFxGridView::count() const
+{
+ Q_D(const QFxGridView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+/*!
+ \qmlproperty component GridView::highlight
+ This property holds the component to use as the highlight.
+
+ An instance of the highlight component will be created for each view.
+ The geometry of the resultant component instance will be managed by the view
+ so as to stay with the current item, unless the autoHighlight property is false.
+
+ The below example demonstrates how to make a simple highlight:
+ \code
+ <Component id="ListHighlight">
+ <Rect color="lightsteelblue" radius="4"/>
+ </Component>
+ <GridView highlight="{ListHighlight}">
+ \endcode
+
+ \sa autoHighlight
+*/
+QmlComponent *QFxGridView::highlight() const
+{
+ Q_D(const QFxGridView);
+ return d->highlightComponent;
+}
+
+void QFxGridView::setHighlight(QmlComponent *highlight)
+{
+ Q_D(QFxGridView);
+ delete d->highlightComponent;
+ d->highlightComponent = highlight;
+ d->updateCurrent(d->currentIndex);
+}
+
+/*!
+ \qmlproperty component GridView::autoHighlight
+ This property sets whether the highlight is managed by the view.
+
+ If autoHighlight is true, the highlight will be moved smoothly
+ to follow the current item. If autoHighlight is false, the
+ highlight will not be moved by the view, and must be implemented
+ by the highlight, for example:
+
+ \code
+ <Component id="Highlight">
+ <Rect id="Wrapper" color="#242424" radius="4" width="320" height="60" >
+ <y>
+ <Follow source="{Wrapper.GridView.view.current.y}" spring="3" damping="0.2"/>
+ </y>
+ <x>
+ <Follow source="{Wrapper.GridView.view.current.x}" spring="3" damping="0.2"/>
+ </x>
+ </Rect>
+ </Component>
+ \endcode
+*/
+bool QFxGridView::autoHighlight() const
+{
+ Q_D(const QFxGridView);
+ return d->autoHighlight;
+}
+
+void QFxGridView::setAutoHighlight(bool autoHighlight)
+{
+ Q_D(QFxGridView);
+ d->autoHighlight = autoHighlight;
+ if (d->highlightXAnimator) {
+ d->highlightXAnimator->setEnabled(d->autoHighlight);
+ d->highlightYAnimator->setEnabled(d->autoHighlight);
+ }
+ d->updateHighlight();
+}
+
+/*!
+ \qmlproperty enumeration GridView::flow
+ This property holds the flow of the grid.
+
+ Possible values are \c LeftToRight (default) and \c TopToBottom.
+
+ If \a flow is \c LeftToRight, the view will scroll vertically.
+ If \a flow is \c TopToBottom, the view will scroll horizontally.
+*/
+QFxGridView::Flow QFxGridView::flow() const
+{
+ Q_D(const QFxGridView);
+ return d->flow;
+}
+
+void QFxGridView::setFlow(Flow flow)
+{
+ Q_D(QFxGridView);
+ if (d->flow != flow) {
+ d->flow = flow;
+ if (d->flow == LeftToRight)
+ setViewportWidth(-1);
+ else
+ setViewportHeight(-1);
+ d->clear();
+ d->updateGrid();
+ refill();
+ d->updateCurrent(d->currentIndex);
+ }
+}
+
+/*!
+ \qmlproperty bool GridView::wrap
+ This property holds whether the grid wraps key navigation
+
+ If this property is true then key presses to move off of one end of the grid will cause the
+ selection to jump to the other side.
+*/
+bool QFxGridView::isWrapEnabled() const
+{
+ Q_D(const QFxGridView);
+ return d->wrap;
+}
+
+void QFxGridView::setWrapEnabled(bool wrap)
+{
+ Q_D(QFxGridView);
+ d->wrap = wrap;
+}
+
+/*!
+ \qmlproperty int GridView::cacheBuffer
+ This property holds the number of off-screen pixels to cache.
+
+ This property determines the number of pixels above the top of the view
+ and below the bottom of the view to cache. Setting this value can make
+ scrolling the view smoother at the expense of additional memory usage.
+*/
+
+/*!
+ \property QFxGridView::cacheBuffer
+ \brief sets the number of off-screen pixels to cache.
+
+ This property determines the number of pixels above the top of the view
+ and below the bottom of the view to cache. Setting this value can make
+ scrolling the view smoother at the expense of additional memory usage.
+*/
+int QFxGridView::cacheBuffer() const
+{
+ Q_D(const QFxGridView);
+ return d->buffer;
+}
+
+void QFxGridView::setCacheBuffer(int buffer)
+{
+ Q_D(QFxGridView);
+ if(d->buffer != buffer) {
+ d->buffer = buffer;
+ if (isComponentComplete())
+ refill();
+ }
+}
+
+/*!
+ \qmlproperty int GridView::cellWidth
+ This property holds the width of each cell in the grid
+
+ The default cellWidth is 100.
+*/
+int QFxGridView::cellWidth() const
+{
+ Q_D(const QFxGridView);
+ return d->cellWidth;
+}
+
+void QFxGridView::setCellWidth(int cellWidth)
+{
+ Q_D(QFxGridView);
+ if (cellWidth != d->cellWidth && cellWidth > 0) {
+ d->cellWidth = qMax(1, cellWidth);
+ d->updateGrid();
+ emit cellSizeChanged();
+ d->layout();
+ }
+}
+
+/*!
+ \qmlproperty int GridView::cellHeight
+ This property holds the height of each cell in the grid
+
+ The default cellHeight is 100.
+*/
+int QFxGridView::cellHeight() const
+{
+ Q_D(const QFxGridView);
+ return d->cellHeight;
+}
+
+void QFxGridView::setCellHeight(int cellHeight)
+{
+ Q_D(QFxGridView);
+ if (cellHeight != d->cellHeight && cellHeight > 0) {
+ d->cellHeight = qMax(1, cellHeight);
+ d->updateGrid();
+ emit cellSizeChanged();
+ d->layout();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::setHeight(int height)
+{
+ Q_D(QFxGridView);
+ QFxFlickable::setHeight(height);
+ if (isComponentComplete()) {
+ d->updateGrid();
+ d->layout();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::setWidth(int width)
+{
+ Q_D(QFxGridView);
+ QFxFlickable::setWidth(width);
+ if (isComponentComplete()) {
+ d->updateGrid();
+ d->layout();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::viewportMoved()
+{
+ QFxFlickable::viewportMoved();
+ refill();
+}
+
+/*!
+ \reimp
+*/
+qreal QFxGridView::minYExtent() const
+{
+ Q_D(const QFxGridView);
+ if (d->flow == QFxGridView::TopToBottom)
+ return QFxFlickable::minYExtent();
+ return -d->startPosition();
+}
+
+/*!
+ \reimp
+*/
+qreal QFxGridView::maxYExtent() const
+{
+ Q_D(const QFxGridView);
+ if (d->flow == QFxGridView::TopToBottom)
+ return QFxFlickable::maxYExtent();
+ return -(d->endPosition() - height());
+}
+
+/*!
+ \reimp
+*/
+qreal QFxGridView::minXExtent() const
+{
+ Q_D(const QFxGridView);
+ if (d->flow == QFxGridView::LeftToRight)
+ return QFxFlickable::minXExtent();
+ return -d->startPosition();
+}
+
+/*!
+ \reimp
+*/
+qreal QFxGridView::maxXExtent() const
+{
+ Q_D(const QFxGridView);
+ if (d->flow == QFxGridView::LeftToRight)
+ return QFxFlickable::maxXExtent();
+ return -(d->endPosition() - height());
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QFxGridView);
+ if (d->model && d->model->count() && !d->locked) {
+ if ((d->flow == QFxGridView::LeftToRight && event->key() == Qt::Key_Up)
+ || (d->flow == QFxGridView::TopToBottom && event->key() == Qt::Key_Left)) {
+ if (currentIndex() >= d->columns || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxGridViewPrivate::Key;
+ int index = currentIndex() - d->columns;
+ setCurrentIndex(index >= 0 ? index : d->model->count()-1);
+ event->accept();
+ }
+ return;
+ } else if ((d->flow == QFxGridView::LeftToRight && event->key() == Qt::Key_Down)
+ || (d->flow == QFxGridView::TopToBottom && event->key() == Qt::Key_Right)) {
+ if (currentIndex() < d->model->count() - d->columns || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxGridViewPrivate::Key;
+ int index = currentIndex()+d->columns;
+ setCurrentIndex(index < d->model->count() ? index : 0);
+ event->accept();
+ }
+ return;
+ } else if ((d->flow == QFxGridView::LeftToRight && event->key() == Qt::Key_Left)
+ || (d->flow == QFxGridView::TopToBottom && event->key() == Qt::Key_Up)) {
+ if (currentIndex() > 0 || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxGridViewPrivate::Key;
+ int index = currentIndex() - 1;
+ setCurrentIndex(index >= 0 ? index : d->model->count()-1);
+ event->accept();
+ }
+ return;
+ } else if ((d->flow == QFxGridView::LeftToRight && event->key() == Qt::Key_Right)
+ || (d->flow == QFxGridView::TopToBottom && event->key() == Qt::Key_Down)) {
+ if (currentIndex() < d->model->count() - 1 || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxGridViewPrivate::Key;
+ int index = currentIndex() + 1;
+ setCurrentIndex(index < d->model->count() ? index : 0);
+ event->accept();
+ }
+ return;
+ }
+ }
+ d->moveReason = QFxGridViewPrivate::Other;
+ QFxFlickable::keyPressEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QFxGridView);
+ d->keyPressed = false;
+ QFxFlickable::keyReleaseEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QFxGridView::componentComplete()
+{
+ Q_D(QFxGridView);
+ QFxFlickable::componentComplete();
+ d->updateGrid();
+ if (d->currentIndex < 0)
+ d->updateCurrent(0);
+ refill();
+}
+
+void QFxGridView::trackedPositionChanged()
+{
+ Q_D(QFxGridView);
+ if (!d->trackedItem)
+ return;
+ if (!isFlicking() && !d->pressed && d->moveReason == QFxGridViewPrivate::Key) {
+ if (d->trackedItem->rowPos() < d->position()) {
+ d->setPosition(d->trackedItem->rowPos());
+ } else if (d->trackedItem->endRowPos() > d->position() + d->size()) {
+ qreal pos = d->trackedItem->endRowPos() - d->size();
+ if (d->rowSize() > d->size())
+ pos = d->trackedItem->rowPos();
+ d->setPosition(pos);
+ }
+ }
+}
+
+void QFxGridView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QFxGridView);
+ if (!d->visibleItems.count() || d->model->count() <= 1) {
+ refill();
+ d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1)));
+ emit countChanged();
+ return;
+ }
+
+ int index = d->mapFromModel(modelIndex);
+ if (index == -1) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (d->visibleItems.at(i)->index + 1 == modelIndex) {
+ // Special case of appending an item to the model.
+ index = d->visibleIndex + d->visibleItems.count();
+ } else {
+ if (modelIndex + count - 1 < d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItem *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem != d->currentItem)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ }
+ d->layout();
+ emit countChanged();
+ return;
+ }
+ }
+
+ // At least some of the added items will be visible
+ int insertCount = count;
+ if (index < d->visibleIndex) {
+ insertCount -= d->visibleIndex - index;
+ index = d->visibleIndex;
+ modelIndex = d->visibleIndex;
+ }
+
+ index -= d->visibleIndex;
+ int to = d->buffer+d->position()+d->size()-1;
+ int colPos, rowPos;
+ if (index < d->visibleItems.count()) {
+ colPos = d->visibleItems.at(index)->colPos();
+ rowPos = d->visibleItems.at(index)->rowPos();
+ } else {
+ // appending items to visible list
+ colPos = d->visibleItems.at(index-1)->colPos() + d->colSize();
+ rowPos = d->visibleItems.at(index-1)->rowPos();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ }
+
+ QList<FxGridItem*> added;
+ int i = 0;
+ for (; i < insertCount && rowPos + d->rowSize() - 1 <= to; ++i) {
+ int mod = (modelIndex+i) % d->columns;
+ while (mod++ < d->columns && modelIndex + i < d->model->count() && i < insertCount) {
+ FxGridItem *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(colPos, rowPos);
+ added.append(item);
+ colPos += d->colSize();
+ if (colPos > d->colSize() * (d->columns-1)) {
+ colPos = 0;
+ rowPos += d->rowSize();
+ }
+ ++index;
+ ++i;
+ }
+ }
+
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex));
+ }
+ }
+ if (i < insertCount) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index)
+ d->releaseItem(d->visibleItems.takeLast());
+ } else {
+ // Update the indexes of the following visible items.
+ for (; index < d->visibleItems.count(); ++index) {
+ FxGridItem *listItem = d->visibleItems.at(index);
+ if (listItem != d->currentItem) {
+ if (listItem->index != -1)
+ listItem->index += count;
+ }
+ }
+ }
+ // everything is in order now - emit add() signal
+ foreach(FxGridItem *item, added)
+ item->attached->emitAdd();
+ d->layout();
+ emit countChanged();
+}
+
+void QFxGridView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QFxGridView);
+
+ int index = d->mapFromModel(modelIndex);
+ if (index == -1) {
+ if (modelIndex + count - 1 < d->visibleIndex) {
+ // Items removed before our visible items.
+ d->visibleIndex -= count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxGridItem *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem != d->currentItem)
+ listItem->index -= count;
+ }
+ }
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem) {
+ FxGridItem *item = d->currentItem;
+ d->currentItem = 0;
+ d->releaseItem(item);
+ }
+ d->currentIndex = -1;
+ d->updateCurrent(qMin(modelIndex, d->model->count()-1));
+ }
+ d->layout(true);
+ emit countChanged();
+ return;
+ }
+
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxGridItem *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ if (item != d->currentItem)
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem && !d->currentItem->attached->delayRemove()) {
+ FxGridItem *item = d->currentItem;
+ d->currentItem = 0;
+ d->releaseItem(item);
+ }
+ d->currentItem = 0;
+ d->currentIndex = -1;
+ d->updateCurrent(qMin(modelIndex, d->model->count()-1));
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (d->visibleItems.isEmpty()) {
+ d->visibleIndex = 0;
+ d->setPosition(0);
+ refill();
+ } else {
+ // Correct the positioning of the items
+ d->layout();
+ }
+ emit countChanged();
+}
+
+void QFxGridView::destroyRemoved()
+{
+ Q_D(QFxGridView);
+ for (QList<FxGridItem*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxGridItem *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->layout();
+}
+
+void QFxGridView::refill()
+{
+ Q_D(QFxGridView);
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+
+QObject *QFxGridView::qmlAttachedProperties(QObject *obj)
+{
+ return QFxGridViewAttached::properties(obj);
+}
+
+QML_DEFINE_TYPE(QFxGridView,GridView);
+
+QT_END_NAMESPACE
+
+#include "qfxgridview.moc"
diff --git a/src/declarative/fx/qfxgridview.h b/src/declarative/fx/qfxgridview.h
new file mode 100644
index 0000000..c612804
--- /dev/null
+++ b/src/declarative/fx/qfxgridview.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXGRIDVIEW_H
+#define QFXGRIDVIEW_H
+
+#include <qfxflickable.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxVisualItemModel;
+class QFxGridViewPrivate;
+class Q_DECLARATIVE_EXPORT QFxGridView : public QFxFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QFxGridView);
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel);
+ Q_CLASSINFO("DefaultProperty", "delegate");
+ Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate);
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged);
+ Q_PROPERTY(QFxItem *current READ currentItem NOTIFY currentIndexChanged);
+ Q_PROPERTY(int count READ count NOTIFY countChanged);
+ Q_PROPERTY(QmlComponent *highlight READ highlight WRITE setHighlight);
+ Q_PROPERTY(bool autoHighlight READ autoHighlight WRITE setAutoHighlight);
+ Q_PROPERTY(Flow flow READ flow WRITE setFlow);
+ Q_PROPERTY(bool wrap READ isWrapEnabled WRITE setWrapEnabled);
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer);
+ Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellSizeChanged);
+ Q_PROPERTY(int cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellSizeChanged);
+
+public:
+ QFxGridView(QFxItem *parent=0);
+ ~QFxGridView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QmlComponent *delegate() const;
+ void setDelegate(QmlComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QFxItem *currentItem();
+ int count() const;
+
+ QmlComponent *highlight() const;
+ void setHighlight(QmlComponent *highlight);
+
+ bool autoHighlight() const;
+ void setAutoHighlight(bool);
+
+ Q_ENUMS(Flow);
+ enum Flow { LeftToRight, TopToBottom };
+ Flow flow() const;
+ void setFlow(Flow);
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ int cellWidth() const;
+ void setCellWidth(int);
+
+ int cellHeight() const;
+ void setCellHeight(int);
+
+ virtual void setHeight(int height);
+ virtual void setWidth(int width);
+
+ static QObject *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void countChanged();
+ void currentIndexChanged();
+ void cellSizeChanged();
+
+protected:
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void trackedPositionChanged();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void destroyRemoved();
+
+private:
+ void refill();
+};
+
+QML_DECLARE_TYPE(QFxGridView);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/fx/qfxhighlightfilter.cpp b/src/declarative/fx/qfxhighlightfilter.cpp
new file mode 100644
index 0000000..6c6277a
--- /dev/null
+++ b/src/declarative/fx/qfxhighlightfilter.cpp
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxhighlightfilter.h"
+#include <qfxpixmap.h>
+#include <qmlcontext.h>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <gltexture.h>
+#include <glbasicshaders.h>
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glsave.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFxHighlightFilterPrivate
+{
+public:
+ QFxHighlightFilterPrivate()
+ : ctxt(QmlContext::activeContext()),
+ xOffset(0), yOffset(0), tiled(false) {}
+
+ QmlContext *ctxt;
+ QString source;
+ QUrl url;
+ int xOffset;
+ int yOffset;
+ bool tiled;
+#if defined(QFX_RENDER_OPENGL2)
+ GLTexture tex;
+#endif
+};
+
+/*!
+ \qmlclass Highlight
+ \brief The Highlight filter adds a highlight to an item.
+ \inherits Filter
+
+ \code
+<Text id="highlighttext" color="red" font.size="32" text="Highlight">
+ <filter>
+ <Highlight src="pics/highlight.png">
+ <xOffset>
+ <NumericAnimation running="true" repeat="true"
+ from="320" to="-320" duration="2000"/>
+ </xOffset>
+ </Highlight>
+ </filter>
+</Text>
+ \endcode
+ \image highlight.gif
+
+ Highlighting is only supported when Qt Declarative is compiled for OpenGL ES 2.0.
+ Otherwise the Highlight filter has no effect.
+*/
+
+/*!
+ \internal
+ \class QFxHighlightFilter
+ \ingroup effects
+ \brief The QFxHightlightFilter class allows you to add a highlight to an item.
+*/
+
+QFxHighlightFilter::QFxHighlightFilter(QObject *parent)
+: QSimpleCanvasFilter(parent), d(new QFxHighlightFilterPrivate)
+{
+#if defined(QFX_RENDER_OPENGL2)
+ d->tex.setHorizontalWrap(GLTexture::ClampToEdge);
+ d->tex.setVerticalWrap(GLTexture::ClampToEdge);
+#endif
+}
+
+QFxHighlightFilter::~QFxHighlightFilter()
+{
+ delete d;
+ d = 0;
+}
+
+/*!
+ \qmlproperty string Highlight::src
+ This property holds the URL of the image to be used as the highlight.
+*/
+
+/*!
+ \property QFxHighlightFilter::src
+ \brief the URL of the image to be used as the highlight.
+*/
+QString QFxHighlightFilter::source() const
+{
+ return d->source;
+}
+
+void QFxHighlightFilter::imageLoaded()
+{
+ QImage img = QFxPixmap(d->url);
+#if defined(QFX_RENDER_OPENGL2)
+ if(!img.isNull())
+ d->tex.setImage(img);
+#endif
+ emit sourceChanged(d->source);
+ update();
+}
+
+void QFxHighlightFilter::setSource(const QString &f)
+{
+ if (d->source == f)
+ return;
+ if(!d->source.isEmpty())
+ QFxPixmap::cancelGet(d->url, this, SLOT(imageLoaded()));
+ d->source = f;
+ d->url = QmlContext::activeContext()->resolvedUrl(f);
+#if defined(QFX_RENDER_OPENGL2)
+ d->tex.clear();
+#endif
+ if(!f.isEmpty())
+ QFxPixmap::get(d->ctxt->engine(), d->url, this, SLOT(imageLoaded()));
+ else
+ emit sourceChanged(d->source);
+}
+
+/*!
+ \qmlproperty bool Highlight::tiled
+ This property holds whether or not the highlight should be tiled.
+*/
+
+/*!
+ \property QFxHighlightFilter::tiled
+ \brief whether or not the highlight should be tiled.
+*/
+bool QFxHighlightFilter::tiled() const
+{
+ return d->tiled;
+}
+
+void QFxHighlightFilter::setTiled(bool t)
+{
+ if(t == d->tiled)
+ return;
+
+ d->tiled = t;
+
+#if defined(QFX_RENDER_OPENGL2)
+ if(d->tiled) {
+ d->tex.setHorizontalWrap(GLTexture::ClampToEdge);
+ d->tex.setVerticalWrap(GLTexture::ClampToEdge);
+ } else {
+ d->tex.setHorizontalWrap(GLTexture::Repeat);
+ d->tex.setVerticalWrap(GLTexture::Repeat);
+ }
+#endif
+
+ emit tiledChanged(d->tiled);
+}
+
+/*!
+ \qmlproperty int Highlight::xOffset
+ \qmlproperty int Highlight::yOffset
+ These properties hold the position of the highlight, relative to the item.
+*/
+
+/*!
+ \property QFxHighlightFilter::xOffset
+ \brief the x position of the highlight, relative to the item.
+*/
+int QFxHighlightFilter::xOffset() const
+{
+ return d->xOffset;
+}
+
+void QFxHighlightFilter::setXOffset(int x)
+{
+ if(x == d->xOffset)
+ return;
+
+ d->xOffset = x;
+ emit offsetChanged(d->xOffset, d->yOffset);
+#if defined(QFX_RENDER_OPENGL2)
+ update();
+#endif
+}
+
+/*!
+ \property QFxHighlightFilter::yOffset
+ \brief the y position of the highlight, relative to the item.
+*/
+int QFxHighlightFilter::yOffset() const
+{
+ return d->yOffset;
+}
+
+void QFxHighlightFilter::setYOffset(int y)
+{
+ if(y == d->yOffset)
+ return;
+
+ d->yOffset = y;
+ emit offsetChanged(d->xOffset, d->yOffset);
+#if defined(QFX_RENDER_OPENGL2)
+ update();
+#endif
+}
+
+void QFxHighlightFilter::filterGL(QSimpleCanvasItem::GLPainter &p)
+{
+#if defined(QFX_RENDER_OPENGL2)
+ if(d->tex.isNull()) {
+ renderToScreen();
+ } else {
+ QSimpleCanvasItem *item = this->item();
+
+ QRect r = item->itemBoundingRect();
+
+ QGLFramebufferObject *fbo = renderToFBO();
+
+ float width = r.width();
+ float height = r.height();
+
+ float texWidth = width / float(fbo->width());
+ float texHeight = height / float(fbo->height());
+
+ GLfloat vert[] = { 0, height,
+ width, height,
+ 0, 0,
+ width, 0 };
+ GLfloat texVert[] = { 0, 0,
+ texWidth, 0,
+ 0, texHeight,
+ texWidth, texHeight };
+ float texXOffset = 0;
+ float texYOffset = 0;
+
+ if(xOffset())
+ texXOffset = float(xOffset()) / float(d->tex.width());
+ if(yOffset())
+ texYOffset = float(yOffset()) / float(d->tex.height());
+
+ GLfloat addTexVert[] = { texXOffset, texYOffset,
+ 1 + texXOffset, texYOffset,
+ texXOffset, 1 + texYOffset,
+ 1 + texXOffset, 1 + texYOffset };
+
+ glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, d->tex.texture());
+
+ DualTextureAddShader *shader = item->basicShaders()->dualTextureAdd();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+ shader->setOpacity(p.activeOpacity);
+
+ shader->setAttributeArray(DualTextureAddShader::Vertices, vert, 2);
+ shader->setAttributeArray(DualTextureAddShader::TextureCoords, texVert, 2);
+ shader->setAttributeArray(DualTextureAddShader::AddTextureCoords, addTexVert, 2);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(DualTextureAddShader::Vertices);
+ shader->disableAttributeArray(DualTextureAddShader::TextureCoords);
+ shader->disableAttributeArray(DualTextureAddShader::AddTextureCoords);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ releaseFBO(fbo);
+ }
+#else
+ Q_UNUSED(p);
+#endif
+}
+
+QML_DEFINE_TYPE(QFxHighlightFilter,Highlight);
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxhighlightfilter.h b/src/declarative/fx/qfxhighlightfilter.h
new file mode 100644
index 0000000..6204242
--- /dev/null
+++ b/src/declarative/fx/qfxhighlightfilter.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXHIGHLIGHTFILTER_H
+#define QFXHIGHLIGHTFILTER_H
+
+#include <qsimplecanvasfilter.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxHighlightFilterPrivate;
+class Q_DECLARATIVE_EXPORT QFxHighlightFilter : public QSimpleCanvasFilter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString src READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(bool tiled READ tiled WRITE setTiled NOTIFY tiledChanged)
+ Q_PROPERTY(int xOffset READ xOffset WRITE setXOffset NOTIFY offsetChanged)
+ Q_PROPERTY(int yOffset READ yOffset WRITE setYOffset NOTIFY offsetChanged)
+public:
+ QFxHighlightFilter(QObject *parent=0);
+ virtual ~QFxHighlightFilter();
+
+ QString source() const;
+ void setSource(const QString &);
+
+ bool tiled() const;
+ void setTiled(bool);
+
+ int xOffset() const;
+ void setXOffset(int);
+ int yOffset() const;
+ void setYOffset(int);
+
+Q_SIGNALS:
+ void sourceChanged(const QString &);
+ void offsetChanged(int x, int y);
+ void tiledChanged(bool);
+
+private Q_SLOTS:
+ void imageLoaded();
+
+protected:
+ virtual void filterGL(QSimpleCanvasItem::GLPainter &p);
+
+private:
+ QFxHighlightFilterPrivate *d;
+};
+QML_DECLARE_TYPE(QFxHighlightFilter);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXHIGHLIGHTFILTER_H
diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp
new file mode 100644
index 0000000..a137bc3
--- /dev/null
+++ b/src/declarative/fx/qfximage.cpp
@@ -0,0 +1,935 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfximage.h"
+#include "qfximage_p.h"
+#include <qfxperf.h>
+#if defined(QFX_RENDER_OPENGL)
+#include <glsave.h>
+#endif
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QFile>
+#include <QtDeclarative/qmlengine.h>
+
+QT_BEGIN_NAMESPACE
+
+
+QML_DEFINE_TYPE(QFxImage,Image);
+
+/*!
+ \qmlclass Image QFxImage
+ \brief The Image element allows you to add bitmaps to a scene.
+ \inherits Item
+
+ The Image element supports untransformed, stretched, grid-scaled and tiled images. For an explanation of grid-scaling see the scaleGrid property description or the QFxScaleGrid class description.
+
+ Examples:
+ \table
+ \row
+ \o \image declarative-qtlogo1.png
+ \o Untransformed
+ \code
+ <Image src="pics/qtlogo.png"/>
+ \endcode
+ \row
+ \o \image declarative-qtlogo2.png
+ \o Stretched
+ \code
+ <Image width="160" height="160" src="pics/qtlogo.png"/>
+ \endcode
+ \row
+ \o \image declarative-qtlogo4.png
+ \o Grid-scaled
+ \code
+ <Image scaleGrid.left="20" scaleGrid.right="10"
+ scaleGrid.top="14" scaleGrid.bottom="14"
+ width="160" height="160" src="pics/qtlogo.png"/>
+ \endcode
+ \row
+ \o \image declarative-qtlogo3.png
+ \o Tiled
+ \code
+ <Image tile="true"
+ width="160" height="160" src="pics/qtlogo.png"/>
+ \endcode
+ \endtable
+ */
+
+/*!
+ \internal
+ \class QFxImage Image
+ \brief The QFxImage class provides an image item that you can add to a QFxView.
+
+ \ingroup coreitems
+
+ Example:
+ \code
+ <Image src="pics/star.png"/>
+ \endcode
+
+ A QFxImage object can be instantiated in Qml using the tag \l Image.
+*/
+
+QFxImage::QFxImage(QFxItem *parent)
+ : QFxItem(*(new QFxImagePrivate), parent)
+{
+ setOptions(SimpleItem | HasContents, true);
+}
+
+QFxImage::QFxImage(QFxImagePrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ setOptions(SimpleItem | HasContents, true);
+}
+
+QFxImage::~QFxImage()
+{
+ Q_D(const QFxImage);
+ if(d->reply)
+ d->reply->deleteLater();
+}
+
+/*!
+ \property QFxImage::pixmap
+ \brief the image displayed in this item.
+
+ This property contains the image currently being displayed by this item,
+ which may be an empty pixmap if nothing is currently displayed. If this
+ property is set, the src property will be unset. This property is intended
+ to be used only in C++, not in XML.
+*/
+QPixmap QFxImage::pixmap() const
+{
+ Q_D(const QFxImage);
+ return d->_pix.pixmap();
+}
+
+void QFxImage::setPixmap(const QPixmap &pix)
+{
+ Q_D(QFxImage);
+ d->url = QUrl();
+ d->_pix.setPixmap(pix);
+ d->_opaque=false;
+ d->_pix.setOpaque(false);
+
+ setImplicitWidth(d->_pix.width());
+ setImplicitHeight(d->_pix.height());
+
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ update();
+}
+
+/*!
+ \qmlproperty int Image::scaleGrid.left
+ \qmlproperty int Image::scaleGrid.right
+ \qmlproperty int Image::scaleGrid.top
+ \qmlproperty int Image::scaleGrid.bottom
+
+ \target ImagexmlpropertiesscaleGrid
+
+ A scale grid uses 4 grid lines (2 horizontal and 2 vertical) to break an image into 9 sections, as shown below:
+
+ \image declarative-scalegrid.png
+
+ When the image is scaled:
+ \list
+ \i the corners (sections 1, 3, 7, and 9) are not scaled at all
+ \i the middle (section 5) is scaled both horizontally and vertically
+ \i sections 2 and 8 are scaled horizontally
+ \i sections 4 and 6 are scaled vertically
+ \endlist
+
+ Each scale grid property (left, right, top, and bottom) specifies an offset from the respective side. For example, \c scaleGrid.bottom="10" sets the bottom scale grid line 10 pixels up from the bottom of the image.
+
+ A scale grid can also be specified using a \l {Imagexmlpropertysrc}{.sci file}.
+*/
+QFxScaleGrid *QFxImage::scaleGrid()
+{
+ Q_D(QFxImage);
+ return d->scaleGrid();
+}
+
+/*!
+ \qmlproperty bool Image::tile
+
+ Set this property to enable image tiling. Normally the Image element scales the
+ bitmap file to its size. If tiling is enabled, the bitmap is repeated as a set
+ of unscaled tiles, clipped to the size of the Image.
+
+ \code
+ <Item>
+ <Image src="tile.png" />
+ <Image x="80" width="100" height="100" src="tile.png" />
+ <Image x="190" width="100" height="100" tile="true" src="tile.png" />
+ </Item>
+ \endcode
+ \image declarative-image_tile.png
+
+ If both tiling and the scaleGrid are set, tiling takes precedence.
+*/
+bool QFxImage::isTiled() const
+{
+ Q_D(const QFxImage);
+ return d->_tiled;
+}
+
+void QFxImage::setTiled(bool tile)
+{
+ Q_D(QFxImage);
+ d->_tiled = tile;
+}
+
+/*!
+ \qmlproperty bool Image::opaque
+
+ Set this property if you know that the image is opaque to give your
+ application a significant performance boost.
+
+ \note
+ This is a performance hint to Qt Declarative. Unfortunately whether or not an image
+ is opaque is not automatically detected. Setting this property to true when
+ the image is not opaque will lead to drawing artifacts. However, leaving it as
+ false will always work correctly - although possibly not at maximum performance.
+ */
+
+/*!
+ \property QFxImage::opaque
+ \brief whether the image is opaque (non-transparent).
+
+ This property is provided purely for the purpose of optimization. An opaque
+ image can be optimized more than a non-opaque one.
+*/
+bool QFxImage::isOpaque() const
+{
+ Q_D(const QFxImage);
+ return d->_opaque;
+}
+
+void QFxImage::setOpaque(bool o)
+{
+ Q_D(QFxImage);
+ if(o == d->_opaque)
+ return;
+ d->_opaque = o;
+ d->_pix.setOpaque(o);
+ update();
+}
+
+void QFxImage::componentComplete()
+{
+ QFxItem::componentComplete();
+}
+
+/*!
+ \property QFxImage::scaleGrid
+ \brief the 3x3 grid used to scale an image, excluding the corners.
+*/
+
+/*!
+ \qmlproperty bool Image::smooth
+
+ Set this property if you want the image to be smoothly filtered when scaled or
+ transformed. Smooth filtering gives better visual quality, but is slower. If
+ the Image is displayed at its natural size, this property has no visual or
+ performance effect.
+
+ \note Generally scaling artifacts are only visible if the image is stationary on
+ the screen. A common pattern when animating an image is to disable smooth
+ filtering at the beginning of the animation and reenable it at the conclusion.
+ */
+
+/*!
+ \property QFxImage::smooth
+ \brief whether the image is smoothly transformed.
+
+ This property is provided purely for the purpose of optimization. Turning
+ smooth transforms off is faster, but looks worse; turning smooth
+ transformations on is slower, but looks better.
+
+ By default smooth transformations are off.
+*/
+bool QFxImage::smoothTransform() const
+{
+ Q_D(const QFxImage);
+ return d->_smooth;
+}
+
+void QFxImage::setSmoothTransform(bool s)
+{
+ Q_D(QFxImage);
+ if(d->_smooth == s)
+ return;
+ d->_smooth = s;
+ update();
+}
+
+void QFxImage::dump(int depth)
+{
+ Q_D(QFxImage);
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << "URL:" << d->url;
+ QFxItem::dump(depth);
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxImage::paintContents(QPainter &p)
+{
+ Q_D(QFxImage);
+ if(d->_pix.isNull())
+ return;
+
+ if(d->_smooth) {
+ p.save();
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->_smooth);
+ }
+
+ QSimpleCanvasConfig::Image pix = d->_pix;
+
+ if (d->_tiled) {
+ p.save();
+ p.setClipRect(0, 0, width(), height(), Qt::IntersectClip);
+ QRect me = QRect(0, 0, width(), height());
+
+ int pw = d->_pix.width();
+ int ph = d->_pix.height();
+ int yy = 0;
+
+ while(yy < height()) {
+ int xx = 0;
+ while(xx < width()) {
+ p.drawImage(xx, yy, d->_pix);
+ xx += pw;
+ }
+ yy += ph;
+ }
+
+ p.restore();
+ } else if (!d->_scaleGrid || d->_scaleGrid->isNull()) {
+ if(width() != pix.width() || height() != pix.height()) {
+ QTransform scale;
+ scale.scale(width() / qreal(pix.width()),
+ height() / qreal(pix.height()));
+ QTransform old = p.transform();
+ p.setWorldTransform(scale * old);
+ p.drawImage(0, 0, pix);
+ p.setWorldTransform(old);
+ } else {
+ p.drawImage(0, 0, pix);
+ }
+ } else {
+ const int sgl = d->_scaleGrid->left();
+ const int sgr = d->_scaleGrid->right();
+ const int sgt = d->_scaleGrid->top();
+ const int sgb = d->_scaleGrid->bottom();
+ const int xSide = sgl + sgr;
+ const int ySide = sgt + sgb;
+
+ // Upper left
+ if(sgt && sgl)
+ p.drawImage(QRect(0, 0, sgl, sgt), pix, QRect(0, 0, sgl, sgt));
+ // Upper middle
+ if(pix.width() - xSide && sgt)
+ p.drawImage(QRect(sgl, 0, width() - xSide, sgt), pix,
+ QRect(sgl, 0, pix.width() - xSide, sgt));
+ // Upper right
+ if(sgt && pix.width() - sgr)
+ p.drawImage(QPoint(width()-sgr, 0), pix,
+ QRect(pix.width()-sgr, 0, sgr, sgt));
+ // Middle left
+ if(sgl && pix.height() - ySide)
+ p.drawImage(QRect(0, sgt, sgl, height() - ySide), pix,
+ QRect(0, sgt, sgl, pix.height() - ySide));
+
+ // Middle
+ if(pix.width() - xSide && pix.height() - ySide)
+ p.drawImage(QRect(sgl, sgt, width() - xSide, height() - ySide),
+ pix,
+ QRect(sgl, sgt, pix.width() - xSide, pix.height() - ySide));
+ // Middle right
+ if(sgr && pix.height() - ySide)
+ p.drawImage(QRect(width()-sgr, sgt, sgr, height() - ySide), pix,
+ QRect(pix.width()-sgr, sgt, sgr, pix.height() - ySide));
+ // Lower left
+ if(sgl && sgr)
+ p.drawImage(QPoint(0, height() - sgb), pix,
+ QRect(0, pix.height() - sgb, sgl, sgb));
+ // Lower Middle
+ if(pix.width() - xSide && sgb)
+ p.drawImage(QRect(sgl, height() - sgb, width() - xSide, sgb), pix,
+ QRect(sgl, pix.height() - sgb, pix.width() - xSide, sgb));
+ // Lower Right
+ if(sgr && sgb)
+ p.drawImage(QPoint(width()-sgr, height() - sgb), pix,
+ QRect(pix.width()-sgr, pix.height() - sgb, sgr, sgb));
+ }
+
+ if(d->_smooth) {
+ p.restore();
+ }
+}
+#elif defined(QFX_RENDER_OPENGL)
+uint QFxImage::glSimpleItemData(float *vertices, float *texVertices,
+ GLTexture **texture, uint count)
+{
+ Q_D(QFxImage);
+
+ if(d->_pix.isNull() || (d->_scaleGrid && !d->_scaleGrid->isNull()))
+ return 0;
+
+ if(count < 8)
+ return 8;
+
+ d->checkDirty();
+
+ float widthV = width();
+ float heightV = height();
+
+ vertices[0] = 0; vertices[1] = heightV;
+ vertices[2] = widthV; vertices[3] = heightV;
+ vertices[4] = 0; vertices[5] = 0;
+ vertices[6] = widthV; vertices[7] = 0;
+
+ *texture = &d->_tex;
+
+ if(d->_tiled) {
+ float tileWidth = widthV / d->_pix.width();
+ float tileHeight = heightV / d->_pix.height();
+ texVertices[0] = 0; texVertices[1] = 0;
+ texVertices[2] = tileWidth; texVertices[3] = 0;
+ texVertices[4] = 0; texVertices[5] = tileHeight;
+ texVertices[6] = tileWidth; texVertices[7] = tileHeight;
+ } else {
+ texVertices[0] = 0; texVertices[1] = 0;
+ texVertices[2] = 1; texVertices[3] = 0;
+ texVertices[4] = 0; texVertices[5] = 1;
+ texVertices[6] = 1; texVertices[7] = 1;
+ }
+
+ return 8;
+}
+
+void QFxImagePrivate::checkDirty()
+{
+ if(_texDirty && !_pix.isNull()) {
+ _tex.setImage(_pix);
+ _tex.setHorizontalWrap(GLTexture::Repeat);
+ _tex.setVerticalWrap(GLTexture::Repeat);
+ }
+ _texDirty = false;
+}
+
+#if defined(QFX_RENDER_OPENGL2)
+void QFxImage::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxImage);
+ if(d->_pix.isNull())
+ return;
+
+ QGLShaderProgram *shader = p.useTextureShader();
+
+ bool restoreBlend = false;
+ if(isOpaque() && p.activeOpacity == 1) {
+ glDisable(GL_BLEND);
+ restoreBlend = true;
+ }
+
+ if(d->_tiled || (!d->_scaleGrid || d->_scaleGrid->isNull())) {
+
+ GLfloat vertices[8];
+ GLfloat texVertices[8];
+ GLTexture *tex = 0;
+
+ QFxImage::glSimpleItemData(vertices, texVertices, &tex, 8);
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2);
+
+ glBindTexture(GL_TEXTURE_2D, tex->texture());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+
+ } else {
+ d->checkDirty();
+
+ float imgWidth = d->_pix.width();
+ float imgHeight = d->_pix.height();
+ if(!imgWidth || !imgHeight) {
+ if (restoreBlend)
+ glEnable(GL_BLEND);
+ return;
+ }
+
+ float widthV = width();
+ float heightV = height();
+
+ float texleft = 0;
+ float texright = 1;
+ float textop = 1;
+ float texbottom = 0;
+ float imgleft = 0;
+ float imgright = widthV;
+ float imgtop = 0;
+ float imgbottom = heightV;
+
+ const int sgl = d->_scaleGrid->left();
+ const int sgr = d->_scaleGrid->right();
+ const int sgt = d->_scaleGrid->top();
+ const int sgb = d->_scaleGrid->bottom();
+
+ if(sgl) {
+ texleft = float(sgl) / imgWidth;
+ imgleft = sgl;
+ }
+ if(sgr) {
+ texright = 1. - float(sgr) / imgWidth;
+ imgright = widthV - sgr;
+ }
+ if(sgt) {
+ textop = 1. - float(sgb) / imgHeight;
+ imgtop = sgt;
+ }
+ if(sgb) {
+ texbottom = float(sgt) / imgHeight;
+ imgbottom = heightV - sgb;
+ }
+
+ float vert1[] = { 0, 0,
+ 0, imgtop,
+ imgleft, 0,
+ imgleft, imgtop,
+ imgright, 0,
+ imgright, imgtop,
+ widthV, 0,
+ widthV, imgtop };
+ float tex1[] = { 0, 1,
+ 0, textop,
+ texleft, 1,
+ texleft, textop,
+ texright, 1,
+ texright, textop,
+ 1, 1,
+ 1, textop };
+ float vert2[] = { 0, imgtop,
+ 0, imgbottom,
+ imgleft, imgtop,
+ imgleft, imgbottom,
+ imgright, imgtop,
+ imgright, imgbottom,
+ widthV, imgtop,
+ widthV, imgbottom };
+ float tex2[] = { 0, textop,
+ 0, texbottom,
+ texleft, textop,
+ texleft, texbottom,
+ texright, textop,
+ texright, texbottom,
+ 1, textop,
+ 1, texbottom };
+ float vert3[] = { 0, imgbottom,
+ 0, heightV,
+ imgleft, imgbottom,
+ imgleft, heightV,
+ imgright, imgbottom,
+ imgright, heightV,
+ widthV, imgbottom,
+ widthV, heightV };
+ float tex3[] = { 0, texbottom,
+ 0, 0,
+ texleft, texbottom,
+ texleft, 0,
+ texright, texbottom,
+ texright, 0,
+ 1, texbottom,
+ 1, 0 };
+
+ glBindTexture(GL_TEXTURE_2D, d->_tex.texture());
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert1, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex1, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert2, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex2, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert3, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex3, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+ }
+
+ if (restoreBlend)
+ glEnable(GL_BLEND);
+}
+#elif defined(QFX_RENDER_OPENGL1)
+void QFxImage::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxImage);
+ if(d->_pix.isNull())
+ return;
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(p.activeTransform.data());
+
+ bool restoreBlend = false;
+ if(isOpaque() && p.activeOpacity == 1) {
+ glDisable(GL_BLEND);
+ restoreBlend = true;
+ }
+
+ glEnable(GL_TEXTURE_2D);
+ if(p.activeOpacity == 1.) {
+ GLint i = GL_REPLACE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ } else {
+ GLint i = GL_MODULATE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ glColor4f(1, 1, 1, p.activeOpacity);
+ }
+
+ if(d->_tiled || !d->_scaleGrid || d->_scaleGrid->isNull()) {
+
+ GLfloat vertices[8];
+ GLfloat texVertices[8];
+ GLTexture *tex = 0;
+
+ QFxImage::glSimpleItemData(vertices, texVertices, &tex, 8);
+
+ glBindTexture(GL_TEXTURE_2D, tex->texture());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texVertices);
+
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+
+ } else {
+ d->checkDirty();
+
+ float imgWidth = d->_pix.width();
+ float imgHeight = d->_pix.height();
+ if(!imgWidth || !imgHeight) {
+ if (restoreBlend)
+ glEnable(GL_BLEND);
+ return;
+ }
+
+ float widthV = width();
+ float heightV = height();
+
+ float texleft = 0;
+ float texright = 1;
+ float textop = 1;
+ float texbottom = 0;
+ float imgleft = 0;
+ float imgright = widthV;
+ float imgtop = 0;
+ float imgbottom = heightV;
+
+ const int sgl = d->_scaleGrid->left();
+ const int sgr = d->_scaleGrid->right();
+ const int sgt = d->_scaleGrid->top();
+ const int sgb = d->_scaleGrid->bottom();
+
+ if(sgl) {
+ texleft = float(sgl) / imgWidth;
+ imgleft = sgl;
+ }
+ if(sgr) {
+ texright = 1. - float(sgr) / imgWidth;
+ imgright = widthV - sgr;
+ }
+ if(sgt) {
+ textop = 1. - float(sgb) / imgHeight;
+ imgtop = sgt;
+ }
+ if(sgb) {
+ texbottom = float(sgt) / imgHeight;
+ imgbottom = heightV - sgb;
+ }
+
+ float vert1[] = { 0, 0,
+ 0, imgtop,
+ imgleft, 0,
+ imgleft, imgtop,
+ imgright, 0,
+ imgright, imgtop,
+ widthV, 0,
+ widthV, imgtop };
+ float tex1[] = { 0, 1,
+ 0, textop,
+ texleft, 1,
+ texleft, textop,
+ texright, 1,
+ texright, textop,
+ 1, 1,
+ 1, textop };
+ float vert2[] = { 0, imgtop,
+ 0, imgbottom,
+ imgleft, imgtop,
+ imgleft, imgbottom,
+ imgright, imgtop,
+ imgright, imgbottom,
+ widthV, imgtop,
+ widthV, imgbottom };
+ float tex2[] = { 0, textop,
+ 0, texbottom,
+ texleft, textop,
+ texleft, texbottom,
+ texright, textop,
+ texright, texbottom,
+ 1, textop,
+ 1, texbottom };
+ float vert3[] = { 0, imgbottom,
+ 0, heightV,
+ imgleft, imgbottom,
+ imgleft, heightV,
+ imgright, imgbottom,
+ imgright, heightV,
+ widthV, imgbottom,
+ widthV, heightV };
+ float tex3[] = { 0, texbottom,
+ 0, 0,
+ texleft, texbottom,
+ texleft, 0,
+ texright, texbottom,
+ texright, 0,
+ 1, texbottom,
+ 1, 0 };
+
+ glBindTexture(GL_TEXTURE_2D, d->_tex.texture());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, 0, vert1);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex1);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ glVertexPointer(2, GL_FLOAT, 0, vert2);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ glVertexPointer(2, GL_FLOAT, 0, vert3);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex3);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if (restoreBlend)
+ glEnable(GL_BLEND);
+}
+#endif
+
+#endif
+
+QString QFxImage::propertyInfo() const
+{
+ Q_D(const QFxImage);
+ return d->url.toString();
+}
+
+QFxImage::Status QFxImage::status() const
+{
+ Q_D(const QFxImage);
+ return d->status;
+}
+
+/*!
+ \qmlproperty string Image::src
+
+ Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
+
+ \target Imagexmlpropertysrc
+
+ It can also handle .sci files, which are a Qml-specific format. A .sci file uses a simple text-based format that specifies
+ \list
+ \i the grid lines describing a \l {ImagexmlpropertiesscaleGrid}{scale grid}.
+ \i an image file.
+ \endlist
+
+ The following .sci file sets grid line offsets of 10 on each side for the image \c picture.png:
+ \code
+ gridLeft: 10
+ gridTop: 10
+ gridBottom: 10
+ gridRight: 10
+ imageFile: picture.png
+ \endcode
+
+ The URL may be absolute, or relative to the URL of the component.
+*/
+
+/*!
+ \property QFxImage::src
+ \brief the url of the image to be displayed in this item.
+
+ The content specified can be of any image type loadable by QImage. Alternatively,
+ you can specify an sci format file, which specifies both an image and it's scale grid.
+*/
+QString QFxImage::source() const
+{
+ Q_D(const QFxImage);
+ return d->source;
+}
+
+void QFxImage::setSource(const QString &url)
+{
+ Q_D(QFxImage);
+ if(url == d->source)
+ return;
+
+ if(d->reply) {
+ d->reply->deleteLater();
+ d->reply = 0;
+ }
+
+ if (!d->url.isEmpty())
+ QFxPixmap::cancelGet(d->url, this, SLOT(requestFinished()));
+ if (!d->sciurl.isEmpty())
+ QFxPixmap::cancelGet(d->sciurl, this, SLOT(requestFinished()));
+
+ d->source = url;
+ d->url = itemContext()->resolvedUrl(url);
+ d->sciurl = QUrl();
+
+ if(url.isEmpty()) {
+ setPixmap(QPixmap());
+ d->status = Idle;
+ } else {
+ d->status = Loading;
+ if (d->url.path().endsWith(QLatin1String(".sci"))) {
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ if (d->url.scheme() == QLatin1String("file")) {
+ QFile file(d->url.toLocalFile());
+ file.open(QIODevice::ReadOnly);
+ setGridScaledImage(QFxGridScaledImage(&file));
+ } else
+#endif
+ {
+ QNetworkRequest req(d->url);
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ d->reply = itemContext()->engine()->networkAccessManager()->get(req);
+ QObject::connect(d->reply, SIGNAL(finished()),
+ this, SLOT(sciRequestFinished()));
+ }
+ } else {
+ QFxPixmap::get(itemContext()->engine(), d->url, this, SLOT(requestFinished()));
+ }
+ }
+
+ emit statusChanged(d->status);
+}
+
+void QFxImage::requestFinished()
+{
+ Q_D(QFxImage);
+ if (d->url.path().endsWith(QLatin1String(".sci"))) {
+ d->_pix = QFxPixmap(d->sciurl);
+ } else {
+ d->_pix = QFxPixmap(d->url);
+ d->_pix.setOpaque(d->_opaque);
+ setOptions(QFxImage::SimpleItem, true);
+ }
+ setImplicitWidth(d->_pix.width());
+ setImplicitHeight(d->_pix.height());
+
+ d->status = Idle;
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ emit statusChanged(d->status);
+ emit sourceChanged(d->source);
+ update();
+}
+
+void QFxImage::sciRequestFinished()
+{
+ Q_D(QFxImage);
+ if(d->reply->error() != QNetworkReply::NoError) {
+ d->status = Error;
+ d->reply->deleteLater();
+ d->reply = 0;
+ emit statusChanged(d->status);
+ } else {
+ QFxGridScaledImage sci(d->reply);
+ d->reply->deleteLater();
+ d->reply = 0;
+ setGridScaledImage(sci);
+ }
+}
+
+
+void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci)
+{
+ Q_D(QFxImage);
+ if(!sci.isValid()) {
+ d->status = Error;
+ emit statusChanged(d->status);
+ } else {
+ d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl()));
+ QFxPixmap::get(itemContext()->engine(), d->sciurl, this, SLOT(requestFinished()));
+ QFxScaleGrid *sg = scaleGrid();
+ sg->setTop(sci.gridTop());
+ sg->setBottom(sci.gridBottom());
+ sg->setLeft(sci.gridLeft());
+ sg->setRight(sci.gridRight());
+ setOptions(QFxImage::SimpleItem, false);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h
new file mode 100644
index 0000000..4eed0ef
--- /dev/null
+++ b/src/declarative/fx/qfximage.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXIMAGE_H
+#define QFXIMAGE_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxImagePrivate;
+class Q_DECLARATIVE_EXPORT QFxImage : public QFxItem
+{
+ Q_OBJECT
+ Q_ENUMS(Status)
+
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged)
+ Q_PROPERTY(QString src READ source WRITE setSource NOTIFY sourceChanged)
+
+ Q_PROPERTY(QFxScaleGrid *scaleGrid READ scaleGrid)
+ Q_PROPERTY(bool tile READ isTiled WRITE setTiled)
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE false)
+ Q_PROPERTY(bool opaque READ isOpaque WRITE setOpaque)
+ Q_PROPERTY(bool smooth READ smoothTransform WRITE setSmoothTransform)
+public:
+ QFxImage(QFxItem *parent=0);
+ ~QFxImage();
+
+ QFxScaleGrid *scaleGrid();
+
+ bool isTiled() const;
+ void setTiled(bool tile);
+
+ QPixmap pixmap() const;
+ void setPixmap(const QPixmap &);
+
+ bool isOpaque() const;
+ void setOpaque(bool);
+
+ bool smoothTransform() const;
+ void setSmoothTransform(bool);
+
+ enum Status { Idle, Loading, Error };
+ Status status() const;
+
+ QString source() const;
+ virtual void setSource(const QString &url);
+
+ virtual void dump(int depth);
+ virtual QString propertyInfo() const;
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#elif defined(QFX_RENDER_OPENGL)
+ void paintGLContents(GLPainter &);
+ uint glSimpleItemData(float *vertices, float *texVertices,
+ GLTexture **texture, uint count);
+#endif
+
+Q_SIGNALS:
+ void sourceChanged(const QString &);
+ void statusChanged(Status);
+
+protected:
+ QFxImage(QFxImagePrivate &dd, QFxItem *parent);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void requestFinished();
+ void sciRequestFinished();
+
+private:
+ Q_DISABLE_COPY(QFxImage)
+ Q_DECLARE_PRIVATE(QFxImage)
+ void setGridScaledImage(const QFxGridScaledImage& sci);
+};
+QML_DECLARE_TYPE(QFxImage);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXIMAGE_H
diff --git a/src/declarative/fx/qfximage_p.h b/src/declarative/fx/qfximage_p.h
new file mode 100644
index 0000000..46aea49
--- /dev/null
+++ b/src/declarative/fx/qfximage_p.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXIMAGE_P_H
+#define QFXIMAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSvgRenderer;
+class QWebPage;
+class QNetworkReply;
+class QIODevice;
+
+class QFxImagePrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxImage)
+
+public:
+ QFxImagePrivate()
+ : _scaleGrid(0), _tiled(false), _smooth(false), _opaque(false),
+#if defined(QFX_RENDER_OPENGL)
+ _texDirty(true),
+#endif
+ status(QFxImage::Idle), reply(0)
+ {
+ }
+
+ ~QFxImagePrivate()
+ {
+ delete _scaleGrid;
+ }
+
+ void setContent(QIODevice* dev, const QString &url);
+
+ QFxScaleGrid *scaleGrid()
+ {
+ if(!_scaleGrid)
+ _scaleGrid = new QFxScaleGrid;
+ return _scaleGrid;
+ }
+
+ QFxScaleGrid *_scaleGrid;
+ bool _tiled;
+ QFxPixmap _pix;
+ bool _smooth;
+ bool _opaque;
+#if defined(QFX_RENDER_OPENGL)
+ void checkDirty();
+ bool _texDirty;
+ GLTexture _tex;
+#endif
+
+ QFxImage::Status status;
+ QString source;
+ QUrl url;
+ QUrl sciurl;
+ QNetworkReply *reply;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXIMAGE_P_H
diff --git a/src/declarative/fx/qfximageitem.cpp b/src/declarative/fx/qfximageitem.cpp
new file mode 100644
index 0000000..6c257fa
--- /dev/null
+++ b/src/declarative/fx/qfximageitem.cpp
@@ -0,0 +1,343 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfximageitem.h"
+#include "qfximageitem_p.h"
+
+#include <QDebug>
+#include <QPen>
+#include <QFile>
+#include <QEvent>
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glsave.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QFxImageItem
+ \brief The QFxImageItem class is an abstract base class for QFxView items that render using QPainter.
+ \ingroup coreitems
+
+ This is a convenience class allowing easy use of a QPainter within a custom
+ item. The contents of the item are are cached behind the scenes.
+ The dirtyCache() function should be called if the contents change to
+ ensure the cache is refreshed the next time painting occurs.
+
+ To subclass QFxImageItem, you must reimplement drawContents() to draw
+ the contents of the item.
+*/
+
+/*!
+ \fn void QFxImageItem::drawContents(QPainter *painter, const QRect &rect)
+
+ This function is called when the cache needs to be refreshed. When
+ sub-classing QFxImageItem this function should be implemented so as to
+ paint the contents of the item using the given \a painter for the
+ area of the contents specified by \a rect.
+*/
+
+/*!
+ \property QFxImageItem::contentsSize
+ \brief The size of the contents
+
+ The contents size is the size of the item in regards to how it is painted
+ using the drawContents() function. This is distinct from the size of the
+ item in regards to height() and width().
+*/
+
+/*!
+ \property QFxImageItem::smooth
+ \brief Setting for whether smooth scaling is enabled.
+*/
+
+/*!
+ Marks areas of the cache that intersect with the given \a rect as dirty and
+ in need of being refreshed.
+
+ \sa clearCache()
+*/
+void QFxImageItem::dirtyCache(const QRect& rect)
+{
+ Q_D(QFxImageItem);
+ for (int i=0; i < d->imagecache.count(); ) {
+ if (d->imagecache[i]->area.intersects(rect)) {
+ d->imagecache.removeAt(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+/*!
+ Marks the entirety of the contents cache as dirty.
+
+ \sa dirtyCache()
+*/
+void QFxImageItem::clearCache()
+{
+ Q_D(QFxImageItem);
+ foreach (QFxImageItemPrivate::ImageCacheItem* i, d->imagecache)
+ delete i;
+ d->imagecache.clear();
+}
+
+/*!
+ Returns if smooth scaling of the cache contents is enabled.
+
+ \sa setSmooth()
+*/
+bool QFxImageItem::isSmooth() const
+{
+ Q_D(const QFxImageItem);
+ return d->smooth;
+}
+
+/*!
+ Returns the size of the contents.
+
+ \sa setContentsSize()
+*/
+QSize QFxImageItem::contentsSize() const
+{
+ Q_D(const QFxImageItem);
+ return d->contentsSize;
+}
+
+/*!
+ If \a smooth is true sets the image item to enable smooth scaling of
+ the cache contents.
+
+ \sa isSmooth()
+*/
+void QFxImageItem::setSmooth(bool smooth)
+{
+ Q_D(QFxImageItem);
+ if(d->smooth == smooth) return;
+ d->smooth = smooth;
+ clearCache();
+ update();
+}
+
+/*!
+ Sets the size of the contents to the given \a size.
+
+ \sa contentsSize()
+*/
+void QFxImageItem::setContentsSize(const QSize &size)
+{
+ Q_D(QFxImageItem);
+ if(d->contentsSize == size) return;
+ d->contentsSize = size;
+ clearCache();
+ update();
+}
+
+/*!
+ Constructs a new QFxImageItem with the given \a parent.
+*/
+QFxImageItem::QFxImageItem(QFxItem *parent)
+ : QFxItem(*(new QFxImageItemPrivate), parent)
+{
+ init();
+}
+
+/*!
+ \internal
+ Constructs a new QFxImageItem with the given \a parent and
+ initialized private data member \a dd.
+*/
+QFxImageItem::QFxImageItem(QFxImageItemPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ init();
+}
+
+/*!
+ Destroys the image item.
+*/
+QFxImageItem::~QFxImageItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QFxImageItem::init()
+{
+ connect(this,SIGNAL(widthChanged()),this,SLOT(clearCache()));
+ connect(this,SIGNAL(heightChanged()),this,SLOT(clearCache()));
+ connect(this,SIGNAL(visibleChanged()),this,SLOT(clearCache()));
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+/*!
+ \reimp
+*/
+void QFxImageItem::paintContents(QPainter &p)
+#elif defined(QFX_RENDER_OPENGL)
+/*!
+ \reimp
+*/
+void QFxImageItem::paintGLContents(GLPainter &p)
+#else
+#error "What render?"
+#endif
+{
+ Q_D(QFxImageItem);
+ const QRect content(QPoint(0,0),d->contentsSize);
+ if (content.width() <= 0 || content.height() <= 0)
+ return;
+
+#if defined(QFX_RENDER_QPAINTER)
+ if(d->smooth) {
+ p.save();
+ p.setRenderHints(QPainter::Antialiasing, true);
+ p.setRenderHints(QPainter::SmoothPixmapTransform, true);
+ }
+ QRectF clipf = p.clipRegion().boundingRect();
+ if (clipf.isEmpty())
+ clipf = mapToScene(content); // ### Inefficient: Maps toScene and then fromScene
+ else
+ clipf = mapToScene(clipf);
+
+#elif defined(QFX_RENDER_OPENGL2)
+ p.useTextureShader();
+ const QRectF clipf = p.sceneClipRect;
+
+#elif defined(QFX_RENDER_OPENGL1)
+ p.useTextureShader();
+ const QRectF clipf = p.sceneClipRect;
+#endif
+
+ qreal hscale = widthValid() ? qreal(width()) / content.width() : heightValid() ? qreal(height()) / content.height() : 1.0;
+ qreal vscale = heightValid() ? qreal(height()) / content.height() : widthValid() ? qreal(width()) / content.width() : 1.0;
+ const QRect clip = mapFromScene(QRectF(clipf.x()/hscale,clipf.y()/vscale,clipf.width()/hscale,clipf.height()/vscale)).toRect();
+
+ QRegion topaint(clip);
+ topaint &= content;
+ QRegion uncached(content);
+
+#if defined(QFX_RENDER_OPENGL2)
+ glEnableVertexAttribArray(SingleTextureShader::Vertices);
+ glEnableVertexAttribArray(SingleTextureShader::TextureCoords);
+#elif defined(QFX_RENDER_OPENGL1)
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+#endif
+
+ int cachesize=0;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ QRect area = d->imagecache[i]->area;
+ if (topaint.contains(area)) {
+ QRectF target(area.x()*hscale, area.y()*vscale, area.width()*hscale, area.height()*vscale);
+ p.drawImage(target.toRect(), d->imagecache[i]->image);
+ topaint -= area;
+ d->imagecache[i]->age=0;
+ } else {
+ d->imagecache[i]->age++;
+ }
+ cachesize += area.width()*area.height();
+ uncached -= area;
+ }
+
+ if (!topaint.isEmpty()) {
+ // Find a sensible larger area, otherwise will paint lots of tiny images.
+ QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128);
+ cachesize += biggerrect.width() * biggerrect.height();
+ while (d->imagecache.count() && cachesize > d->max_imagecache_size) {
+ int oldest=-1;
+ int age=-1;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ int a = d->imagecache[i]->age;
+ if (a > age) {
+ oldest = i;
+ age = a;
+ }
+ }
+ cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height();
+ uncached += d->imagecache[oldest]->area;
+ d->imagecache.removeAt(oldest);
+ }
+ const QRegion bigger = QRegion(biggerrect) & uncached;
+ const QVector<QRect> rects = bigger.rects();
+ foreach (QRect r, rects) {
+#if defined(QFX_RENDER_QPAINTER)
+ QImage img(r.size(),QImage::Format_ARGB32_Premultiplied);
+#else
+ QImage img(r.size(),QImage::Format_ARGB32);
+#endif
+ img.fill(0);
+ {
+ QPainter qp(&img);
+ qp.translate(-r.x(),-r.y());
+ drawContents(&qp, r);
+ }
+ QFxImageItemPrivate::ImageCacheItem *newitem = new QFxImageItemPrivate::ImageCacheItem;
+ newitem->area = r;
+#if defined(QFX_RENDER_QPAINTER)
+ newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img));
+#else
+ newitem->image.setImage(img);
+#endif
+ d->imagecache.append(newitem);
+ QRectF target(r.x()*hscale, r.y()*vscale, r.width()*hscale, r.height()*vscale);
+ p.drawImage(target.toRect(), newitem->image);
+ }
+ }
+#if defined(QFX_RENDER_OPENGL2)
+ glDisableVertexAttribArray(SingleTextureShader::Vertices);
+ glDisableVertexAttribArray(SingleTextureShader::TextureCoords);
+#elif defined(QFX_RENDER_OPENGL1)
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+#endif
+#if defined(QFX_RENDER_QPAINTER)
+ if(d->smooth)
+ p.restore();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfximageitem.h b/src/declarative/fx/qfximageitem.h
new file mode 100644
index 0000000..9ffd44e
--- /dev/null
+++ b/src/declarative/fx/qfximageitem.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXIMAGEITEM_H
+#define QFXIMAGEITEM_H
+
+#include <qfxglobal.h>
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+/*
+WARNING: SHORT TERM CLASS. INTENDED TO MERGE INTO QFxPainted
+*/
+
+class QFxImageItemPrivate;
+class Q_DECLARATIVE_EXPORT QFxImageItem : public QFxItem
+{
+ Q_OBJECT
+public:
+ QFxImageItem(QFxItem *parent=0);
+ ~QFxImageItem();
+
+ Q_PROPERTY(QSize contentsSize READ contentsSize WRITE setContentsSize);
+ Q_PROPERTY(bool smooth READ isSmooth WRITE setSmooth);
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#elif defined(QFX_RENDER_OPENGL)
+ void paintGLContents(GLPainter &);
+#endif
+
+ bool isSmooth() const;
+ QSize contentsSize() const;
+
+ void setSmooth(bool);
+ void setContentsSize(const QSize &);
+protected:
+ QFxImageItem(QFxImageItemPrivate &dd, QFxItem *parent);
+
+ virtual void drawContents(QPainter *p, const QRect &) = 0;
+
+protected Q_SLOTS:
+ void dirtyCache(const QRect &);
+ void clearCache();
+
+private:
+ void init();
+ Q_DISABLE_COPY(QFxImageItem)
+ Q_DECLARE_PRIVATE(QFxImageItem)
+};
+QML_DECLARE_TYPE(QFxImageItem);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfximageitem_p.h b/src/declarative/fx/qfximageitem_p.h
new file mode 100644
index 0000000..80450ec
--- /dev/null
+++ b/src/declarative/fx/qfximageitem_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXIMAGEITEM_P_H
+#define QFXIMAGEITEM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+#include <qsimplecanvas.h>
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFxImageItemPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxImageItem)
+
+public:
+ QFxImageItemPrivate()
+ : max_imagecache_size(1000*1000), smooth(false)
+ {
+ }
+
+ struct ImageCacheItem {
+ ImageCacheItem() : age(0) {}
+ ~ImageCacheItem() { }
+ int age;
+ QRect area;
+#if defined(QFX_RENDER_QPAINTER)
+ QSimpleCanvasConfig::Image image;
+#else
+ GLTexture image;
+#endif
+ };
+
+ QList<ImageCacheItem*> imagecache;
+
+ const int max_imagecache_size;
+ bool smooth;
+ QSize contentsSize;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp
new file mode 100644
index 0000000..2f4c220
--- /dev/null
+++ b/src/declarative/fx/qfxitem.cpp
@@ -0,0 +1,1751 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QPen>
+#include <QFile>
+#include <QEvent>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QGraphicsSceneMouseEvent>
+#include <QtScript/qscriptengine.h>
+#include <qfxperf.h>
+
+#include "qmlengine.h"
+#include "qmlstate.h"
+#include "qlistmodelinterface.h"
+
+#include "qfxtransform.h"
+#include "qfxscalegrid.h"
+#include "qfxview.h"
+#include "qmlstategroup.h"
+
+#include "qfxitem_p.h"
+#include "qfxitem.h"
+#include <qsimplecanvasfilter.h>
+#include <qmlcomponent.h>
+
+
+QT_BEGIN_NAMESPACE
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+QML_DEFINE_NOCREATE_TYPE(QFxContents);
+QML_DEFINE_TYPE(QFxItem,Item);
+QML_DEFINE_NOCREATE_TYPE(QSimpleCanvasFilter);
+
+/*!
+ \defgroup animation Animation
+ \defgroup coreitems Basic Items
+ \defgroup effects Effects
+ \defgroup layouts Layouts
+ \defgroup states States and Transitions
+ \defgroup utility Utility
+ \defgroup views Views
+ \defgroup widgets Widgets
+*/
+
+/*!
+ \internal
+ \class QFxContents
+ \ingroup utility
+ \brief The QFxContents class gives access to the height and width of an item's contents.
+
+*/
+
+QFxContents::QFxContents() : _height(0), _width(0)
+{
+}
+
+/*!
+ \property QFxContents::height
+ \brief The height of the contents.
+*/
+int QFxContents::height() const
+{
+ return _height;
+}
+
+/*!
+ \property QFxContents::width
+ \brief The width of the contents.
+*/
+int QFxContents::width() const
+{
+ return _width;
+}
+
+//TODO: optimization: only check sender(), if there is one
+void QFxContents::calcHeight()
+{
+ int oldheight = _height;
+
+ int top = INT_MAX;
+ int bottom = 0;
+ foreach(const QSimpleCanvasItem *child,
+ _item->QSimpleCanvasItem::children()) {
+ if (child->y() + child->height() > bottom)
+ bottom = (int)child->y() + child->height();
+ if (child->y() < top)
+ top = (int)child->y();
+ }
+ _height = bottom - top;
+
+ if (_height != oldheight)
+ emit heightChanged();
+}
+
+//TODO: optimization: only check sender(), if there is one
+void QFxContents::calcWidth()
+{
+ int oldwidth = _width;
+
+ int left = INT_MAX;
+ int right = 0;
+ foreach(const QSimpleCanvasItem *child,
+ _item->QSimpleCanvasItem::children()) {
+ if (child->x() + child->width() > right)
+ right = (int)child->x() + child->width();
+ if (child->x() < left)
+ left = (int)child->x();
+ }
+ _width = right - left;
+
+ if (_width != oldwidth)
+ emit widthChanged();
+}
+
+void QFxContents::setItem(QFxItem *item)
+{
+ _item = item;
+
+ foreach(const QSimpleCanvasItem *child,
+ _item->QSimpleCanvasItem::children()) {
+ connect(child, SIGNAL(bottomChanged()), this, SLOT(calcHeight()));
+ connect(child, SIGNAL(rightChanged()), this, SLOT(calcWidth()));
+ }
+
+ calcHeight();
+ calcWidth();
+}
+
+/*!
+ \qmlclass Item QFxItem
+ \brief The Item element is the most basic of all visual canvas members.
+ */
+
+/*!
+ \class QFxItem Item
+ \brief The QFxItem class is a generic QFxView item. It is the base class for all other view items.
+
+ \qmltext
+ All visual elements in Qt Declarative inherit from QFxItem. Although QFxItem
+ has no visual appearance, it defines all the properties that are
+ common across visual elements - like the x and y position, and the
+ width and height.
+
+ QFxItem is also useful for grouping elements together.
+
+ \qml
+ <Item>
+ <Image file="tile.png" />
+ <Image x="80" width="100" height="100" file="tile.png" />
+ <Image x="190" width="100" height="100" tile="true" file="tile.png" />
+ </Item>
+ \endqml
+ \endqmltext
+
+ \ingroup coreitems
+*/
+
+/*!
+ \fn void QFxItem::activeFocusChanged()
+
+ This signal is emitted when this item gains active focus.
+*/
+
+/*!
+ \fn void QFxItem::baselineChanged()
+
+ This signal is emitted when the baseline of the item changes.
+
+ The baseline may change in response to a call to setBaselineOffset()
+ or due to the geometry of the item changing.
+
+ \sa baselineOffset(), setBaselineOffset()
+*/
+
+/*!
+ \fn void QFxItem::baselineOffsetChanged()
+
+ This signal is emitted when the baseline of the item is changed
+ via setBaselineOffset().
+
+ The baseline corresponds to the baseline of the text contained in
+ the element. It is useful for aligning the text in items placed
+ beside each other. The default baseline is positioned at
+ 2/3 of the height of the item.
+
+ \sa baselineOffset(), setBaselineOffset()
+*/
+
+/*!
+ \fn void QFxItem::leftChanged()
+
+ This signal is emitted when the left coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::rightChanged()
+
+ This signal is emitted when the right coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::topChanged()
+
+ This signal is emitted when the top coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::bottomChanged()
+
+ This signal is emitted when the bottom coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::widthChanged()
+
+ This signal is emitted when the width of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::heightChanged()
+
+ This signal is emitted when the height of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::hcenterChanged()
+
+ This signal is emitted when the horizontal center coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::vcenterChanged()
+
+ This signal is emitted when the vertical center coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::scaleChanged()
+
+ This signal is emitted when the scale of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::stateChanged(const QString &state)
+
+ This signal is emitted when the \a state of the item changes.
+
+ \sa states-transitions
+*/
+
+/*!
+ \fn void QFxItem::keyPress()
+
+ This signal is emitted when a key is pressed.
+
+ The key event is available in QML via the QFxKeyEvent \c event
+ property.
+
+ \qml
+ <Item onKeyPress="if (event.key == Qt.Key_Enter) state='Enter'"/>
+ \endqml
+
+ \sa keyRelease()
+*/
+
+/*!
+ \fn void QFxItem::keyRelease()
+
+ This signal is emitted when a key is released.
+
+ The key event is available in QML via the QFxKeyEvent \c event
+ property.
+
+ \qml
+ <Item onKeyRelease="if (event.key == Qt.Key_Enter) state='Enter'"/>
+ \endqml
+
+ \sa keyPress()
+*/
+
+/*!
+ \fn void QFxItem::visibleChanged()
+
+ This signal is emitted when the visibility of the item changes.
+
+ \sa setVisible()
+*/
+
+/*!
+ \fn void QFxItem::opacityChanged()
+
+ This signal is emitted when the opacity of the item changes.
+
+ \sa opacity(), setOpacity()
+*/
+
+/*!
+ \fn void QFxItem::parentChanged()
+
+ This signal is emitted when the parent of the item changes.
+
+ \sa setItemParent()
+*/
+
+/*!
+ \fn void QFxItem::focusChanged()
+
+ This signal is emitted when the item's focus state changes.
+
+ \sa setFocus()
+*/
+
+/*!
+ \fn QFxItem::QFxItem(QFxItem *parent)
+
+ Constructs a QFxItem with the given \a parent.
+*/
+QFxItem::QFxItem(QFxItem* parent)
+ : QSimpleCanvasItem(*(new QFxItemPrivate), parent)
+{
+ Q_D(QFxItem);
+ d->init(parent);
+}
+
+/*! \internal
+*/
+QFxItem::QFxItem(QFxItemPrivate &dd, QFxItem *parent)
+ : QSimpleCanvasItem(dd, parent)
+{
+ Q_D(QFxItem);
+ d->init(parent);
+}
+
+/*! \internal
+*/
+void QFxItem::doUpdate()
+{
+ update();
+}
+
+/*!
+ Destroys the QFxItem.
+*/
+QFxItem::~QFxItem()
+{
+ Q_D(QFxItem);
+ delete d->_anchorLines; d->_anchorLines = 0;
+}
+
+/*!
+ \qmlproperty enum Item::transformOrigin
+ This property holds the origin point around which scale and rotation transform.
+
+ Nine transform origins are available, as shown in the image below.
+
+ \image declarative-transformorigin.png
+
+ This example scales an image about its center.
+ \code
+ <Image src="myimage.png" transformOrigin="Center" scale="4" />
+ \endcode
+
+ The default transform origin is \c TopLeft.
+*/
+/*!
+ \qmlproperty Item Item::parent
+ This property holds the parent of the item.
+*/
+void QFxItem::setItemParent(QFxItem *parent)
+{
+ setParent(parent);
+}
+
+/*!
+ XXX Playing around with view2view transitions.
+ */
+void QFxItem::moveToParent(QFxItem *parent)
+{
+ if(parent && itemParent()) {
+ QPointF me = itemParent()->mapToScene(QPointF(0,0));
+ QPointF them = parent->mapToScene(QPointF(0,0));
+
+ QPointF themx = parent->mapToScene(QPointF(1,0));
+ QPointF themy = parent->mapToScene(QPointF(0,1));
+
+ themx -= them;
+ themy -= them;
+
+ setItemParent(parent);
+
+ // XXX - this is silly and will only work in a few cases
+
+ /*
+ xDiff = rx * themx_x + ry * themy_x
+ yDiff = rx * themx_y + ry * themy_y
+ */
+
+ qreal rx = 0;
+ qreal ry = 0;
+ qreal xDiff = them.x() - me.x();
+ qreal yDiff = them.y() - me.y();
+
+
+ if(themx.x() == 0.) {
+ ry = xDiff / themy.x();
+ rx = (yDiff - ry * themy.y()) / themx.y();
+ } else if(themy.x() == 0.) {
+ rx = xDiff / themx.x();
+ ry = (yDiff - rx * themx.y()) / themy.y();
+ } else if(themx.y() == 0.) {
+ ry = yDiff / themy.y();
+ rx = (xDiff - ry * themy.x()) / themx.x();
+ } else if(themy.y() == 0.) {
+ rx = yDiff / themx.y();
+ ry = (xDiff - rx * themx.x()) / themy.x();
+ } else {
+ qreal div = (themy.x() * themx.y() - themy.y() * themx.x());
+
+ if(div != 0.)
+ rx = (themx.y() * xDiff - themx.x() * yDiff) / div;
+
+ if(themy.y() != 0.) ry = (yDiff - rx * themx.y()) / themy.y();
+ }
+
+ setX(x() - rx);
+ setY(y() - ry);
+ } else {
+ setItemParent(parent);
+ }
+}
+
+/*!
+ Returns the QFxItem parent of this item.
+*/
+QFxItem *QFxItem::itemParent() const
+{
+ return qobject_cast<QFxItem *>(QObject::parent());
+}
+
+/*!
+ \qmlproperty list<Item> Item::children
+ \qmlproperty list<Object> Item::resources
+
+ The children property contains the list of visual children of this element.
+ The resources property contains non-visual resources that you want to
+ reference by name.
+
+ Generally you can rely on Item's default property to handle all this for
+ you, but it can come in handy in some cases.
+
+ \qml
+ <Item>
+ <children>
+ <Text />
+ <Rect />
+ </children>
+ <resources>
+ <Component id="myComponent">
+ <Text />
+ </Component>
+ </resources>
+ </Item>
+ \endqml
+*/
+
+/*!
+ Returns true if all of the attributes set via QML have been set;
+ otherwise returns false.
+
+ \sa classComplete()
+*/
+bool QFxItem::isClassComplete() const
+{
+ Q_D(const QFxItem);
+ return d->_classComplete;
+}
+
+/*!
+ Returns true if construction of the QML component is complete; otherwise
+ returns false.
+
+ It is often desireable to delay some processing until the component is
+ completed.
+
+ \sa componentComplete().
+*/
+bool QFxItem::isComponentComplete() const
+{
+ Q_D(const QFxItem);
+ return d->_componentComplete;
+}
+
+/*!
+ \property QFxItem::anchors
+ \brief The anchors (alignments) used by the item.
+*/
+QFxAnchors *QFxItem::anchors()
+{
+ Q_D(QFxItem);
+ return d->anchors();
+}
+
+void QFxItemPrivate::data_removeAt(int)
+{
+ // ###
+}
+
+int QFxItemPrivate::data_count() const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::data_append(QObject *o)
+{
+ Q_Q(QFxItem);
+ QFxItem *i = qobject_cast<QFxItem *>(o);
+ if(i)
+ q->children()->append(i);
+ else
+ resources_append(o);
+}
+
+void QFxItemPrivate::data_insert(int, QObject *)
+{
+ // ###
+}
+
+QObject *QFxItemPrivate::data_at(int) const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::data_clear()
+{
+ // ###
+}
+
+void QFxItemPrivate::resources_removeAt(int)
+{
+ // ###
+}
+
+int QFxItemPrivate::resources_count() const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::resources_append(QObject *o)
+{
+ Q_Q(QFxItem);
+ o->setParent(q);
+}
+
+void QFxItemPrivate::resources_insert(int, QObject *)
+{
+ // ###
+}
+
+QObject *QFxItemPrivate::resources_at(int) const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::resources_clear()
+{
+ // ###
+}
+
+void QFxItemPrivate::children_removeAt(int)
+{
+ // ###
+}
+
+int QFxItemPrivate::children_count() const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::children_append(QFxItem *i)
+{
+ Q_Q(QFxItem);
+ i->setParent(q);
+}
+
+void QFxItemPrivate::children_insert(int, QFxItem *)
+{
+ // ###
+}
+
+QFxItem *QFxItemPrivate::children_at(int) const
+{
+ // ###
+ return 0;
+}
+
+void QFxItemPrivate::children_clear()
+{
+ // ###
+}
+
+/*!
+ \qmlproperty list<Object> Item::data
+ \default
+
+ The data property is allows you to freely mix visual children and resources
+ of an element. If you assign a visual element to the data list it becomes
+ a child and if you assign any other object type, it is added as a resource.
+
+ So you can write:
+ \qml
+ <Item>
+ <Text />
+ <Rect />
+ <Script />
+ </Item>
+ \endqml
+
+ instead of:
+ \qml
+ <Item>
+ <children>
+ <Text />
+ <Rect />
+ </children>
+ <resources>
+ <Script/>
+ </resources>
+ </Item>
+ \endqml
+
+ data is a behind-the-scenes property: you should never need to explicitly
+ specify it.
+ */
+QmlList<QObject *> *QFxItem::data()
+{
+ Q_D(QFxItem);
+ return &d->data;
+}
+
+/*!
+ \property QFxItem::contents
+ \brief An object that knows about the size of an item's children.
+
+ contents provides an easy way to access the (collective) width and
+ height of the item's children.
+*/
+QFxContents *QFxItem::contents()
+{
+ Q_D(QFxItem);
+ if (!d->_contents) {
+ d->_contents = new QFxContents;
+ d->_contents->setParent(this);
+ d->_contents->setItem(this);
+ }
+ return d->_contents;
+}
+
+QFxItem *QFxItem::qmlItem() const
+{
+ Q_D(const QFxItem);
+ return d->qmlItem;
+}
+
+/*!
+ \qmlproperty string Item::qml
+ This property holds the dynamic QML for the item.
+
+ This property is used for dynamically loading QML into the
+ item. Querying for the QML only has meaning if the QML has been
+ dynamically set; otherwise an empty string is returned.
+*/
+QString QFxItem::qml() const
+{
+ Q_D(const QFxItem);
+ return d->_qml;
+}
+
+void QFxItem::setQml(const QString &qml)
+{
+ Q_D(QFxItem);
+ if (d->_qml == qml)
+ return;
+
+ if(!d->_qml.isEmpty()) {
+ QmlChildren::Iterator iter = d->_qmlChildren.find(d->_qml);
+ if(iter != d->_qmlChildren.end())
+ (*iter)->setOpacity(0.);
+ }
+
+ d->_qml = qml;
+ d->_qmlurl = itemContext()->resolvedUri(qml);
+ d->qmlItem = 0;
+
+ if(d->_qml.isEmpty()) {
+ emit qmlChanged();
+ return;
+ }
+
+ QmlChildren::Iterator iter = d->_qmlChildren.find(d->_qml);
+ if(iter != d->_qmlChildren.end()) {
+ (*iter)->setOpacity(1.);
+ d->qmlItem = (*iter);
+ emit qmlChanged();
+ } else {
+ d->_qmlcomp =
+ new QmlComponent(itemContext()->engine(), d->_qmlurl, this);
+ if(d->_qmlcomp->isReady())
+ qmlLoaded();
+ else
+ QObject::connect(d->_qmlcomp, SIGNAL(readyChanged()),
+ this, SLOT(qmlLoaded()));
+ }
+}
+
+
+void QFxItem::qmlLoaded()
+{
+ Q_D(QFxItem);
+
+ { // newChild...
+ // ###
+ for (int i=0; i<d->_qmlnewloading.length(); ++i) {
+ QmlComponent *c = d->_qmlnewcomp.at(i);
+ if(!c->isReady())
+ continue;
+
+ QmlContext *ctxt = new QmlContext(itemContext());
+ QObject* o = c ? c->create(ctxt):0;
+ QFxItem* ret = qobject_cast<QFxItem*>(o);
+ if (ret) {
+ ret->setItemParent(this);
+ QScriptValue v = itemContext()->engine()->scriptEngine()->newQObject(ret);
+ emit newChildCreated(d->_qmlnewloading.at(i).toString(),v);
+ }
+
+ delete c;
+ d->_qmlnewloading.removeAt(i);
+ d->_qmlnewcomp.removeAt(i);
+ --i;
+ }
+ }
+
+ // setQml...
+ if (d->_qmlcomp) {
+ QmlContext *ctxt = new QmlContext(itemContext());
+ ctxt->addDefaultObject(this);
+
+ QObject *obj = d->_qmlcomp->create(ctxt);
+ QFxItem *qmlChild = qobject_cast<QFxItem *>(obj);
+ if(qmlChild) {
+ qmlChild->setItemParent(this);
+ d->_qmlChildren.insert(d->_qml, qmlChild);
+ d->qmlItem = qmlChild;
+ } else {
+ delete qmlChild;
+ d->_qml = QString();
+ }
+ delete d->_qmlcomp;
+ d->_qmlcomp = 0;
+ emit qmlChanged();
+ }
+}
+
+/*!
+ \qmlproperty Item Item::clipToItem
+
+ Experimental clip to item support. Do not use.
+
+ \todo complete clip to item support.
+ */
+QFxItem *QFxItem::clipToItem() const
+{
+ return 0;
+}
+
+void QFxItem::setClipToItem(QFxItem *)
+{
+ qWarning() << "QFxItem: clipToItem not implemented";
+}
+
+/*!
+ \qmlproperty real Item::x
+ \qmlproperty real Item::y
+ \qmlproperty int Item::width
+ \qmlproperty int Item::height
+
+ Defines the item's position and size relative to its parent.
+
+ \qml
+ <Item x="100" y="100" width="100" height="100" />
+ \endqml
+ */
+
+/*!
+ \qmlproperty real Item::z
+
+ Sets the stacking order of the item. By default the stacking order is 0.
+
+ Items with a higher stacking value are drawn on top of items with a
+ lower stacking order. Items with the same stacking value are drawn
+ bottom up in the order they appear. Items with a negative stacking
+ value are drawn under their parent's content.
+
+ The following example shows the various effects of stacking order.
+
+ \table
+ \row
+ \o \image declarative-item_stacking1.png
+ \o Same \c z - later children above earlier children:
+ \qml
+ <Item>
+ <Rect color="red" width="100" height="100" />
+ <Rect color="blue" x="50" y="50" width="100" height="100" />
+ </Item>
+ \endqml
+ \row
+ \o \image declarative-item_stacking2.png
+ \o Higher \c z on top:
+ \qml
+ <Item>
+ <Rect z="1" color="red" width="100" height="100" />
+ <Rect color="blue" x="50" y="50" width="100" height="100" />
+ </Item>
+ \endqml
+ \row
+ \o \image declarative-item_stacking3.png
+ \o Same \c z - children above parents:
+ \qml
+ <Item>
+ <Rect color="red" width="100" height="100">
+ <Rect color="blue" x="50" y="50" width="100" height="100" />
+ </Rect>
+ </Item>
+ \endqml
+ \row
+ \o \image declarative-item_stacking4.png
+ \o Lower \c z below:
+ \qml
+ <Item>
+ <Rect color="red" width="100" height="100">
+ <Rect z="-1" color="blue" x="50" y="50" width="100" height="100" />
+ </Rect>
+ </Item>
+ \endqml
+ \endtable
+ */
+/*!
+ \property QFxItem::z
+ \brief The z coordinate of the item relative to its parent.
+
+ A negative z coordinate means the item will be painted below its parent.
+*/
+
+void QFxItem::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QFxItem);
+ if(newGeometry.width() != oldGeometry.width()) {
+ int xoffset = oldGeometry.width() - newGeometry.width();
+ d->handleWidthChange(xoffset);
+ }
+
+ if(newGeometry.height() != oldGeometry.height()) {
+ int yoffset = oldGeometry.height() - newGeometry.height();
+ d->handleHeightChange(yoffset);
+ }
+
+ if(newGeometry.x() != oldGeometry.x()) {
+ emit leftChanged();
+ emit hcenterChanged();
+ emit rightChanged();
+ }
+
+ if(newGeometry.y() != oldGeometry.y()) {
+ emit topChanged();
+ emit vcenterChanged();
+ emit bottomChanged();
+ }
+}
+
+void QFxItemPrivate::handleWidthChange(int xoffset)
+{
+ Q_Q(QFxItem);
+ if(!_anchors) {
+ emit q->hcenterChanged();
+ emit q->rightChanged();
+ } else {
+ QFxAnchors::UsedAnchors used = anchors()->usedAnchors();
+ if (used & QFxAnchors::HasHCenterAnchor) {
+ q->setX(q->x() + xoffset/2);
+ emit q->rightChanged();
+ } else if ((used & QFxAnchors::HasRightAnchor) && !(used & QFxAnchors::HasLeftAnchor)) {
+ q->setX(q->x() + xoffset);
+ emit q->hcenterChanged();
+ } else {
+ emit q->hcenterChanged();
+ emit q->rightChanged();
+ }
+ }
+ if(q->rotation() && q->transformOrigin() != QFxItem::TopLeft)
+ q->setRotation(q->rotation());
+ if(q->scale() && q->transformOrigin() != QFxItem::TopLeft)
+ q->setScale(q->scale());
+ emit q->widthChanged();
+}
+
+void QFxItemPrivate::handleHeightChange(int yoffset)
+{
+ Q_Q(QFxItem);
+ if(!_anchors) {
+ emit q->vcenterChanged();
+ emit q->bottomChanged();
+ emit q->baselineChanged();
+ } else {
+ QFxAnchors::UsedAnchors used = anchors()->usedAnchors();
+ if (used & QFxAnchors::HasBaselineAnchor) {
+ q->setY(q->y() + yoffset - q->baselineOffset());
+ emit q->bottomChanged();
+ emit q->vcenterChanged();
+ } else if (used & QFxAnchors::HasVCenterAnchor) {
+ q->setY(q->y() + yoffset/2);
+ emit q->bottomChanged();
+ } else if ((used & QFxAnchors::HasBottomAnchor) && !(used & QFxAnchors::HasTopAnchor)) {
+ q->setY(q->y() + yoffset);
+ emit q->vcenterChanged();
+ } else {
+ emit q->vcenterChanged();
+ emit q->bottomChanged();
+ emit q->baselineChanged();
+ }
+ }
+ if(q->rotation() && q->transformOrigin() != QFxItem::TopLeft)
+ q->setRotation(q->rotation());
+ if(q->scale() && q->transformOrigin() != QFxItem::TopLeft)
+ q->setScale(q->scale());
+ emit q->heightChanged();
+}
+
+/*!
+ \qmlproperty bool Item::flipVertically
+ \qmlproperty bool Item::flipHorizontally
+
+ When set, the item will be displayed flipped horizontally or vertically
+ about its center.
+ */
+bool QFxItem::flipVertically() const
+{
+ return flip() & VerticalFlip;
+}
+
+void QFxItem::setFlipVertically(bool v)
+{
+ if(v)
+ setFlip((QSimpleCanvasItem::Flip)(flip() | VerticalFlip));
+ else
+ setFlip((QSimpleCanvasItem::Flip)(flip() & ~VerticalFlip));
+}
+
+bool QFxItem::flipHorizontally() const
+{
+ return flip() & HorizontalFlip;
+}
+
+void QFxItem::setFlipHorizontally(bool v)
+{
+ if(v)
+ setFlip((QSimpleCanvasItem::Flip)(flip() | HorizontalFlip));
+ else
+ setFlip((QSimpleCanvasItem::Flip)(flip() & ~HorizontalFlip));
+}
+
+class QFxKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key);
+ Q_PROPERTY(QString text READ text);
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted);
+public:
+ QFxKeyEvent(int key, const QString &text=QString()) : _accepted(false), _key(key), _text(text) {}
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+ int key() const { return _key; }
+
+ QString text() const { return _text; }
+
+private:
+ bool _accepted;
+ int _key;
+ QString _text;
+};
+
+/*!
+ \reimp
+*/
+void QFxItem::keyPressEvent(QKeyEvent *event)
+{
+ QFxKeyEvent ke(event->key(), event->text());
+ emit keyPress(&ke);
+ event->setAccepted(ke.isAccepted());
+ if (itemParent() && !ke.isAccepted())
+ itemParent()->keyPressEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QFxItem::keyReleaseEvent(QKeyEvent *event)
+{
+ QFxKeyEvent ke(event->key(), event->text());
+ emit keyRelease(&ke);
+ event->setAccepted(ke.isAccepted());
+ if (itemParent() && !ke.isAccepted())
+ itemParent()->keyReleaseEvent(event);
+}
+
+/*!
+ Returns the bounding rectangle of the item in scene coordinates.
+*/
+QRectF QFxItem::sceneBoundingRect() const
+{
+ return QRectF(mapToScene(QPointF(0,0)), QSize(width(), height()));
+}
+
+/*!
+ \qmlproperty string Item::id
+ This property holds the identifier for the item.
+
+ The identifier can be used in bindings and other expressions to
+ refer to the item. For example:
+
+ \qml
+ <Text id="myText" .../>
+ <Text text="{myText.text}"/>
+ \endqml
+
+ The identifier is available throughout to the \l {components}{component}
+ where it is declared. Two items in the same component
+ with the same identifier is invalid.
+*/
+QString QFxItem::id() const
+{
+ Q_D(const QFxItem);
+ return d->_id;
+}
+
+void QFxItem::setId(const QString &id)
+{
+ Q_D(QFxItem);
+ setObjectName(id);
+ d->_id = id;
+}
+
+QFxAnchorLine QFxItem::left() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->left;
+}
+
+QFxAnchorLine QFxItem::right() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->right;
+}
+
+QFxAnchorLine QFxItem::horizontalCenter() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->hCenter;
+}
+
+QFxAnchorLine QFxItem::top() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->top;
+}
+
+QFxAnchorLine QFxItem::bottom() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->bottom;
+}
+
+QFxAnchorLine QFxItem::verticalCenter() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->vCenter;
+}
+
+/*!
+ \qmlproperty AnchorLine Item::top
+ \qmlproperty AnchorLine Item::bottom
+ \qmlproperty AnchorLine Item::left
+ \qmlproperty AnchorLine Item::right
+ \qmlproperty AnchorLine Item::horizontalCenter
+ \qmlproperty AnchorLine Item::verticalCenter
+
+ The anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \qmlproperty AnchorLine Item::anchors.top
+ \qmlproperty AnchorLine Item::anchors.bottom
+ \qmlproperty AnchorLine Item::anchors.left
+ \qmlproperty AnchorLine Item::anchors.right
+ \qmlproperty AnchorLine Item::anchors.horizontalCenter
+ \qmlproperty AnchorLine Item::anchors.verticalCenter
+
+ \qmlproperty Item Item::anchors.fill
+
+ \qmlproperty int Item::anchors.topMargin
+ \qmlproperty int Item::anchors.bottomMargin
+ \qmlproperty int Item::anchors.leftMargin
+ \qmlproperty int Item::anchors.rightMargin
+ \qmlproperty int Item::anchors.horizontalCenterOffset
+ \qmlproperty int Item::anchors.verticalCenterOffset
+
+ Anchors provide a way to position an item by specifying its
+ relationship with other items.
+
+ Margins apply to top, bottom, left, right, and fill anchors.
+
+ Offsets apply for horizontal and vertical center anchors.
+
+ \table
+ \row
+ \o \image declarative-anchors_example.png
+ \o Text anchored to Image, horizontally centered and vertically below, with a margin.
+ \qml
+ <Image id="pic" .../>
+ <Text id="label" anchors.horizontalCenter="{pic.horizontalCenter}"
+ anchors.top="{pic.bottom}"
+ anchors.topMargin="5" .../>
+ \endqml
+ \row
+ \o \image declarative-anchors_example2.png
+ \o
+ Left of Text anchored to right of Image, with a margin. The y
+ property of both defaults to 0.
+
+ \qml
+ <Image id="pic" .../>
+ <Text id="label" anchors.left="{pic.right}"
+ anchors.leftMargin="5" .../>
+ \endqml
+ \endtable
+
+ anchors.fill provides a convenient way for one item to have the
+ same geometry as another item, and is equivalent to connecting all
+ four directional anchors.
+
+ \note You can only anchor an item to siblings or a parent.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*
+ \property QFxItem::baseline
+ \brief The position of the item's baseline in global (scene) coordinates.
+
+ The baseline of a Text item is the imaginary line on which the text
+ sits. Controls containing text usually set their baseline to the
+ baseline of their text.
+
+ For non-text items, a default baseline offset of two-thirds of the
+ item's height is used to determine the baseline.
+*/
+
+int QFxItem::baselineOffset() const
+{
+ Q_D(const QFxItem);
+ if (!d->_baselineOffset.isValid()) {
+ return height()*2/3; //### default baseline is 2/3 of the way to the bottom of the item
+ } else
+ return d->_baselineOffset;
+}
+
+void QFxItem::setBaselineOffset(int offset)
+{
+ Q_D(QFxItem);
+ if (offset == d->_baselineOffset)
+ return;
+
+ d->_baselineOffset = offset;
+ emit baselineOffsetChanged();
+ emit baselineChanged();
+}
+
+/*!
+ \qmlproperty real Item::rotation
+ This property holds the rotation of the item in degrees.
+
+ This specifies how many degrees to rotate the item around its origin (0,0).
+ The default rotation is 0 degrees (i.e. not rotated at all).
+
+ \table
+ \row
+ \o \image declarative-rotation.png
+ \o
+ \qml
+ <Rect color="blue" width="100" height="100">
+ <Rect color="green" width="25" height="25"/>
+ <Rect color="red" width="50" height="50" x="25" y="25" rotation="30"/>
+ </Rect>
+ \endqml
+ \endtable
+*/
+qreal QFxItem::rotation() const
+{
+ Q_D(const QFxItem);
+ return d->_rotation;
+}
+
+void QFxItem::setRotation(qreal rotation)
+{
+ Q_D(QFxItem);
+ if (d->_rotation == rotation)
+ return;
+ d->_rotation = rotation;
+#if defined(QFX_RENDER_OPENGL)
+ QMatrix4x4 trans;
+ QPointF to = transformOriginPoint();
+ trans.translate(to.x(), to.y());
+ trans.rotate(d->_rotation, 0, 0, 1);
+ trans.translate(-to.x(), -to.y());
+#else
+ QTransform trans;
+ QPointF to = transformOriginPoint();
+ trans.translate(to.x(), to.y());
+ trans.rotate(d->_rotation);
+ trans.translate(-to.x(), -to.y());
+#endif
+ setTransform(trans);
+ emit rotationChanged();
+}
+
+/*!
+ \qmlproperty real Item::scale
+ This property holds the scale of the item.
+
+ A scale of less than 1 means the item will be displayed smaller than
+ normal, and a scale of greater than 1 means the item will be
+ displayed larger than normal. A negative scale means the item will
+ be mirrored.
+
+ By default, items are displayed at a scale of 1 (i.e. at their
+ normal size).
+
+ Scaling is from the item's origin (0,0).
+
+ \table
+ \row
+ \o \image declarative-scale.png
+ \o
+ \qml
+ <Rect color="blue" width="100" height="100">
+ <Rect color="green" width="25" height="25"/>
+ <Rect color="red" width="50" height="50" x="25" y="25" scale="1.4"/>
+ </Rect>
+ \endqml
+ \endtable
+*/
+qreal QFxItem::scale() const
+{
+ return QSimpleCanvasItem::scale();
+}
+
+void QFxItem::setScale(qreal s)
+{
+ if (QSimpleCanvasItem::scale() == s) return;
+ QSimpleCanvasItem::setScale(s);
+ emit scaleChanged();
+ update();
+}
+
+/*!
+ \qmlproperty real Item::opacity
+
+ The opacity of the item. Opacity is specified as a number between 0
+ (fully transparent) and 1 (fully opaque). The default is 1.
+
+ Opacity is an \e inherited attribute. That is, the opacity is
+ also applied individually to child items. In almost all cases this
+ is what you want. If you can spot the issue in the following
+ example, you might need to use an opacity filter instead.
+
+ \table
+ \row
+ \o \image declarative-item_opacity1.png
+ \o
+ \qml
+ <Item>
+ <Rect color="red" width="100" height="100">
+ <Rect color="blue" x="50" y="50" width="100" height="100" />
+ </Rect>
+ </Item>
+ \endqml
+ \row
+ \o \image declarative-item_opacity2.png
+ \o
+ \qml
+ <Item>
+ <Rect opacity="0.5" color="red" width="100" height="100">
+ <Rect color="blue" x="50" y="50" width="100" height="100" />
+ </Rect>
+ </Item>
+ \endqml
+ \endtable
+
+ \todo There is no such thing as an opacity filter
+*/
+
+qreal QFxItem::opacity() const
+{
+ return QSimpleCanvasItem::visible();
+}
+
+void QFxItem::setOpacity(qreal v)
+{
+ if(v == QSimpleCanvasItem::visible())
+ return;
+
+ if(v < 0) v = 0;
+ else if(v > 1) v = 1;
+ QSimpleCanvasItem::setVisible(v);
+
+ emit opacityChanged();
+}
+
+bool QFxItem::keepMouseGrab() const
+{
+ Q_D(const QFxItem);
+ return d->_keepMouse;
+}
+
+void QFxItem::setKeepMouseGrab(bool keep)
+{
+ Q_D(QFxItem);
+ d->_keepMouse = keep;
+}
+
+void QFxItem::activeFocusChanged(bool)
+{
+ emit activeFocusChanged();
+}
+
+void QFxItem::focusChanged(bool)
+{
+ emit focusChanged();
+}
+
+QmlList<QFxItem *> *QFxItem::children()
+{
+ Q_D(QFxItem);
+ return &(d->children);
+}
+
+QmlList<QObject *> *QFxItem::resources()
+{
+ Q_D(QFxItem);
+ return &(d->resources);
+}
+
+/*!
+ \qmlproperty list<State> Item::states
+ This property holds a list of states defined by the item.
+
+ \qml
+ <Item>
+ <states>
+ <State .../>
+ <State .../>
+ ...
+ </states>
+ </Item>
+ \endqml
+
+ \sa {states-transitions}{States and Transitions}
+*/
+QmlList<QmlState *>* QFxItem::states()
+{
+ Q_D(QFxItem);
+ return d->states()->statesProperty();
+}
+
+/*!
+ \qmlproperty list<Transition> Item::transitions
+ This property holds a list of transitions defined by the item.
+
+ \qml
+ <Item>
+ <transitions>
+ <Transition .../>
+ <Transition .../>
+ ...
+ </transitions>
+ </Item>
+ \endqml
+
+ \sa {states-transitions}{States and Transitions}
+*/
+QmlList<QmlTransition *>* QFxItem::transitions()
+{
+ Q_D(QFxItem);
+ return d->states()->transitionsProperty();
+}
+
+/*!
+ \qmlproperty list<Filter> Item::filter
+ This property holds a list of graphical filters to be applied to the item.
+
+ \l {qmlfilter}{Filters} include things like \l {qmlblur}{blurring}
+ the item, or giving it a Reflection. Some
+ filters may not be available on all canvases; if a filter is not
+ available on a certain canvas, it will simply not be applied for
+ that canvas (but the XML will still be considered valid).
+
+ \qml
+ <Item>
+ <filter>
+ <Blur .../>
+ <Relection .../>
+ ...
+ </filter>
+ </Item>
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool Item::clip
+ This property holds whether clipping is enabled.
+
+ if clipping is enabled, an item will clip its own painting, as well
+ as the painting of its children, to its bounding rectangle.
+
+ Non-rectangular clipping regions are not supported for performance reasons.
+*/
+
+/*!
+ Returns the state with \a name. Returns 0 if no matching state is found.
+*/
+QmlState *QFxItem::findState(const QString &name) const
+{
+ Q_D(const QFxItem);
+ if(!d->_stateGroup)
+ return 0;
+ else
+ return d->_stateGroup->findState(name);
+}
+
+/*!
+ \qmlproperty string Item::state
+
+ This property holds the name of the current state of the item.
+
+ This property is often used in scripts to change between states. For
+ example:
+
+ \qml
+ <Script>
+ function toggle() {
+ if (button.state == 'On')
+ button.state = 'Off';
+ else
+ button.state = 'On';
+ }
+ </Script>
+ \endqml
+
+ If the item is in its base state (i.e. no explicit state has been
+ set), \c state will be a blank string. Likewise, you can return an
+ item to its base state by setting its current state to \c ''.
+
+ \sa {states-transitions}{States and Transitions}
+*/
+QString QFxItem::state() const
+{
+ Q_D(const QFxItem);
+ if(!d->_stateGroup)
+ return QString();
+ else
+ return d->_stateGroup->state();
+}
+
+void QFxItem::setState(const QString &state)
+{
+ Q_D(QFxItem);
+ d->states()->setState(state);
+}
+
+/*!
+ \qmlproperty list<Transform> Item::transform
+ This property holds the list of transformations to apply.
+
+ For more information see \l Transform.
+*/
+QList<QFxTransform *> *QFxItem::transform()
+{
+ Q_D(QFxItem);
+ return &(d->_transform);
+}
+
+/*!
+ Returns true if the item is visible; otherwise returns false.
+
+ An item is considered visible if its opacity is not 0.
+*/
+bool QFxItem::isVisible() const
+{
+ Q_D(const QFxItem);
+ return d->visible;
+}
+
+/*!
+ Sets the visibility of the item to \a visible.
+
+ Setting visibility to false sets opacity to 0. Setting the
+ visibility to true restores the opacity to its previous value.
+*/
+void QFxItem::setVisible(bool visible)
+{
+ Q_D(QFxItem);
+ if(visible == d->visible)
+ return;
+
+ d->visible = visible;
+ if(visible)
+ setOpacity(d->visibleOp);
+ else {
+ d->visibleOp = opacity();
+ setOpacity(0);
+ }
+
+ emit visibleChanged();
+}
+
+/*! \internal
+*/
+void QFxItem::dump(int depth)
+{
+ Q_D(QFxItem);
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << metaObject()->className() << "(" << (void *)static_cast<QFxItem*>(this) << ", " << (void *)static_cast<QSimpleCanvasItem*>(this) << "):" << x() << y() << width() << height() << (void *) itemParent();
+}
+
+/*! \internal
+*/
+QString QFxItem::propertyInfo() const
+{
+ return QString();
+}
+
+/*!
+ Creates a new child of the given component \a type. The
+ newChildCreated() signal will be emitted when and if the child is
+ successfully created.
+
+ \preliminary
+*/
+void QFxItem::newChild(const QString &type)
+{
+ Q_D(QFxItem);
+
+ QUrl url = itemContext()->resolvedUri(type);
+ if (url.isEmpty())
+ return;
+
+ d->_qmlnewloading.append(url);
+ d->_qmlnewcomp.append(new QmlComponent(itemContext()->engine(), url, this));
+
+ if(d->_qmlnewcomp.last()->isReady())
+ qmlLoaded();
+ else
+ connect(d->_qmlnewcomp.last(), SIGNAL(readyChanged()),
+ this, SLOT(qmlLoaded()));
+}
+
+/*!
+ classBegin() is called when the item is constructed, but its
+ properties have not yet been set.
+
+ \sa classComplete(), componentComplete(), isClassComplete(), isComponentComplete()
+*/
+void QFxItem::classBegin()
+{
+ Q_D(QFxItem);
+ d->_classComplete = false;
+ d->_componentComplete = false;
+ if(d->_stateGroup)
+ d->_stateGroup->classBegin();
+}
+
+/*!
+ classComplete() is called when all properties specified in QML
+ have been assigned. It is sometimes desireable to delay some
+ processing until all property assignments are complete.
+*/
+void QFxItem::classComplete()
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::ItemClassComplete> cc;
+#endif
+ Q_D(QFxItem);
+ d->_classComplete = true;
+ if(d->_stateGroup)
+ d->_stateGroup->classComplete();
+}
+
+/*!
+ componentComplete() is called when all elements in the component
+ have been constructed. It is often desireable to delay some
+ processing until the component is complete an all bindings in the
+ component have been resolved.
+*/
+void QFxItem::componentComplete()
+{
+ Q_D(QFxItem);
+ d->_componentComplete = true;
+ if(d->_stateGroup)
+ d->_stateGroup->componentComplete();
+ if(d->_anchors) {
+ d->anchors()->connectHAnchors();
+ d->anchors()->connectVAnchors();
+ }
+ if(!d->_transform.isEmpty())
+ updateTransform();
+}
+
+/*! \internal
+*/
+void QFxItem::parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *)
+{
+ emit parentChanged();
+}
+
+/*! \internal
+*/
+void QFxItem::reparentItems()
+{
+ qFatal("EEK");
+}
+
+void QFxItem::updateTransform()
+{
+ Q_D(QFxItem);
+ QSimpleCanvas::Matrix trans;
+ for(int ii = d->_transform.count() - 1; ii >= 0; --ii) {
+ QFxTransform *a = d->_transform.at(ii);
+ if(!a->isIdentity())
+ trans = a->transform() * trans;
+ }
+
+ setTransform(trans);
+ transformChanged(trans);
+}
+
+void QFxItem::transformChanged(const QSimpleCanvas::Matrix &)
+{
+}
+
+/*!
+ Returns the current QML context for this item.
+*/
+QmlContext *QFxItem::itemContext() const
+{
+ Q_D(const QFxItem);
+ return d->_ctxt;
+}
+
+QmlStateGroup *QFxItemPrivate::states()
+{
+ Q_Q(QFxItem);
+ if(!_stateGroup) {
+ _stateGroup = new QmlStateGroup(q);
+ if(!_classComplete)
+ _stateGroup->classBegin();
+ QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)),
+ q, SIGNAL(stateChanged(QString)));
+ }
+
+ return _stateGroup;
+}
+
+QFxItemPrivate::AnchorLines::AnchorLines(QFxItem *q)
+{
+ left.item = q;
+ left.anchorLine = QFxAnchorLine::Left;
+ right.item = q;
+ right.anchorLine = QFxAnchorLine::Right;
+ hCenter.item = q;
+ hCenter.anchorLine = QFxAnchorLine::HCenter;
+ top.item = q;
+ top.anchorLine = QFxAnchorLine::Top;
+ bottom.item = q;
+ bottom.anchorLine = QFxAnchorLine::Bottom;
+ vCenter.item = q;
+ vCenter.anchorLine = QFxAnchorLine::VCenter;
+}
+
+#include "qfxitem.moc"
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h
new file mode 100644
index 0000000..d3b9899
--- /dev/null
+++ b/src/declarative/fx/qfxitem.h
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXITEM_H
+#define QFXITEM_H
+
+#include <QObject>
+#include <QtScript/qscriptvalue.h>
+#include <QList>
+#include <QtDeclarative/qfxanchors.h>
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qml.h>
+#include <QtDeclarative/qfxscalegrid.h>
+#include <QtDeclarative/qsimplecanvasitem.h>
+#include <QtDeclarative/qmlcomponent.h>
+#include <QtDeclarative/qmlstate.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QFxContents : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int height READ height NOTIFY heightChanged);
+ Q_PROPERTY(int width READ width NOTIFY widthChanged);
+public:
+ QFxContents();
+
+ int height() const;
+
+ int width() const;
+
+ void setItem(QFxItem *item);
+
+public Q_SLOTS:
+ void calcHeight();
+ void calcWidth();
+
+Q_SIGNALS:
+ void heightChanged();
+ void widthChanged();
+
+private:
+ QFxItem *_item;
+ int _height;
+ int _width;
+};
+QML_DECLARE_TYPE(QFxContents);
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFxAnchors::UsedAnchors);
+
+class QmlContext;
+class QmlState;
+class QmlTransition;
+class QFxTransform;
+class QFxItemPrivate;
+class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QmlParserStatus)
+
+ Q_PROPERTY(QFxItem * parent READ itemParent WRITE setItemParent NOTIFY parentChanged DESIGNABLE false)
+ Q_PROPERTY(QFxItem * moveToParent READ itemParent WRITE moveToParent NOTIFY parentChanged DESIGNABLE false)
+ Q_PROPERTY(QString id READ id WRITE setId)
+ Q_PROPERTY(QmlList<QFxItem *>* children READ children DESIGNABLE false)
+ Q_PROPERTY(QmlList<QObject *>* resources READ resources DESIGNABLE false)
+ Q_PROPERTY(QFxAnchors * anchors READ anchors DESIGNABLE false)
+ Q_PROPERTY(QmlList<QObject *> *data READ data DESIGNABLE false)
+ Q_PROPERTY(QFxContents * contents READ contents DESIGNABLE false)
+ Q_PROPERTY(QmlList<QmlState *>* states READ states DESIGNABLE false)
+ Q_PROPERTY(QmlList<QmlTransition *>* transitions READ transitions DESIGNABLE false)
+ Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
+ Q_PROPERTY(QString qml READ qml WRITE setQml NOTIFY qmlChanged)
+ Q_PROPERTY(QFxItem *qmlItem READ qmlItem NOTIFY qmlChanged)
+ Q_PROPERTY(QFxItem *clipToItem READ clipToItem WRITE setClipToItem)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY leftChanged)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY topChanged)
+ Q_PROPERTY(qreal z READ z WRITE setZ)
+ Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
+ Q_PROPERTY(bool flipVertically READ flipVertically WRITE setFlipVertically)
+ Q_PROPERTY(bool flipHorizontally READ flipHorizontally WRITE setFlipHorizontally)
+ Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
+ Q_PROPERTY(int baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged )
+ Q_PROPERTY(QFxAnchorLine left READ left)
+ Q_PROPERTY(QFxAnchorLine right READ right)
+ Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter)
+ Q_PROPERTY(QFxAnchorLine top READ top)
+ Q_PROPERTY(QFxAnchorLine bottom READ bottom)
+ Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged)
+ Q_PROPERTY(QSimpleCanvasFilter *filter READ filter WRITE setFilter)
+ Q_PROPERTY(bool clip READ clip WRITE setClip)
+ Q_PROPERTY(bool focusable READ isFocusable WRITE setFocusable)
+ Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged)
+ Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged)
+ Q_PROPERTY(QList<QFxTransform *>* transform READ transform)
+ Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+ typedef QHash<QString, QFxItem *> QmlChildren;
+
+public:
+ QFxItem(QFxItem *parent = 0);
+ virtual ~QFxItem();
+
+ QFxItem *itemParent() const;
+ void setItemParent(QFxItem *parent);
+
+ void moveToParent(QFxItem *parent);
+
+ QString id() const;
+ void setId(const QString &);
+
+ QmlList<QObject *> *data();
+ QmlList<QFxItem *> *children();
+ QmlList<QObject *> *resources();
+
+ QFxAnchors *anchors();
+
+ QFxContents *contents();
+
+ QmlList<QmlState *>* states();
+ QmlState *findState(const QString &name) const;
+
+ QmlList<QmlTransition *>* transitions();
+
+ QString state() const;
+ void setState(const QString &);
+
+ QFxItem *qmlItem() const;
+ QString qml() const;
+ void setQml(const QString &);
+
+ QFxItem *clipToItem() const;
+ void setClipToItem(QFxItem *i);
+
+ bool flipVertically() const;
+ void setFlipVertically(bool);
+ bool flipHorizontally() const;
+ void setFlipHorizontally(bool);
+
+ int baselineOffset() const;
+ void setBaselineOffset(int);
+
+ QFxAnchorLine left() const;
+ QFxAnchorLine right() const;
+ QFxAnchorLine horizontalCenter() const;
+ QFxAnchorLine top() const;
+ QFxAnchorLine bottom() const;
+ QFxAnchorLine verticalCenter() const;
+
+ qreal rotation() const;
+ void setRotation(qreal);
+
+ qreal scale() const;
+ void setScale(qreal);
+
+ qreal opacity() const;
+ virtual void setOpacity(qreal);
+
+ QList<QFxTransform *> *transform();
+
+ bool isVisible() const;
+ void setVisible(bool);
+
+ virtual void dump(int depth = 0);
+ virtual QString propertyInfo() const;
+
+ bool isClassComplete() const;
+ bool isComponentComplete() const;
+
+ QRectF sceneBoundingRect() const;
+
+ void updateTransform();
+
+ bool keepMouseGrab() const;
+ void setKeepMouseGrab(bool);
+
+ QmlContext *itemContext() const;
+
+public Q_SLOTS:
+ void newChild(const QString &url);
+
+Q_SIGNALS:
+ void leftChanged();
+ void rightChanged();
+ void widthChanged();
+ void heightChanged();
+ void topChanged();
+ void bottomChanged();
+ void hcenterChanged();
+ void vcenterChanged();
+ void baselineChanged();
+ void baselineOffsetChanged();
+ void stateChanged(const QString &);
+ void focusChanged();
+ void activeFocusChanged();
+ void parentChanged();
+ void keyPress(QObject *event);
+ void keyRelease(QObject *event);
+ void rotationChanged();
+ void scaleChanged();
+ void opacityChanged();
+ void visibleChanged();
+ void qmlChanged();
+ void newChildCreated(const QString &url, QScriptValue);
+
+protected:
+ virtual void transformChanged(const QSimpleCanvas::Matrix &);
+ virtual void classBegin();
+ virtual void classComplete();
+ virtual void componentComplete();
+ virtual void parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *);
+ virtual void reparentItems();
+ virtual void focusChanged(bool);
+ virtual void activeFocusChanged(bool);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+private Q_SLOTS:
+ void doUpdate();
+ void qmlLoaded();
+
+protected:
+ QFxItem(QFxItemPrivate &dd, QFxItem *parent = 0);
+
+private:
+ void init(QFxItem *parent);
+ friend class QmlStatePrivate;
+ Q_DISABLE_COPY(QFxItem)
+ Q_DECLARE_PRIVATE(QFxItem)
+};
+QML_DECLARE_TYPE(QFxItem);
+
+QML_DECLARE_TYPE(QSimpleCanvasFilter);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXITEM_H
diff --git a/src/declarative/fx/qfxitem_p.h b/src/declarative/fx/qfxitem_p.h
new file mode 100644
index 0000000..1266711
--- /dev/null
+++ b/src/declarative/fx/qfxitem_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXITEM_P_H
+#define QFXITEM_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem.h"
+#include <private/qsimplecanvasitem_p.h>
+#include <private/qmlnullablevalue_p.h>
+#include <qml.h>
+#include <qmlcontext.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkReply;
+
+class QFxItemPrivate : public QSimpleCanvasItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxItem)
+
+ typedef QHash<QString, QFxItem *> QmlChildren;
+
+public:
+ QFxItemPrivate()
+ : _anchors(0), _contents(0), qmlItem(0), _qmlcomp(0),
+ _baselineOffset(0), _rotation(0.),
+ _classComplete(true), _componentComplete(true), _keepMouse(false),
+ visible(true), _anchorLines(0), visibleOp(1), reparentedChildren(0),
+ _stateGroup(0)
+ {}
+ ~QFxItemPrivate()
+ { delete _anchors; }
+
+ void init(QFxItem *parent)
+ {
+ Q_Q(QFxItem);
+ _ctxt = QmlContext::activeContext();
+
+ if(parent)
+ q->setItemParent(parent);
+ _baselineOffset.invalidate();
+ q->setAcceptedMouseButtons(Qt::NoButton);
+ }
+
+ QmlContext *_ctxt;
+ QString _id;
+
+ // data property
+ void data_removeAt(int);
+ int data_count() const;
+ void data_append(QObject *);
+ void data_insert(int, QObject *);
+ QObject *data_at(int) const;
+ void data_clear();
+ QML_DECLARE_LIST_PROXY(QFxItemPrivate, QObject *, data);
+
+ // resources property
+ void resources_removeAt(int);
+ int resources_count() const;
+ void resources_append(QObject *);
+ void resources_insert(int, QObject *);
+ QObject *resources_at(int) const;
+ void resources_clear();
+ QML_DECLARE_LIST_PROXY(QFxItemPrivate, QObject *, resources);
+
+ // children property
+ void children_removeAt(int);
+ int children_count() const;
+ void children_append(QFxItem *);
+ void children_insert(int, QFxItem *);
+ QFxItem *children_at(int) const;
+ void children_clear();
+ QML_DECLARE_LIST_PROXY(QFxItemPrivate, QFxItem *, children);
+
+ QList<QFxTransform *> _transform;
+ QFxAnchors *anchors() {
+ if(!_anchors) {
+ Q_Q(QFxItem);
+ _anchors = new QFxAnchors;
+ _anchors->setItem(q);
+ }
+ return _anchors;
+ }
+ QFxAnchors *_anchors;
+ QFxContents *_contents;
+ QFxItem *qmlItem;
+ QUrl _qmlurl;
+ QmlComponent *_qmlcomp;
+ QString _qml;
+ QList<QUrl> _qmlnewloading;
+ QList<QmlComponent*> _qmlnewcomp;
+
+ QmlNullableValue<int> _baselineOffset;
+ float _rotation;
+
+ bool _classComplete:1;
+ bool _componentComplete:1;
+ bool _keepMouse:1;
+ bool visible:1;
+
+ QmlChildren _qmlChildren;
+
+ struct AnchorLines {
+ AnchorLines(QFxItem *);
+ QFxAnchorLine left;
+ QFxAnchorLine right;
+ QFxAnchorLine hCenter;
+ QFxAnchorLine top;
+ QFxAnchorLine bottom;
+ QFxAnchorLine vCenter;
+ };
+ mutable AnchorLines *_anchorLines;
+ AnchorLines *anchorLines() const {
+ Q_Q(const QFxItem);
+ if(!_anchorLines) _anchorLines =
+ new AnchorLines(const_cast<QFxItem *>(q));
+ return _anchorLines;
+ }
+
+ float visibleOp;
+
+ int reparentedChildren;
+
+ QmlStateGroup *states();
+ QmlStateGroup *_stateGroup;
+
+ void handleWidthChange(int xoffset);
+ void handleHeightChange(int xoffset);
+};
+
+QT_END_NAMESPACE
+#endif // QFXITEM_P_H
diff --git a/src/declarative/fx/qfxkeyactions.cpp b/src/declarative/fx/qfxkeyactions.cpp
new file mode 100644
index 0000000..c4ae3e3
--- /dev/null
+++ b/src/declarative/fx/qfxkeyactions.cpp
@@ -0,0 +1,930 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxkeyactions.h"
+#include <qmlexpression.h>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxKeyActions,KeyActions);
+
+class QFxKeyActionsPrivate
+{
+public:
+ QFxKeyActionsPrivate();
+
+ bool enabled;
+
+ uint keys1;
+ uint keys2;
+
+ QHash<Qt::Key, QString> actions;
+
+ bool key(Qt::Key) const;
+ QString action(Qt::Key) const;
+ void setKey(Qt::Key, bool = true);
+
+ bool testBit(int) const;
+ void setBit(int, bool);
+
+ int keyToBit(Qt::Key) const;
+
+ QString keyExpr(Qt::Key) const;
+ void setKeyExpr(Qt::Key, const QString &);
+};
+
+QFxKeyActionsPrivate::QFxKeyActionsPrivate()
+: enabled(true), keys1(0), keys2(0)
+{
+}
+
+int QFxKeyActionsPrivate::keyToBit(Qt::Key k) const
+{
+ if(k >= Qt::Key_A && k <= Qt::Key_Z ) {
+ return k - Qt::Key_A;
+ } else if(k >= Qt::Key_Left && k <= Qt::Key_Down) {
+ return 26 + k - Qt::Key_Left;
+ } else if(k >= Qt::Key_0 && k <= Qt::Key_9) {
+ return 30 + k - Qt::Key_0;
+ } else if(k >= Qt::Key_Context1 && k <= Qt::Key_Flip) {
+ return 40 + k - Qt::Key_Context1;
+ } else if(k >= Qt::Key_Select && k <= Qt::Key_No) {
+ return 47 + k - Qt::Key_Select;
+ } else {
+ const int start = 50;
+ switch(k) {
+ case Qt::Key_Escape:
+ return start + 0;
+ case Qt::Key_Return:
+ return start + 1;
+ case Qt::Key_Enter:
+ return start + 2;
+ case Qt::Key_Delete:
+ return start + 3;
+ case Qt::Key_Space:
+ return start + 4;
+ case Qt::Key_Back:
+ return start + 5;
+ case Qt::Key_unknown:
+ return start + 6;
+ case Qt::Key_Asterisk:
+ return start + 7;
+ default:
+ return -1;
+ }
+ }
+}
+
+bool QFxKeyActionsPrivate::key(Qt::Key k) const
+{
+ int b = keyToBit(k);
+ bool rv = testBit(b);
+ if(!rv && k != Qt::Key_Shift)
+ rv = testBit(keyToBit(Qt::Key_unknown));
+ return rv;
+}
+
+QString QFxKeyActionsPrivate::action(Qt::Key k) const
+{
+ int b = keyToBit(k);
+ if(b != -1 && testBit(b))
+ return actions.value(k);
+ else
+ return actions.value(Qt::Key_unknown);
+}
+
+void QFxKeyActionsPrivate::setKey(Qt::Key k, bool v)
+{
+ int b = keyToBit(k);
+ if(b == -1)
+ return;
+
+ setBit(b, v);
+}
+
+bool QFxKeyActionsPrivate::testBit(int b) const
+{
+ if(b < 0)
+ return false;
+
+ if(b < 32)
+ return keys1 & (1 << b);
+ else
+ return keys2 & (1 << (b - 32));
+}
+
+void QFxKeyActionsPrivate::setBit(int b, bool v)
+{
+ if(v) {
+ if(b < 32)
+ keys1 |= (1 << b);
+ else
+ keys2 |= (1 << (b - 32));
+ } else {
+ if(b < 32)
+ keys1 &= ~(1 << b);
+ else
+ keys2 &= ~(1 << (b - 32));
+ }
+}
+
+
+/*!
+ \qmlclass KeyActions
+ \brief The KeyActions element enables simple key handling.
+ \inherits Item
+
+ KeyActions is typically used in basic key handling scenarios where writing
+ JavaScript key handling routines would be unnecessarily complicated. The
+ KeyActions element has a collection of properties that correspond to a
+ selection of common keys. When a given key is pressed, the element executes
+ the action script assigned to the matching property. If no action has
+ been set the KeyActions element does nothing.
+
+ To receive (and susequently respond to) key presses, the KeyActions class
+ must be in the current focus chain, just like any other element.
+
+ For basic mouse handling, see \l MouseRegion.
+
+ KeyActions is an invisible element: it is never painted.
+*/
+QFxKeyActions::QFxKeyActions(QFxItem *parent)
+: QFxItem(parent), d(new QFxKeyActionsPrivate)
+{
+}
+
+QFxKeyActions::~QFxKeyActions()
+{
+ delete d;
+}
+
+QString QFxKeyActionsPrivate::keyExpr(Qt::Key k) const
+{
+ if(key(k))
+ return actions.value(k);
+ else
+ return QString();
+}
+
+void QFxKeyActionsPrivate::setKeyExpr(Qt::Key k, const QString &expr)
+{
+ if(expr.isEmpty()) {
+ if(key(k)) {
+ actions.remove(k);
+ setKey(k, false);
+ }
+ } else {
+ actions.insert(k, expr);
+ setKey(k);
+ }
+}
+
+/*!
+ \qmlproperty bool KeyActions::enabled
+
+ Enables or disables KeyActions' key handling. When not enabled, the
+ KeyActions instance does not respond to any key presses. The element is
+ enabled by default.
+*/
+bool QFxKeyActions::enabled() const
+{
+ return d->enabled;
+}
+
+void QFxKeyActions::setEnabled(bool e)
+{
+ if(d->enabled == e)
+ return;
+
+ d->enabled = e;
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty string KeyActions::keyA
+ \qmlproperty string KeyActions::keyB
+ \qmlproperty string KeyActions::keyC
+ \qmlproperty ... KeyActions::...
+ \qmlproperty string KeyActions::keyY
+ \qmlproperty string KeyActions::keyZ
+
+ The action to take for the given letter.
+
+ The following example sets actions for the 'c' and 'x' keys.
+ \code
+ <KeyActions keyC="print('c is for cookie')" keyX="print('I like cookies')" />
+ \endcode
+*/
+QString QFxKeyActions::key_A() const
+{
+ return d->keyExpr(Qt::Key_A);
+}
+
+void QFxKeyActions::setKey_A(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_A, s);
+}
+
+QString QFxKeyActions::key_B() const
+{
+ return d->keyExpr(Qt::Key_B);
+}
+
+void QFxKeyActions::setKey_B(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_B, s);
+}
+
+QString QFxKeyActions::key_C() const
+{
+ return d->keyExpr(Qt::Key_C);
+}
+
+void QFxKeyActions::setKey_C(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_C, s);
+}
+
+QString QFxKeyActions::key_D() const
+{
+ return d->keyExpr(Qt::Key_D);
+}
+
+void QFxKeyActions::setKey_D(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_D, s);
+}
+
+QString QFxKeyActions::key_E() const
+{
+ return d->keyExpr(Qt::Key_E);
+}
+
+void QFxKeyActions::setKey_E(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_E, s);
+}
+
+QString QFxKeyActions::key_F() const
+{
+ return d->keyExpr(Qt::Key_F);
+}
+
+void QFxKeyActions::setKey_F(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_F, s);
+}
+
+QString QFxKeyActions::key_G() const
+{
+ return d->keyExpr(Qt::Key_G);
+}
+
+void QFxKeyActions::setKey_G(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_G, s);
+}
+
+QString QFxKeyActions::key_H() const
+{
+ return d->keyExpr(Qt::Key_H);
+}
+
+void QFxKeyActions::setKey_H(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_H, s);
+}
+
+QString QFxKeyActions::key_I() const
+{
+ return d->keyExpr(Qt::Key_I);
+}
+
+void QFxKeyActions::setKey_I(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_I, s);
+}
+
+QString QFxKeyActions::key_J() const
+{
+ return d->keyExpr(Qt::Key_J);
+}
+
+void QFxKeyActions::setKey_J(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_J, s);
+}
+
+QString QFxKeyActions::key_K() const
+{
+ return d->keyExpr(Qt::Key_K);
+}
+
+void QFxKeyActions::setKey_K(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_K, s);
+}
+
+QString QFxKeyActions::key_L() const
+{
+ return d->keyExpr(Qt::Key_L);
+}
+
+void QFxKeyActions::setKey_L(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_L, s);
+}
+
+QString QFxKeyActions::key_M() const
+{
+ return d->keyExpr(Qt::Key_M);
+}
+
+void QFxKeyActions::setKey_M(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_M, s);
+}
+
+QString QFxKeyActions::key_N() const
+{
+ return d->keyExpr(Qt::Key_N);
+}
+
+void QFxKeyActions::setKey_N(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_N, s);
+}
+
+QString QFxKeyActions::key_O() const
+{
+ return d->keyExpr(Qt::Key_O);
+}
+
+void QFxKeyActions::setKey_O(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_O, s);
+}
+
+QString QFxKeyActions::key_P() const
+{
+ return d->keyExpr(Qt::Key_P);
+}
+
+void QFxKeyActions::setKey_P(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_P, s);
+}
+
+QString QFxKeyActions::key_Q() const
+{
+ return d->keyExpr(Qt::Key_Q);
+}
+
+void QFxKeyActions::setKey_Q(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Q, s);
+}
+
+QString QFxKeyActions::key_R() const
+{
+ return d->keyExpr(Qt::Key_R);
+}
+
+void QFxKeyActions::setKey_R(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_R, s);
+}
+
+QString QFxKeyActions::key_S() const
+{
+ return d->keyExpr(Qt::Key_S);
+}
+
+void QFxKeyActions::setKey_S(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_S, s);
+}
+
+QString QFxKeyActions::key_T() const
+{
+ return d->keyExpr(Qt::Key_T);
+}
+
+void QFxKeyActions::setKey_T(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_T, s);
+}
+
+QString QFxKeyActions::key_U() const
+{
+ return d->keyExpr(Qt::Key_U);
+}
+
+void QFxKeyActions::setKey_U(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_U, s);
+}
+
+QString QFxKeyActions::key_V() const
+{
+ return d->keyExpr(Qt::Key_V);
+}
+
+void QFxKeyActions::setKey_V(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_V, s);
+}
+
+QString QFxKeyActions::key_W() const
+{
+ return d->keyExpr(Qt::Key_W);
+}
+
+void QFxKeyActions::setKey_W(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_W, s);
+}
+
+QString QFxKeyActions::key_X() const
+{
+ return d->keyExpr(Qt::Key_X);
+}
+
+void QFxKeyActions::setKey_X(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_X, s);
+}
+
+QString QFxKeyActions::key_Y() const
+{
+ return d->keyExpr(Qt::Key_Y);
+}
+
+void QFxKeyActions::setKey_Y(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Y, s);
+}
+
+QString QFxKeyActions::key_Z() const
+{
+ return d->keyExpr(Qt::Key_Z);
+}
+
+void QFxKeyActions::setKey_Z(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Z, s);
+}
+
+
+/*!
+ \qmlproperty string KeyActions::leftArrow
+ \qmlproperty string KeyActions::rightArrow
+ \qmlproperty string KeyActions::upArrow
+ \qmlproperty string KeyActions::downArrow
+
+ The action to take for the given arrow key.
+
+ The following example sets actions for the left and right arrow keys.
+ \code
+ <KeyActions leftArrow="print('You pressed left')" rightArrow="print('You pressed right')" />
+ \endcode
+*/
+
+QString QFxKeyActions::key_Left() const
+{
+ return d->keyExpr(Qt::Key_Left);
+}
+
+void QFxKeyActions::setKey_Left(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Left, s);
+}
+
+QString QFxKeyActions::key_Right() const
+{
+ return d->keyExpr(Qt::Key_Right);
+}
+
+void QFxKeyActions::setKey_Right(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Right, s);
+}
+
+QString QFxKeyActions::key_Up() const
+{
+ return d->keyExpr(Qt::Key_Up);
+}
+
+void QFxKeyActions::setKey_Up(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Up, s);
+}
+
+QString QFxKeyActions::key_Down() const
+{
+ return d->keyExpr(Qt::Key_Down);
+}
+
+void QFxKeyActions::setKey_Down(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Down, s);
+}
+
+/*!
+ \qmlproperty string KeyActions::digit0
+ \qmlproperty string KeyActions::digit1
+ \qmlproperty string KeyActions::digit2
+ \qmlproperty ... KeyActions::...
+ \qmlproperty string KeyActions::digit9
+
+ The action to take for the given number key.
+
+ The following example sets actions for the '5' and '6' keys.
+ \code
+ <KeyActions digit5="print('5 is a prime number')" digit6="print('6 is a composite number')" />
+ \endcode
+*/
+
+QString QFxKeyActions::key_0() const
+{
+ return d->keyExpr(Qt::Key_0);
+}
+
+void QFxKeyActions::setKey_0(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_0, s);
+}
+
+QString QFxKeyActions::key_1() const
+{
+ return d->keyExpr(Qt::Key_1);
+}
+
+void QFxKeyActions::setKey_1(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_1, s);
+}
+
+QString QFxKeyActions::key_2() const
+{
+ return d->keyExpr(Qt::Key_2);
+}
+
+void QFxKeyActions::setKey_2(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_2, s);
+}
+
+QString QFxKeyActions::key_3() const
+{
+ return d->keyExpr(Qt::Key_3);
+}
+
+void QFxKeyActions::setKey_3(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_3, s);
+}
+
+QString QFxKeyActions::key_4() const
+{
+ return d->keyExpr(Qt::Key_4);
+}
+
+void QFxKeyActions::setKey_4(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_4, s);
+}
+
+QString QFxKeyActions::key_5() const
+{
+ return d->keyExpr(Qt::Key_5);
+}
+
+void QFxKeyActions::setKey_5(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_5, s);
+}
+
+QString QFxKeyActions::key_6() const
+{
+ return d->keyExpr(Qt::Key_6);
+}
+
+void QFxKeyActions::setKey_6(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_6, s);
+}
+
+QString QFxKeyActions::key_7() const
+{
+ return d->keyExpr(Qt::Key_7);
+}
+
+void QFxKeyActions::setKey_7(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_7, s);
+}
+
+QString QFxKeyActions::key_8() const
+{
+ return d->keyExpr(Qt::Key_8);
+}
+
+void QFxKeyActions::setKey_8(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_8, s);
+}
+
+QString QFxKeyActions::key_9() const
+{
+ return d->keyExpr(Qt::Key_9);
+}
+
+void QFxKeyActions::setKey_9(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_9, s);
+}
+
+QString QFxKeyActions::key_Asterisk() const
+{
+ return d->keyExpr(Qt::Key_Asterisk);
+}
+
+void QFxKeyActions::setKey_Asterisk(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Asterisk, s);
+}
+
+QString QFxKeyActions::key_Escape() const
+{
+ return d->keyExpr(Qt::Key_Escape);
+}
+
+void QFxKeyActions::setKey_Escape(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Escape, s);
+}
+
+QString QFxKeyActions::key_Return() const
+{
+ return d->keyExpr(Qt::Key_Return);
+}
+
+void QFxKeyActions::setKey_Return(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Return, s);
+}
+
+QString QFxKeyActions::key_Enter() const
+{
+ return d->keyExpr(Qt::Key_Enter);
+}
+
+void QFxKeyActions::setKey_Enter(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Enter, s);
+}
+
+QString QFxKeyActions::key_Delete() const
+{
+ return d->keyExpr(Qt::Key_Delete);
+}
+
+void QFxKeyActions::setKey_Delete(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Delete, s);
+}
+
+QString QFxKeyActions::key_Space() const
+{
+ return d->keyExpr(Qt::Key_Space);
+}
+
+void QFxKeyActions::setKey_Space(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Space, s);
+}
+
+/*!
+ \qmlproperty string KeyActions::escape
+ \qmlproperty string KeyActions::return
+ \qmlproperty string KeyActions::enter
+ \qmlproperty string KeyActions::delete
+ \qmlproperty string KeyActions::space
+
+ The action to take for the given utility key.
+
+ The following example sets an action for the space key.
+ \code
+ <KeyActions space="print('Space pressed')" />
+ \endcode
+*/
+
+/*!
+ \qmlproperty string KeyActions::back
+ \qmlproperty string KeyActions::select
+ \qmlproperty string KeyActions::yes
+ \qmlproperty string KeyActions::no
+ \qmlproperty string KeyActions::context1
+ \qmlproperty string KeyActions::context2
+ \qmlproperty string KeyActions::context3
+ \qmlproperty string KeyActions::context4
+ \qmlproperty string KeyActions::call
+ \qmlproperty string KeyActions::hangup
+ \qmlproperty string KeyActions::flip
+
+ The action to take for the given device key.
+
+ The following example sets an action for the hangup key.
+ \code
+ <KeyActions hangup="print('Go away now')" />
+ \endcode
+*/
+
+QString QFxKeyActions::key_Back() const
+{
+ return d->keyExpr(Qt::Key_Back);
+}
+
+void QFxKeyActions::setKey_Back(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Back, s);
+}
+
+QString QFxKeyActions::key_Select() const
+{
+ return d->keyExpr(Qt::Key_Select);
+}
+
+void QFxKeyActions::setKey_Select(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Select, s);
+}
+
+QString QFxKeyActions::key_Yes() const
+{
+ return d->keyExpr(Qt::Key_Yes);
+}
+
+void QFxKeyActions::setKey_Yes(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Yes, s);
+}
+
+QString QFxKeyActions::key_No() const
+{
+ return d->keyExpr(Qt::Key_No);
+}
+
+void QFxKeyActions::setKey_No(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_No, s);
+}
+
+QString QFxKeyActions::key_Context1() const
+{
+ return d->keyExpr(Qt::Key_Context1);
+}
+
+void QFxKeyActions::setKey_Context1(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Context1, s);
+}
+
+QString QFxKeyActions::key_Context2() const
+{
+ return d->keyExpr(Qt::Key_Context2);
+}
+
+void QFxKeyActions::setKey_Context2(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Context2, s);
+}
+
+QString QFxKeyActions::key_Context3() const
+{
+ return d->keyExpr(Qt::Key_Context3);
+}
+
+void QFxKeyActions::setKey_Context3(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Context3, s);
+}
+
+QString QFxKeyActions::key_Context4() const
+{
+ return d->keyExpr(Qt::Key_Context4);
+}
+
+void QFxKeyActions::setKey_Context4(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Context4, s);
+}
+
+QString QFxKeyActions::key_Call() const
+{
+ return d->keyExpr(Qt::Key_Call);
+}
+
+void QFxKeyActions::setKey_Call(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Call, s);
+}
+
+QString QFxKeyActions::key_Hangup() const
+{
+ return d->keyExpr(Qt::Key_Hangup);
+}
+
+void QFxKeyActions::setKey_Hangup(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Hangup, s);
+}
+
+QString QFxKeyActions::key_Flip() const
+{
+ return d->keyExpr(Qt::Key_Flip);
+}
+
+void QFxKeyActions::setKey_Flip(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_Flip, s);
+}
+
+/*!
+ \qmlproperty string KeyActions::any
+
+ The action to take for any key not otherwise handled.
+*/
+QString QFxKeyActions::key_Any() const
+{
+ return d->keyExpr(Qt::Key_unknown);
+}
+
+void QFxKeyActions::setKey_Any(const QString &s)
+{
+ d->setKeyExpr(Qt::Key_unknown, s);
+}
+
+void QFxKeyActions::keyPressEvent(QKeyEvent *event)
+{
+ Qt::Key key = (Qt::Key)event->key();
+ if(d->enabled && d->key(key)) {
+ QmlExpression b(itemContext(), d->action(key),
+ this, false);
+ b.value();
+ event->accept();
+ } else {
+ QFxItem::keyPressEvent(event);
+ }
+}
+
+void QFxKeyActions::keyReleaseEvent(QKeyEvent *event)
+{
+ Qt::Key key = (Qt::Key)event->key();
+ if(d->enabled && d->key(key)) {
+ event->accept();
+ } else {
+ QFxItem::keyReleaseEvent(event);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxkeyactions.h b/src/declarative/fx/qfxkeyactions.h
new file mode 100644
index 0000000..7ad323a
--- /dev/null
+++ b/src/declarative/fx/qfxkeyactions.h
@@ -0,0 +1,319 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXKEYACTIONS_H
+#define QFXKEYACTIONS_H
+
+#include <qfxglobal.h>
+#include <QObject>
+#include <qml.h>
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxKeyActionsPrivate;
+class Q_DECLARATIVE_EXPORT QFxKeyActions : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged)
+ Q_PROPERTY(QString keyA READ key_A WRITE setKey_A)
+ Q_PROPERTY(QString keyB READ key_B WRITE setKey_B)
+ Q_PROPERTY(QString keyC READ key_C WRITE setKey_C)
+ Q_PROPERTY(QString keyD READ key_D WRITE setKey_D)
+ Q_PROPERTY(QString keyE READ key_E WRITE setKey_E)
+ Q_PROPERTY(QString keyF READ key_F WRITE setKey_F)
+ Q_PROPERTY(QString keyG READ key_G WRITE setKey_G)
+ Q_PROPERTY(QString keyH READ key_H WRITE setKey_H)
+ Q_PROPERTY(QString keyI READ key_I WRITE setKey_I)
+ Q_PROPERTY(QString keyJ READ key_J WRITE setKey_J)
+ Q_PROPERTY(QString keyK READ key_K WRITE setKey_K)
+ Q_PROPERTY(QString keyL READ key_L WRITE setKey_L)
+ Q_PROPERTY(QString keyM READ key_M WRITE setKey_M)
+ Q_PROPERTY(QString keyN READ key_N WRITE setKey_N)
+ Q_PROPERTY(QString keyO READ key_O WRITE setKey_O)
+ Q_PROPERTY(QString keyP READ key_P WRITE setKey_P)
+ Q_PROPERTY(QString keyQ READ key_Q WRITE setKey_Q)
+ Q_PROPERTY(QString keyR READ key_R WRITE setKey_R)
+ Q_PROPERTY(QString keyS READ key_S WRITE setKey_S)
+ Q_PROPERTY(QString keyT READ key_T WRITE setKey_T)
+ Q_PROPERTY(QString keyU READ key_U WRITE setKey_U)
+ Q_PROPERTY(QString keyV READ key_V WRITE setKey_V)
+ Q_PROPERTY(QString keyW READ key_W WRITE setKey_W)
+ Q_PROPERTY(QString keyX READ key_X WRITE setKey_X)
+ Q_PROPERTY(QString keyY READ key_Y WRITE setKey_Y)
+ Q_PROPERTY(QString keyZ READ key_Z WRITE setKey_Z)
+ Q_PROPERTY(QString leftArrow READ key_Left WRITE setKey_Left)
+ Q_PROPERTY(QString rightArrow READ key_Right WRITE setKey_Right)
+ Q_PROPERTY(QString upArrow READ key_Up WRITE setKey_Up)
+ Q_PROPERTY(QString downArrow READ key_Down WRITE setKey_Down)
+ Q_PROPERTY(QString digit0 READ key_0 WRITE setKey_0)
+ Q_PROPERTY(QString digit1 READ key_1 WRITE setKey_1)
+ Q_PROPERTY(QString digit2 READ key_2 WRITE setKey_2)
+ Q_PROPERTY(QString digit3 READ key_3 WRITE setKey_3)
+ Q_PROPERTY(QString digit4 READ key_4 WRITE setKey_4)
+ Q_PROPERTY(QString digit5 READ key_5 WRITE setKey_5)
+ Q_PROPERTY(QString digit6 READ key_6 WRITE setKey_6)
+ Q_PROPERTY(QString digit7 READ key_7 WRITE setKey_7)
+ Q_PROPERTY(QString digit8 READ key_8 WRITE setKey_8)
+ Q_PROPERTY(QString digit9 READ key_9 WRITE setKey_9)
+ Q_PROPERTY(QString asterisk READ key_Asterisk WRITE setKey_Asterisk)
+ Q_PROPERTY(QString escape READ key_Escape WRITE setKey_Escape)
+ Q_PROPERTY(QString return READ key_Return WRITE setKey_Return)
+ Q_PROPERTY(QString enter READ key_Enter WRITE setKey_Enter)
+ Q_PROPERTY(QString delete READ key_Delete WRITE setKey_Delete)
+ Q_PROPERTY(QString space READ key_Space WRITE setKey_Space)
+ Q_PROPERTY(QString back READ key_Back WRITE setKey_Back)
+ Q_PROPERTY(QString select READ key_Select WRITE setKey_Select)
+ Q_PROPERTY(QString yes READ key_Yes WRITE setKey_Yes)
+ Q_PROPERTY(QString no READ key_No WRITE setKey_No)
+ Q_PROPERTY(QString context1 READ key_Context1 WRITE setKey_Context1)
+ Q_PROPERTY(QString context2 READ key_Context2 WRITE setKey_Context2)
+ Q_PROPERTY(QString context3 READ key_Context3 WRITE setKey_Context3)
+ Q_PROPERTY(QString context4 READ key_Context4 WRITE setKey_Context4)
+ Q_PROPERTY(QString call READ key_Call WRITE setKey_Call)
+ Q_PROPERTY(QString hangup READ key_Hangup WRITE setKey_Hangup)
+ Q_PROPERTY(QString flip READ key_Flip WRITE setKey_Flip)
+ Q_PROPERTY(QString any READ key_Any WRITE setKey_Any)
+
+public:
+ QFxKeyActions(QFxItem *parent=0);
+ virtual ~QFxKeyActions();
+
+ bool enabled() const;
+ void setEnabled(bool);
+
+ QString key_A() const;
+ void setKey_A(const QString &);
+
+ QString key_B() const;
+ void setKey_B(const QString &);
+
+ QString key_C() const;
+ void setKey_C(const QString &);
+
+ QString key_D() const;
+ void setKey_D(const QString &);
+
+ QString key_E() const;
+ void setKey_E(const QString &);
+
+ QString key_F() const;
+ void setKey_F(const QString &);
+
+ QString key_G() const;
+ void setKey_G(const QString &);
+
+ QString key_H() const;
+ void setKey_H(const QString &);
+
+ QString key_I() const;
+ void setKey_I(const QString &);
+
+ QString key_J() const;
+ void setKey_J(const QString &);
+
+ QString key_K() const;
+ void setKey_K(const QString &);
+
+ QString key_L() const;
+ void setKey_L(const QString &);
+
+ QString key_M() const;
+ void setKey_M(const QString &);
+
+ QString key_N() const;
+ void setKey_N(const QString &);
+
+ QString key_O() const;
+ void setKey_O(const QString &);
+
+ QString key_P() const;
+ void setKey_P(const QString &);
+
+ QString key_Q() const;
+ void setKey_Q(const QString &);
+
+ QString key_R() const;
+ void setKey_R(const QString &);
+
+ QString key_S() const;
+ void setKey_S(const QString &);
+
+ QString key_T() const;
+ void setKey_T(const QString &);
+
+ QString key_U() const;
+ void setKey_U(const QString &);
+
+ QString key_V() const;
+ void setKey_V(const QString &);
+
+ QString key_W() const;
+ void setKey_W(const QString &);
+
+ QString key_X() const;
+ void setKey_X(const QString &);
+
+ QString key_Y() const;
+ void setKey_Y(const QString &);
+
+ QString key_Z() const;
+ void setKey_Z(const QString &);
+
+ QString key_Left() const;
+ void setKey_Left(const QString &);
+
+ QString key_Right() const;
+ void setKey_Right(const QString &);
+
+ QString key_Up() const;
+ void setKey_Up(const QString &);
+
+ QString key_Down() const;
+ void setKey_Down(const QString &);
+
+ QString key_0() const;
+ void setKey_0(const QString &);
+
+ QString key_1() const;
+ void setKey_1(const QString &);
+
+ QString key_2() const;
+ void setKey_2(const QString &);
+
+ QString key_3() const;
+ void setKey_3(const QString &);
+
+ QString key_4() const;
+ void setKey_4(const QString &);
+
+ QString key_5() const;
+ void setKey_5(const QString &);
+
+ QString key_6() const;
+ void setKey_6(const QString &);
+
+ QString key_7() const;
+ void setKey_7(const QString &);
+
+ QString key_8() const;
+ void setKey_8(const QString &);
+
+ QString key_9() const;
+ void setKey_9(const QString &);
+
+ QString key_Asterisk() const;
+ void setKey_Asterisk(const QString &);
+
+ QString key_Escape() const;
+ void setKey_Escape(const QString &);
+
+ QString key_Return() const;
+ void setKey_Return(const QString &);
+
+ QString key_Enter() const;
+ void setKey_Enter(const QString &);
+
+ QString key_Delete() const;
+ void setKey_Delete(const QString &);
+
+ QString key_Space() const;
+ void setKey_Space(const QString &);
+
+ QString key_Back() const;
+ void setKey_Back(const QString &);
+
+ QString key_Select() const;
+ void setKey_Select(const QString &);
+
+ QString key_Yes() const;
+ void setKey_Yes(const QString &);
+
+ QString key_No() const;
+ void setKey_No(const QString &);
+
+ QString key_Context1() const;
+ void setKey_Context1(const QString &);
+
+ QString key_Context2() const;
+ void setKey_Context2(const QString &);
+
+ QString key_Context3() const;
+ void setKey_Context3(const QString &);
+
+ QString key_Context4() const;
+ void setKey_Context4(const QString &);
+
+ QString key_Call() const;
+ void setKey_Call(const QString &);
+
+ QString key_Hangup() const;
+ void setKey_Hangup(const QString &);
+
+ QString key_Flip() const;
+ void setKey_Flip(const QString &);
+
+ QString key_Any() const;
+ void setKey_Any(const QString &);
+
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+
+Q_SIGNALS:
+ void enabledChanged();
+
+private:
+ Q_DISABLE_COPY(QFxKeyActions)
+ QFxKeyActionsPrivate *d;
+};
+
+QML_DECLARE_TYPE(QFxKeyActions);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXKEYACTIONS_H
diff --git a/src/declarative/fx/qfxkeyproxy.cpp b/src/declarative/fx/qfxkeyproxy.cpp
new file mode 100644
index 0000000..8598ad6
--- /dev/null
+++ b/src/declarative/fx/qfxkeyproxy.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxkeyproxy.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxKeyProxy,KeyProxy);
+
+/*!
+ \qmlclass KeyProxy
+ \brief The KeyProxy element proxies key presses to a number of other elements.
+ \inherits Item
+
+*/
+
+/*!
+ \internal
+ \class QFxKeyProxy
+ \brief The QFxKeyProxy class proxies key presses to a number of other elements.
+ \ingroup utility
+*/
+
+class QFxKeyProxyPrivate
+{
+public:
+ QList<QFxItem *> targets;
+};
+
+QFxKeyProxy::QFxKeyProxy(QFxItem *parent)
+: QFxItem(parent), d(new QFxKeyProxyPrivate)
+{
+}
+
+QFxKeyProxy::~QFxKeyProxy()
+{
+ delete d; d = 0;
+}
+
+/*!
+ \qmlproperty list<Item> KeyProxy::targets
+
+ The proxy targets.
+*/
+
+/*!
+ \property QFxKeyProxy::targets
+ \brief the proxy targets.
+*/
+
+QList<QFxItem *> *QFxKeyProxy::targets() const
+{
+ return &d->targets;
+}
+
+void QFxKeyProxy::keyPressEvent(QKeyEvent *e)
+{
+ for(int ii = 0; ii < d->targets.count(); ++ii) {
+ QSimpleCanvasItem *i = d->targets.at(ii);
+ if(i)
+ i->keyPressEvent(e);
+ if(e->isAccepted())
+ return;
+ }
+}
+
+void QFxKeyProxy::keyReleaseEvent(QKeyEvent *e)
+{
+ for(int ii = 0; ii < d->targets.count(); ++ii) {
+ QSimpleCanvasItem *i = d->targets.at(ii);
+ if(i)
+ i->keyReleaseEvent(e);
+ if(e->isAccepted())
+ return;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxkeyproxy.h b/src/declarative/fx/qfxkeyproxy.h
new file mode 100644
index 0000000..ae5fce4
--- /dev/null
+++ b/src/declarative/fx/qfxkeyproxy.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXKEYPROXY_H
+#define QFXKEYPROXY_H
+
+#include <qfxitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxKeyProxyPrivate;
+class Q_DECLARATIVE_EXPORT QFxKeyProxy : public QFxItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QList<QFxItem *> *targets READ targets)
+public:
+ QFxKeyProxy(QFxItem *parent=0);
+ virtual ~QFxKeyProxy();
+
+ QList<QFxItem *> *targets() const;
+
+protected:
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+
+private:
+ Q_DISABLE_COPY(QFxKeyProxy)
+ QFxKeyProxyPrivate *d;
+};
+
+QML_DECLARE_TYPE(QFxKeyProxy);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXKEYPROXY_H
diff --git a/src/declarative/fx/qfxlayouts.cpp b/src/declarative/fx/qfxlayouts.cpp
new file mode 100644
index 0000000..455b8a5
--- /dev/null
+++ b/src/declarative/fx/qfxlayouts.cpp
@@ -0,0 +1,1027 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QCoreApplication>
+#include "qml.h"
+#include "qmlstate.h"
+#include "qmlstategroup.h"
+#include "qmlstateoperations.h"
+#include "qfxperf.h"
+#include "qfxlayouts.h"
+#include "qfxlayouts_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QFxBaseLayout
+ \brief The QFxBaseLayout class provides a base for QFx layouts.
+
+ To create a QFx Layout, simple subclass QFxBaseLayout and implement
+ doLayout(), which is automatically called when the layout might need
+ updating.
+
+ It is strongly recommended that in your implementation of doLayout()
+ that you use the move, remove and add transitions when those conditions
+ arise.
+
+ \ingroup layouts
+*/
+QFxBaseLayout::QFxBaseLayout(AutoUpdateType at, QFxItem *parent)
+ : QFxItem(*(new QFxBaseLayoutPrivate), parent)
+{
+ Q_D(QFxBaseLayout);
+ d->init(at);
+}
+
+QFxBaseLayout::QFxBaseLayout(QFxBaseLayoutPrivate &dd, AutoUpdateType at, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxBaseLayout);
+ d->init(at);
+}
+
+/*!
+ \property QFxBaseLayout::spacing
+ \brief the amount of spacing between items (in px)
+
+ Note that the subclass is repsonsible for ensuring this.
+*/
+int QFxBaseLayout::spacing() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->_spacing;
+}
+
+void QFxBaseLayout::setSpacing(int s)
+{
+ Q_D(QFxBaseLayout);
+ if(s==d->_spacing)
+ return;
+ d->_spacing = s;
+ preLayout();
+}
+
+/*!
+ \property QFxBaseLayout::margin
+ \brief the size of the margin around all items (in px)
+
+*/
+int QFxBaseLayout::margin() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->_margin;
+}
+
+void QFxBaseLayout::setMargin(int s)
+{
+ Q_D(QFxBaseLayout);
+ if(s==d->_margin)
+ return;
+ d->_margin = s;
+ preLayout();
+}
+
+
+/*!
+ \property QFxBaseLayout::move
+ \brief the transition when moving an item.
+
+ \code
+ <BaseLayout id="layout" y="0">
+ <move>
+ <Transition>
+ <NumericAnimation properties="y" ease="easeOutBounce" />
+ </Transition>
+ </move>
+ </BaseLayout>
+ \endcode
+*/
+QmlTransition *QFxBaseLayout::move() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->moveTransition;
+}
+
+void QFxBaseLayout::setMove(QmlTransition *mt)
+{
+ Q_D(QFxBaseLayout);
+ d->moveTransition = mt;
+}
+
+/*!
+ \property QFxBaseLayout::add
+ \brief the transition when adding an item.
+
+ \code
+ <BaseLayout id="layout" y="0">
+ <add>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="0" to="1" duration="500" />
+ </Transition>
+ </add>
+ </BaseLayout>
+ \endcode
+*/
+QmlTransition *QFxBaseLayout::add() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->addTransition;
+}
+
+void QFxBaseLayout::setAdd(QmlTransition *add)
+{
+ Q_D(QFxBaseLayout);
+ d->addTransition = add;
+}
+
+
+/*!
+ \property QFxBaseLayout::remove
+ \brief the transition when removing an item.
+
+ Note that the item may be 'removed' because its opacity is zero. This can make certain
+ transitions difficult to see.
+ \code
+ <BaseLayout id="layout" y="0">
+ <remove>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="1" to="0" duration="500" />
+ </Transition>
+ </remove>
+ </BaseLayout>
+ \endcode
+*/
+QmlTransition *QFxBaseLayout::remove() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->removeTransition;
+}
+
+void QFxBaseLayout::setRemove(QmlTransition *remove)
+{
+ Q_D(QFxBaseLayout);
+ d->removeTransition = remove;
+}
+
+/*!
+ \property QFxBaseLayout::item
+
+ The item that is currently being laid out. Used to target transitions that apply
+ only to the item being laid out, such as in the add transition.
+*/
+
+QFxItem *QFxBaseLayout::layoutItem() const
+{
+ Q_D(const QFxBaseLayout);
+ return d->_layoutItem;
+}
+
+/*!
+ \internal
+*/
+void QFxBaseLayout::setLayoutItem(QFxItem *li)
+{
+ Q_D(QFxBaseLayout);
+ if(li == d->_layoutItem)
+ return;
+ d->_layoutItem = li;
+ emit layoutItemChanged();
+}
+
+void QFxBaseLayout::componentComplete()
+{
+ QFxItem::componentComplete();
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::BaseLayoutComponentComplete> cc;
+#endif
+ preLayout();
+}
+
+void QFxBaseLayout::childrenChanged()
+{
+ preLayout();
+}
+
+bool QFxBaseLayout::event(QEvent *e)
+{
+ Q_D(QFxBaseLayout);
+ if(e->type() == QEvent::User) {
+ d->_ep = false;
+ d->_stableItems += d->_newItems;
+ d->_leavingItems.clear();
+ d->_newItems.clear();
+ return true;
+ }
+ return QFxItem::event(e);
+}
+
+/*!
+ Items that have just been added to the layout. This includes invisible items
+ that have turned visible.
+*/
+QSet<QFxItem *>* QFxBaseLayout::newItems()
+{
+ Q_D(QFxBaseLayout);
+ return &d->_newItems;
+}
+
+/*!
+ Items that are visible in the layout, not including ones that have just been added.
+*/
+QSet<QFxItem *>* QFxBaseLayout::items()
+{
+ Q_D(QFxBaseLayout);
+ return &d->_stableItems;
+}
+
+/*!
+ Items that have just left the layout. This includes visible items
+ that have turned invisible.
+*/
+QSet<QFxItem *>* QFxBaseLayout::leavingItems()
+{
+ Q_D(QFxBaseLayout);
+ return &d->_leavingItems;
+}
+
+void QFxBaseLayout::preLayout()
+{
+ Q_D(QFxBaseLayout);
+ if(!isComponentComplete() || d->_movingItem)
+ return;
+
+ if(!d->_ep) {
+ d->_ep = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ }
+ if(d->stateGroup) {
+ delete d->stateGroup; d->stateGroup = 0;
+ }
+ QSet<QFxItem *> allItems;
+ for(int ii = 0; ii < this->QSimpleCanvasItem::children().count(); ++ii) {
+ QFxItem *child = qobject_cast<QFxItem *>(this->QSimpleCanvasItem::children().at(ii));
+ if(!child)
+ continue;
+ if(!d->_items.contains(child)){
+ QObject::connect(child, SIGNAL(visibleChanged()),
+ this, SLOT(preLayout()));
+ QObject::connect(child, SIGNAL(heightChanged()),
+ this, SLOT(preLayout()));
+ QObject::connect(child, SIGNAL(widthChanged()),
+ this, SLOT(preLayout()));
+ d->_items += child;
+ }
+ if(!child->isVisible()){
+ if(d->_stableItems.contains(child)){
+ d->_leavingItems += child;
+ d->_stableItems -= child;
+ }
+ }else if(!d->_stableItems.contains(child)){
+ d->_newItems+=child;
+ }
+ allItems += child;
+ }
+ QSet<QFxItem *> deletedItems = d->_items - allItems;
+ foreach(QFxItem *child, d->_items){
+ if(!allItems.contains(child)){
+ if(!deletedItems.contains(child)) {
+ QObject::disconnect(child, SIGNAL(visibleChanged()),
+ this, SLOT(preLayout()));
+ QObject::disconnect(child, SIGNAL(heightChanged()),
+ this, SLOT(preLayout()));
+ QObject::disconnect(child, SIGNAL(widthChanged()),
+ this, SLOT(preLayout()));
+ }
+ d->_items -= child;
+ }
+ }
+ d->_animated.clear();
+ doLayout();
+ //Set the layout's size to be the rect containing all children
+ //Also set the margin
+ qreal width=0;
+ qreal height=0;
+ foreach(QFxItem *item, d->_items){
+ if(item->isVisible()){
+ if(!d->_animated.contains(item)){
+ setMovingItem(item);
+ item->setPos(QPointF(item->x()+d->_margin, item->y()+d->_margin));
+ setMovingItem(0);
+ }
+ width = qMax(width, item->x() + item->width());
+ height = qMax(height, item->y() + item->height());
+ }
+ }
+ width += d->_margin;
+ height+= d->_margin;
+
+ if(d->aut & Horizontal)
+ setWidth(int(width));
+ else
+ setImplicitWidth(itemParent()->width());
+ if(d->aut & Vertical)
+ setHeight(int(height));
+ else
+ setImplicitHeight(itemParent()->height());
+ setLayoutItem(0);
+}
+
+//###This should be considered to move more centrally, as it seems useful
+void QFxBaseLayout::applyTransition(const QList<QPair<QString, QVariant> >& changes,
+ QFxItem* target, QmlTransition* trans)
+{
+ Q_D(QFxBaseLayout);
+ if(!trans||!target)//TODO: if !trans, just apply changes
+ return;
+ setLayoutItem(target);
+ if(d->stateGroup)
+ delete d->stateGroup;
+ d->stateGroup = new QmlStateGroup(this);
+
+ QmlState *state = new QmlState;
+ *(d->stateGroup->statesProperty()) << state;
+ for(int ii=0; ii<changes.size(); ++ii){
+ QmlSetProperty *sp = new QmlSetProperty(state);
+ sp->setObject(target);
+ QVariant val = changes[ii].second;
+ if(d->_margin &&
+ (changes[ii].first == QLatin1String("x") || changes[ii].first == QLatin1String("y"))){
+ val = QVariant(val.toInt() + d->_margin);
+ }
+ sp->setValue(val);
+ sp->setProperty(changes[ii].first);
+ *state << sp;
+ }
+ state->apply(d->stateGroup, trans, 0);
+ d->_animated << target;
+}
+
+void QFxBaseLayout::setMovingItem(QFxItem *i)
+{
+ Q_D(QFxBaseLayout);
+ d->_movingItem = i;
+}
+
+/*!
+ Applies the layout's add transition to the \a target item.\a changes is a list of property,value
+ pairs which will be changed on the target using the add transition.
+*/
+void QFxBaseLayout::applyAdd(const QList<QPair<QString, QVariant> >& changes, QFxItem* target)
+{
+ applyTransition(changes,target, add());
+}
+
+/*!
+ Applies the layout's move transition to the \a target.\a changes is a list of property,value pairs
+ which will be changed on the target using the move transition.
+*/
+void QFxBaseLayout::applyMove(const QList<QPair<QString, QVariant> >& changes, QFxItem* target)
+{
+ applyTransition(changes,target, move());
+}
+
+/*!
+ Applies the layout's remove transition to the \a target item.\a changes is a list of
+ property,value pairs which will be changed on the target using the remove transition.
+*/
+void QFxBaseLayout::applyRemove(const QList<QPair<QString, QVariant> >& changes, QFxItem* target)
+{
+ applyTransition(changes,target, remove());
+}
+
+QML_DEFINE_TYPE(QFxVerticalLayout, VerticalLayout);
+/*!
+ \qmlclass VerticalLayout
+ \brief The VerticalLayout element arranges its children in a vertical layout.
+ \inherits Item
+
+ The VerticalLayout element arranges its child elements so that they are vertically
+ aligned and not overlapping. Spacing between items can be added, as can a margin around all the items.
+
+ The below example lays out differently shaped rectangles using a VerticalLayout.
+ \table
+ \row
+ \o \image verticalLayout_example.png
+ \o
+ \code
+ <VerticalLayout spacing="2">
+ <Rect color="red" width="50" height="50"/>
+ <Rect color="green" width="20" height="50"/>
+ <Rect color="blue" width="50" height="20"/>
+ </VerticalLayout>
+ \endcode
+ \endtable
+
+ VerticalLayout also provides for transitions to be set when items are added, moved,
+ or removed in the layout. Adding and removing apply both to elements which are deleted
+ or have their position in the document changed so as to no longer be children of the layout,
+ as well as to elements which have their opacity set to or from zero so as to appear or disappear.
+
+ \table
+ \row
+ \o \image verticalLayout_transition.gif
+ \o
+ \code
+ <VerticalLayout spacing="2">
+ ...
+ <remove>...</remove>
+ <add>...</add>
+ <move>...</move>
+ </VerticalLayout>
+ \endcode
+ \endtable
+
+
+*/
+/*!
+ \qmlproperty Transition VerticalLayout::remove
+ This property holds the transition to apply when removing an item from the layout.
+
+ Removed can mean that either the object has been deleted or reparented, and thus is now longer a child of the layout, or that the object has had its opacity set to zero, and thus is no longer visible.
+
+ Note that if the item counts as removed because its opacity is zero it will not be visible during the transition unless you set the opacity in the transition, like in the below example.
+
+ \table
+ \row
+ \o \image layout-remove.gif
+ \o
+ \code
+ <VerticalLayout id="layout">
+ <remove>
+ <Transition >
+ <NumericAnimation target="{layout.item}"
+ properties="opacity" from="1" to="0"
+ duration="500" />
+ </Transition>
+ </remove>
+ </VerticalLayout>
+ \endcode
+ \endtable
+
+*/
+/*!
+ \qmlproperty Transition VerticalLayout::add
+ This property holds the transition to be applied when adding an item to the layout.
+
+ Added can mean that either the object has been created or reparented, and thus is now a child or the layout, or that the object has had its opacity increased from zero, and thus is now visible.
+
+ \table
+ \row
+ \o \image layout-add.gif
+ \o
+ \code
+ <VerticalLayout id="layout">
+ <add>
+ <Transition >
+ <NumericAnimation target="{layout.item}"
+ properties="opacity" from="0" to="1"
+ duration="500" />
+ </Transition>
+ </add>
+ </VerticalLayout>
+ \endcode
+ \endtable
+
+*/
+/*!
+ \qmlproperty Transition VerticalLayout::move
+ This property holds the transition to apply when moving an item within the layout.
+
+ This can happen when other items are added or removed from the layout, or when items resize themselves.
+
+ \table
+ \row
+ \o \image layout-move.gif
+ \o
+ \code
+ <VerticalLayout id="layout">
+ <move>
+ <Transition>
+ <NumericAnimation properties="y" ease="easeOutBounce" />
+ </Transition>
+ </move>
+ </VerticalLayout>
+ \endcode
+ \endtable
+*/
+/*!
+ \qmlproperty Item VerticalLayout::item
+
+ The item that is currently being laid out. Used to target transitions that apply
+ only to the item being laid out, such as in the add transition.
+
+*/
+/*!
+ \qmlproperty int VerticalLayout::spacing
+ \qmlproperty int VerticalLayout::margin
+
+ spacing and margin allow you to control the empty space surrounding
+ items in layouts.
+
+ spacing is the amount in pixels left empty between each adjacent
+ item. margin is the amount in pixels which will be left empty
+ around the inside edge of the layout. Both default to 0.
+
+ The below example places a GridLayout containing a red, a blue and a
+ green rectangle on a gray background. The area the grid layout
+ occupies is colored white. The top layout has a spacing of 2 and a
+ margin of 5, the bottom layout has the defaults of no margin or
+ spacing.
+
+ \image spacing_a.png
+ \image spacing_b.png
+
+*/
+/*!
+ \internal
+ \class QFxVerticalLayout
+ \brief The QFxVerticalLayout class lines up items vertically.
+ \ingroup layouts
+*/
+QFxVerticalLayout::QFxVerticalLayout(QFxItem *parent)
+: QFxBaseLayout(Vertical, parent)
+{
+}
+
+void QFxVerticalLayout::doLayout()
+{
+ int voffset = 0;
+
+ foreach(QFxItem* item, *leavingItems()){
+ if(remove()){
+ QList<QPair<QString,QVariant> > changes;
+ applyRemove(changes, item);
+ }
+ }
+ for(int ii = 0; ii < this->QSimpleCanvasItem::children().count(); ++ii) {
+ QFxItem *child = qobject_cast<QFxItem *>(this->QSimpleCanvasItem::children().at(ii));
+ if(!child || !child->isVisible())
+ continue;
+
+ bool needMove = (child->y() != voffset || child->x());
+
+ QList<QPair<QString, QVariant> > changes;
+ changes << qMakePair(QString(QLatin1String("y")),QVariant(voffset));
+ changes << qMakePair(QString(QLatin1String("x")),QVariant(0));
+ if(needMove && items()->contains(child) && move()) {
+ applyMove(changes,child);
+ } else if(!items()->contains(child) && add()) {
+ applyAdd(changes,child);
+ } else if(needMove) {
+ setMovingItem(child);
+ child->setY(voffset);
+ setMovingItem(0);
+ child->setX(0);
+ }
+ voffset += child->height();
+ voffset += spacing();
+ }
+ setMovingItem(this);
+ setHeight(voffset);
+ setMovingItem(0);
+}
+
+QML_DEFINE_TYPE(QFxHorizontalLayout,HorizontalLayout);
+/*!
+ \qmlclass HorizontalLayout
+ \brief The HorizontalLayout element arranges its children in a horizontal layout.
+ \inherits Item
+
+ The HorizontalLayout element arranges its child elements so that they are horizontally aligned and not overlapping. Spacing can be added between the items, and a margin around all items can also be added. It also provides for transitions to be set when items are added, moved, or removed in the layout. Adding and removing apply both to elements which are deleted or have their position in the document changed so as to no longer be children of the layout, as well as to elements which have their opacity set to or from zero so as to appear or disappear.
+
+ The below example lays out differently shaped rectangles using a HorizontalLayout.
+ \code
+ <HorizontalLayout spacing="2">
+ <Rect color="red" width="50" height="50"/>
+ <Rect color="green" width="20" height="50"/>
+ <Rect color="blue" width="50" height="20"/>
+ </HorizontalLayout>
+ \endcode
+ \image horizontalLayout_example.png
+
+*/
+/*!
+ \qmlproperty Transition HorizontalLayout::remove
+ This property holds the transition to apply when removing an item from the layout.
+
+ Removed can mean that either the object has been deleted or reparented, and thus is now longer a child of the layout, or that the object has had its opacity set to zero, and thus is no longer visible.
+
+ Note that if the item counts as removed because its opacity is zero it will not be visible during the transition unless you set the opacity in the transition, like in the below example.
+
+ \code
+ <HorizontalLayout id="layout">
+ <remove>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="1" to="0" duration="500" />
+ </Transition>
+ </remove>
+ </HorizontalLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Transition HorizontalLayout::add
+ This property holds the transition to apply when adding an item to the layout.
+
+ Added can mean that either the object has been created or reparented, and thus is now a child or the layout, or that the object has had its opacity increased from zero, and thus is now visible.
+
+ \code
+ <HorizontalLayout id="layout">
+ <add>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="0" to="1" duration="500" />
+ </Transition>
+ </add>
+ </HorizontalLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Transition HorizontalLayout::move
+ This property holds the transition to apply when moving an item within the layout.
+
+ This can happen when other items are added or removed from the layout, or when items resize themselves.
+
+ \code
+ <HorizontalLayout id="layout">
+ <move>
+ <Transition>
+ <NumericAnimation properties="x" ease="easeOutBounce" />
+ </Transition>
+ </move>
+ </HorizontalLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Item HorizontalLayout::item
+
+ The item that is currently being laid out. Used to target transitions that apply
+ only to the item being laid out, such as in the add transition.
+
+*/
+/*!
+ \qmlproperty int HorizontalLayout::spacing
+
+ The spacing, in pixels, left empty between each adjacent item.
+*/
+/*!
+ \qmlproperty int HorizontalLayout::margin
+
+ The margin size, in pixels, which will be left empty around the inside edge of the layout.
+*/
+/*!
+ \qmlproperty int HorizontalLayout::spacing
+ \qmlproperty int HorizontalLayout::margin
+
+ spacing and margin allow you to control the empty space surrounding items in layouts.
+
+ spacing is the amount in pixels left empty between each adjacent item.
+ margin is the amount in pixels which will be left empty around the inside edge of the layout.
+ Both default to 0.
+
+ The below example places a GridLayout containing a red, a blue and a green rectangle on a gray background. The area the grid layout occupies is colored white. The top layout has a spacing of 2 and a margin of 5, the bottom layout has the defaults of no margin or spacing.
+
+ \image spacing_a.png
+ \image spacing_b.png
+
+*/
+/*!
+ \internal
+ \class QFxHorizontalLayout
+ \brief The QFxHorizontalLayout class lines up items horizontally.
+ \ingroup layouts
+*/
+QFxHorizontalLayout::QFxHorizontalLayout(QFxItem *parent)
+: QFxBaseLayout(Horizontal, parent)
+{
+}
+
+void QFxHorizontalLayout::doLayout()
+{
+ int hoffset = 0;
+
+ foreach(QFxItem* item, *leavingItems()){
+ if(remove()){
+ QList<QPair<QString,QVariant> > changes;
+ applyRemove(changes, item);
+ }
+ }
+ for(int ii = 0; ii < this->QSimpleCanvasItem::children().count(); ++ii) {
+ QFxItem *child = qobject_cast<QFxItem *>(this->QSimpleCanvasItem::children().at(ii));
+ if(!child || !child->isVisible())
+ continue;
+
+ bool needMove = (child->x() != hoffset || child->y());
+
+ QList<QPair<QString, QVariant> > changes;
+ changes << qMakePair(QString(QLatin1String("x")),QVariant(hoffset));
+ changes << qMakePair(QString(QLatin1String("y")),QVariant(0));
+ if(needMove && items()->contains(child) && move()) {
+ applyMove(changes,child);
+ } else if(!items()->contains(child) && add()) {
+ applyAdd(changes,child);
+ } else if(needMove) {
+ setMovingItem(child);
+ child->setX(hoffset);
+ setMovingItem(0);
+ child->setY(0);
+ }
+ hoffset += child->width();
+ hoffset += spacing();
+ }
+ setWidth(hoffset);
+}
+
+QML_DEFINE_TYPE(QFxGridLayout,GridLayout);
+
+/*!
+ \qmlclass GridLayout QFxGridLayout
+ \brief The GridLayout element arranges its children in a grid layout.
+ \inherits Item
+
+ The GridLayout element arranges its child elements so that they are
+ aligned in a grid and are not overlapping. Spacing can be added
+ between the items, and a margin around all the items can also be
+ defined. It also provides for transitions to be set when items are
+ added, moved, or removed in the layout. Adding and removing apply
+ both to elements which are deleted or have their position in the
+ document changed so as to no longer be children of the layout, as
+ well as to elements which have their opacity set to or from zero so
+ as to appear or disappear.
+
+ The GridLayout defaults to using four columns, and as many rows as
+ are necessary to fit all the child elements. The number of rows
+ and/or the number of columns can be constrained by setting the rows
+ or columns properties. The grid layout calculates a grid with
+ rectangular cells of sufficient size to hold all items, and then
+ places the items in the cells, going across then down, and
+ positioning each item at the (0,0) corner of the cell. The below
+ example demonstrates this.
+
+ \table
+ \row
+ \o \image gridLayout_example.png
+ \o
+ \code
+ <GridLayout columns="3" spacing="2">
+ <Rect color="red" width="50" height="50"/>
+ <Rect color="green" width="20" height="50"/>
+ <Rect color="blue" width="50" height="20"/>
+ <Rect color="cyan" width="50" height="50"/>
+ <Rect color="magenta" width="10" height="10"/>
+ </GridLayout>
+ \endcode
+ \endtable
+*/
+/*!
+ \qmlproperty Transition GridLayout::remove
+ This property holds the transition to apply when removing an item from the layout.
+
+ Removed can mean that either the object has been deleted or
+ reparented, and thus is now longer a child of the layout, or that
+ the object has had its opacity set to zero, and thus is no longer
+ visible.
+
+ Note that if the item counts as removed because its opacity is
+ zero it will not be visible during the transition unless you set
+ the opacity in the transition, like in the below example.
+
+ \code
+ <GridLayout id="layout">
+ <remove>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="1" to="0" duration="500" />
+ </Transition>
+ </remove>
+ </GridLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Transition GridLayout::add
+ This property holds the transition to apply when adding an item to the layout.
+
+ Added can mean that either the object has been created or
+ reparented, and thus is now a child or the layout, or that the
+ object has had its opacity increased from zero, and thus is now
+ visible.
+
+ \code
+ <GridLayout id="layout">
+ <add>
+ <Transition >
+ <NumericAnimation target="{layout.item}" properties="opacity" from="0" to="1" duration="500" />
+ </Transition>
+ </add>
+ </GridLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Transition GridLayout::move
+ This property holds the transition to apply when moving an item within the layout.
+
+ This can happen when other items are added or removed from the layout, or
+ when items resize themselves.
+
+ \code
+ <GridLayout id="layout">
+ <move>
+ <Transition>
+ <NumericAnimation properties="x,y" ease="easeOutBounce" />
+ </Transition>
+ </move>
+ </GridLayout>
+ \endcode
+
+*/
+/*!
+ \qmlproperty Item GridLayout::item
+
+ The item that is currently being laid out. Used to target
+ transitions that apply only to the item being laid out, such as in
+ the add transition.
+
+*/
+/*!
+ \qmlproperty int GridLayout::spacing
+ \qmlproperty int GridLayout::margin
+
+ spacing and margin allow you to control the empty space surrounding
+ items in layouts.
+
+ spacing is the amount in pixels left empty between each adjacent
+ item. margin is the amount in pixels which will be left empty
+ around the inside edge of the layout. Both default to 0.
+
+ The below example places a GridLayout containing a red, a blue and a
+ green rectangle on a gray background. The area the grid layout
+ occupies is colored white. The top layout has a spacing of 2 and a
+ margin of 5, the bottom layout has the defaults of no margin or
+ spacing.
+
+ \image spacing_a.png
+ \image spacing_b.png
+
+*/
+/*!
+ \internal
+ \class QFxGridLayout
+ \brief The QFxGridLayout class lays out items in a grid.
+ \ingroup layouts
+
+*/
+QFxGridLayout::QFxGridLayout(QFxItem *parent) :
+ QFxBaseLayout(Both, parent)
+{
+ _columns=-1;
+ _rows=-1;
+}
+
+/*!
+ \qmlproperty int GridLayout::columns
+ This property holds the number of columns in the grid.
+
+ When the columns property is set the GridLayout will always have
+ that many columns. Note that if you do not have enough items to
+ fill this many columns some columns will be of zero width.
+*/
+
+/*!
+ \qmlproperty int GridLayout::rows
+ This property holds the number of rows in the grid.
+
+ When the rows property is set the GridLayout will always have that
+ many rows. Note that if you do not have enough items to fill this
+ many rows some rows will be of zero width.
+*/
+
+/*!
+ \property QFxGridLayout::columns
+ \brief the number of columns in the grid.
+*/
+
+/*!
+ \property QFxGridLayout::rows
+ \brief the number of rows in the grid.
+*/
+
+void QFxGridLayout::doLayout()
+{
+ int c=_columns,r=_rows;//Actual number of rows/columns
+ int numVisible = items()->size() + newItems()->size();
+ if(_columns==-1 && _rows==-1){
+ c = 4;
+ r = (numVisible+2)/3;
+ }else if(_rows==-1){
+ r = (numVisible+(_columns-1))/_columns;
+ }else if(_columns==-1){
+ c = (numVisible+(_rows-1))/_rows;
+ }
+
+ QList<int> maxColWidth;
+ QList<int> maxRowHeight;
+ int childIndex =0;
+ for(int i=0; i<r; i++){
+ for(int j=0; j<c; j++){
+ if(j==0)
+ maxRowHeight << 0;
+ if(i==0)
+ maxColWidth << 0;
+ if(childIndex == this->QSimpleCanvasItem::children().count())
+ continue;
+ QFxItem *child = qobject_cast<QFxItem *>(this->QSimpleCanvasItem::children().at(childIndex++));
+ if(!child || !child->isVisible())
+ continue;
+ if(child->width() > maxColWidth[j])
+ maxColWidth[j] = child->width();
+ if(child->height() > maxRowHeight[i])
+ maxRowHeight[i] = child->height();
+ }
+ }
+
+ int xoffset=0;
+ int yoffset=0;
+ int curRow =0;
+ int curCol =0;
+ foreach(QFxItem* item, *leavingItems()){
+ if(remove()){
+ QList<QPair<QString,QVariant> > changes;
+ applyRemove(changes, item);
+ }
+ }
+ foreach(QSimpleCanvasItem* schild, this->QSimpleCanvasItem::children()){
+ QFxItem *child = qobject_cast<QFxItem *>(schild);
+ if(!child || !child->isVisible())
+ continue;
+ bool needMove = (child->x()!=xoffset)||(child->y()!=yoffset);
+ QList<QPair<QString, QVariant> > changes;
+ changes << qMakePair(QString(QLatin1String("x")),QVariant(xoffset));
+ changes << qMakePair(QString(QLatin1String("y")),QVariant(yoffset));
+ if(newItems()->contains(child) && add()) {
+ applyAdd(changes,child);
+ } else if(needMove) {
+ if(move()){
+ applyMove(changes,child);
+ }else{
+ setMovingItem(child);
+ child->setPos(QPointF(xoffset, yoffset));
+ setMovingItem(0);
+ }
+ }
+ xoffset+=maxColWidth[curCol]+spacing();
+ curCol++;
+ curCol%=c;
+ if(!curCol){
+ yoffset+=maxRowHeight[curRow]+spacing();
+ xoffset=0;
+ curRow++;
+ if(curRow>=r)
+ return;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxlayouts.h b/src/declarative/fx/qfxlayouts.h
new file mode 100644
index 0000000..acfc0c4
--- /dev/null
+++ b/src/declarative/fx/qfxlayouts.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXLAYOUTS_H
+#define QFXLAYOUTS_H
+
+#include <qfxitem.h>
+#include <QObject>
+#include <QString>
+#include <qmlstate.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxBaseLayoutPrivate;
+
+class Q_DECLARATIVE_EXPORT QFxBaseLayout : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int spacing READ spacing WRITE setSpacing)
+ Q_PROPERTY(int margin READ margin WRITE setMargin)
+ Q_PROPERTY(QmlTransition *move READ move WRITE setMove)
+ Q_PROPERTY(QmlTransition *add READ add WRITE setAdd)
+ Q_PROPERTY(QmlTransition *remove READ remove WRITE setRemove)
+ Q_PROPERTY(QFxItem *item READ layoutItem NOTIFY layoutItemChanged)
+public:
+ enum AutoUpdateType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 };
+ QFxBaseLayout(AutoUpdateType, QFxItem *parent);
+
+ int spacing() const;
+ void setSpacing(int);
+
+ int margin() const;
+ void setMargin(int);
+
+ QmlTransition *move() const;
+ void setMove(QmlTransition *);
+
+ QmlTransition *add() const;
+ void setAdd(QmlTransition *);
+
+ QmlTransition *remove() const;
+ void setRemove(QmlTransition *);
+
+ QFxItem *layoutItem() const;
+
+protected:
+ virtual void componentComplete();
+ virtual void childrenChanged();
+ virtual bool event(QEvent *);
+ QSet<QFxItem *>* newItems();
+ QSet<QFxItem *>* leavingItems();
+ QSet<QFxItem *>* items();
+ void applyAdd(const QList<QPair<QString, QVariant> >& changes, QFxItem* target);
+ void applyMove(const QList<QPair<QString, QVariant> >& changes, QFxItem* target);
+ void applyRemove(const QList<QPair<QString, QVariant> >& changes, QFxItem* target);
+
+Q_SIGNALS:
+ void layoutItemChanged();
+
+protected Q_SLOTS:
+ virtual void doLayout()=0;
+ void setLayoutItem(QFxItem *);
+
+private Q_SLOTS:
+ void preLayout();
+
+protected:
+ QFxBaseLayout(QFxBaseLayoutPrivate &dd, AutoUpdateType at, QFxItem *parent);
+ void setMovingItem(QFxItem *);
+
+private:
+ void applyTransition(const QList<QPair<QString, QVariant> >& changes, QFxItem* target,
+ QmlTransition* transition);
+ Q_DISABLE_COPY(QFxBaseLayout)
+ Q_DECLARE_PRIVATE(QFxBaseLayout)
+};
+
+class Q_DECLARATIVE_EXPORT QFxVerticalLayout : public QFxBaseLayout
+{
+ Q_OBJECT
+public:
+ QFxVerticalLayout(QFxItem *parent=0);
+protected Q_SLOTS:
+ virtual void doLayout();
+private:
+ Q_DISABLE_COPY(QFxVerticalLayout)
+};
+QML_DECLARE_TYPE(QFxVerticalLayout);
+
+class Q_DECLARATIVE_EXPORT QFxHorizontalLayout: public QFxBaseLayout
+{
+ Q_OBJECT
+public:
+ QFxHorizontalLayout(QFxItem *parent=0);
+protected Q_SLOTS:
+ virtual void doLayout();
+private:
+ Q_DISABLE_COPY(QFxHorizontalLayout)
+};
+QML_DECLARE_TYPE(QFxHorizontalLayout);
+
+class Q_DECLARATIVE_EXPORT QFxGridLayout : public QFxBaseLayout
+{
+ Q_OBJECT
+ Q_PROPERTY(int rows READ rows WRITE setRows)
+ Q_PROPERTY(int columns READ columns WRITE setcolumns)
+public:
+ QFxGridLayout(QFxItem *parent=0);
+
+ int rows() const {return _rows;}
+ void setRows(const int rows){_rows = rows;}
+
+ int columns() const {return _columns;}
+ void setcolumns(const int columns){_columns = columns;}
+protected Q_SLOTS:
+ virtual void doLayout();
+
+private:
+ int _rows;
+ int _columns;
+ Q_DISABLE_COPY(QFxGridLayout)
+};
+QML_DECLARE_TYPE(QFxGridLayout);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxlayouts_p.h b/src/declarative/fx/qfxlayouts_p.h
new file mode 100644
index 0000000..859482f
--- /dev/null
+++ b/src/declarative/fx/qfxlayouts_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXLAYOUTS_P_H
+#define QFXLAYOUTS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxlayouts.h"
+#include "qfxitem_p.h"
+#include <QObject>
+#include <QString>
+#include <qmlstate.h>
+
+
+QT_BEGIN_NAMESPACE
+class QFxBaseLayoutPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxBaseLayout)
+
+public:
+ QFxBaseLayoutPrivate()
+ : _ep(false), _componentComplete(false), _spacing(0),
+ _margin(0), aut(QFxBaseLayout::None), moveTransition(0), addTransition(0),
+ removeTransition(0), _layoutItem(0), stateGroup(0), _movingItem(0)
+ {
+ }
+
+ void init(QFxBaseLayout::AutoUpdateType at)
+ {
+ aut = at;
+ }
+
+ bool _ep;
+ bool _componentComplete;
+ int _spacing;
+ int _margin;
+ QFxBaseLayout::AutoUpdateType aut;
+ QmlTransition *moveTransition;
+ QmlTransition *addTransition;
+ QmlTransition *removeTransition;
+ QSet<QFxItem *> _items;
+ QSet<QFxItem *> _leavingItems;
+ QSet<QFxItem *> _stableItems;
+ QSet<QFxItem *> _newItems;
+ QSet<QFxItem *> _animated;
+ QFxItem *_layoutItem;
+ QmlStateGroup *stateGroup;
+ QFxItem *_movingItem;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp
new file mode 100644
index 0000000..3c8c12c
--- /dev/null
+++ b/src/declarative/fx/qfxlistview.cpp
@@ -0,0 +1,1680 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "private/qfxflickable_p.h"
+#include "qmlfollow.h"
+#include "qlistmodelinterface.h"
+#include "qfxvisualitemmodel.h"
+#include "gfxeasing.h"
+#include "qfxlistview.h"
+#include <qmlexpression.h>
+
+
+QT_BEGIN_NAMESPACE
+class QFxListViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QFxListViewAttached(QObject *parent)
+ : QObject(parent), m_isCurrent(false), m_delayRemove(false) {}
+ ~QFxListViewAttached() {
+ attachedProperties.remove(parent());
+ }
+
+ Q_PROPERTY(QFxListView *view READ view);
+ QFxListView *view() { return m_view; }
+
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY currentItemChanged);
+ bool isCurrentItem() const { return m_isCurrent; }
+ void setIsCurrentItem(bool c) {
+ if (m_isCurrent != c) {
+ m_isCurrent = c;
+ emit currentItemChanged();
+ }
+ }
+
+ Q_PROPERTY(QString prevSection READ prevSection NOTIFY prevSectionChanged);
+ QString prevSection() const { return m_prevSection; }
+ void setPrevSection(const QString &sect) {
+ if (m_prevSection != sect) {
+ m_prevSection = sect;
+ emit prevSectionChanged();
+ }
+ }
+
+ Q_PROPERTY(QString section READ section NOTIFY sectionChanged);
+ QString section() const { return m_section; }
+ void setSection(const QString &sect) {
+ if (m_section != sect) {
+ m_section = sect;
+ emit sectionChanged();
+ }
+ }
+
+ Q_PROPERTY(bool delayRemove READ delayRemove WRITE setDelayRemove NOTIFY delayRemoveChanged);
+ bool delayRemove() const { return m_delayRemove; }
+ void setDelayRemove(bool delay) {
+ if (m_delayRemove != delay) {
+ m_delayRemove = delay;
+ emit delayRemoveChanged();
+ }
+ }
+
+ static QFxListViewAttached *properties(QObject *obj) {
+ if(!attachedProperties.contains(obj)) {
+ QFxListViewAttached *rv = new QFxListViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ return rv;
+ }
+ return attachedProperties.value(obj);
+ }
+
+ void emitAdd() { emit add(); }
+ void emitRemove() { emit remove(); }
+
+signals:
+ void currentItemChanged();
+ void sectionChanged();
+ void prevSectionChanged();
+ void delayRemoveChanged();
+ void add();
+ void remove();
+
+public:
+ QFxListView *m_view;
+ bool m_isCurrent;
+ mutable QString m_section;
+ QString m_prevSection;
+ bool m_delayRemove;
+
+ static QHash<QObject*, QFxListViewAttached*> attachedProperties;
+};
+
+QHash<QObject*, QFxListViewAttached*> QFxListViewAttached::attachedProperties;
+
+//----------------------------------------------------------------------------
+
+class FxListItem
+{
+public:
+ FxListItem(QFxItem *i, QFxListView *v) : item(i), view(v) {
+ attached = QFxListViewAttached::properties(item);
+ attached->m_view = view;
+ }
+ ~FxListItem() {}
+
+ qreal position() const { return (view->orientation() == Qt::Vertical ? item->y() : item->x()); }
+ int size() const { return (view->orientation() == Qt::Vertical ? item->height() : item->width()); }
+ qreal endPosition() const {
+ return (view->orientation() == Qt::Vertical
+ ? item->y() + (item->height() > 0 ? item->height() : 1)
+ : item->x() + (item->width() > 0 ? item->width() : 1)) - 1;
+ }
+ void setPosition(qreal pos) {
+ if (view->orientation() == Qt::Vertical) {
+ item->setY(pos);
+ } else {
+ item->setX(pos);
+ }
+ }
+
+ QFxItem *item;
+ QFxListView *view;
+ QFxListViewAttached *attached;
+ int index;
+};
+
+//----------------------------------------------------------------------------
+
+class QFxListViewPrivate : public QFxFlickablePrivate
+{
+ Q_DECLARE_PUBLIC(QFxListView);
+
+public:
+ QFxListViewPrivate()
+ : model(0), currentItem(0), tmpCurrent(0), orient(Qt::Vertical)
+ , visiblePos(0), visibleIndex(0)
+ , averageSize(100), currentIndex(-1), currItemMode(QFxListView::Free)
+ , snapPos(0), highlightComponent(0), highlight(0), trackedItem(0)
+ , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0)
+ , keyPressed(false), ownModel(false), wrap(false), autoHighlight(true)
+ , fixCurrentVisibility(false) {}
+
+ void init();
+ void clear();
+ FxListItem *getItem(int modelIndex);
+ FxListItem *createItem(int modelIndex);
+ void releaseItem(FxListItem *item);
+
+ FxListItem *visibleItem(int modelIndex) const {
+ if (modelIndex >= visibleIndex && modelIndex < visibleIndex + visibleItems.count()) {
+ for (int i = modelIndex - visibleIndex; i < visibleItems.count(); ++i) {
+ FxListItem *item = visibleItems.at(i);
+ if (item->index == modelIndex)
+ return item;
+ }
+ }
+ return 0;
+ }
+
+ qreal position() const {
+ Q_Q(const QFxListView);
+ return orient == Qt::Vertical ? q->yPosition() : q->xPosition();
+ }
+ void setPosition(qreal pos) {
+ Q_Q(QFxListView);
+ if (orient == Qt::Vertical)
+ q->setYPosition(pos);
+ else
+ q->setXPosition(pos);
+ }
+ int size() const {
+ Q_Q(const QFxListView);
+ return orient == Qt::Vertical ? q->height() : q->width();
+ }
+
+ qreal startPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty())
+ pos = visibleItems.first()->position() - visibleIndex * averageSize;
+ return pos;
+ }
+
+ qreal endPosition() const {
+ qreal pos = 0;
+ if (!visibleItems.isEmpty()) {
+ int invisibleCount = visibleItems.count() - visibleIndex;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ if (visibleItems.at(i)->index != -1) {
+ invisibleCount = model->count() - visibleItems.at(i)->index - 1;
+ break;
+ }
+ }
+ pos = visibleItems.last()->endPosition() + invisibleCount * averageSize;
+ }
+ return pos;
+ }
+
+ qreal positionAt(int modelIndex) const {
+ if (FxListItem *item = visibleItem(modelIndex))
+ return item->position();
+ if (!visibleItems.isEmpty()) {
+ if (modelIndex < visibleIndex) {
+ int count = visibleIndex - modelIndex;
+ return visibleItems.first()->position() - count * averageSize;
+ } else {
+ int idx = visibleItems.count() - 1;
+ while (idx >= 0 && visibleItems.at(idx)->index == -1)
+ --idx;
+ if (idx < 0)
+ idx = visibleIndex;
+ else
+ idx = visibleItems.at(idx)->index;
+ int count = modelIndex - idx - 1;
+ return visibleItems.last()->endPosition() + count * averageSize + 1;
+ }
+ }
+ return 0;
+ }
+
+ QString sectionAt(int modelIndex) {
+ Q_Q(QFxListView);
+ if (FxListItem *item = visibleItem(modelIndex))
+ return item->attached->section();
+ QString section;
+ if (!sectionExpression.isEmpty())
+ section = model->evaluate(modelIndex, sectionExpression, q).toString();
+ return section;
+ }
+
+ bool isValid() const {
+ return model && model->count() && (!ownModel || model->delegate());
+ }
+
+ int snapIndex() {
+ qreal pos = position();
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ qreal itemTop = visibleItems[i]->position() - pos;
+ if (itemTop >= snapPos-averageSize/2 && itemTop < snapPos+averageSize/2)
+ return visibleItems[i]->index;
+ }
+ return -1;
+ }
+
+ // map a model index to visibleItems index.
+ // These may differ if removed items are still present in the visible list,
+ // e.g. doing a removal animation
+ int mapFromModel(int modelIndex) const {
+ if (modelIndex < visibleIndex || modelIndex >= visibleIndex + visibleItems.count())
+ return -1;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItem *listItem = visibleItems.at(i);
+ if (listItem->index == modelIndex)
+ return i + visibleIndex;
+ if (listItem->index > modelIndex)
+ return -1;
+ }
+ return -1; // Not in visibleList
+ }
+
+ // for debugging only
+ void checkVisible() const {
+ int skip = 0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ FxListItem *listItem = visibleItems.at(i);
+ if (listItem->index == -1) {
+ ++skip;
+ } else if (listItem->index != visibleIndex + i - skip) {
+ qDebug() << "index" << visibleIndex << i << listItem->index;
+ abort();
+ }
+ }
+ }
+
+ void refill(qreal from, qreal to);
+ void layout();
+ void updateTrackedItem();
+ void createHighlight();
+ void updateHighlight();
+ void updateSections();
+ void updateCurrentSection();
+ void updateCurrent(int);
+ void updateAverage();
+ void fixupPosition();
+ virtual void fixupY();
+ virtual void fixupX();
+
+ QFxVisualItemModel *model;
+ QVariant modelVariant;
+ QList<FxListItem*> visibleItems;
+ FxListItem *currentItem;
+ QFxItem *tmpCurrent;
+ Qt::Orientation orient;
+ int visiblePos;
+ int visibleIndex;
+ qreal averageSize;
+ int currentIndex;
+ QFxListView::CurrentItemPositioning currItemMode;
+ int snapPos;
+ QmlComponent *highlightComponent;
+ FxListItem *highlight;
+ FxListItem *trackedItem;
+ QFxItem *activeItem; //XXX fix
+ enum MovementReason { Other, Key, Mouse };
+ MovementReason moveReason;
+ int buffer;
+ QmlFollow *highlightPosAnimator;
+ QmlFollow *highlightSizeAnimator;
+ QString sectionExpression;
+ QString currentSection;
+
+ int keyPressed : 1;
+ int ownModel : 1;
+ int wrap : 1;
+ int autoHighlight : 1;
+ int fixCurrentVisibility : 1;
+};
+
+void QFxListViewPrivate::init()
+{
+ Q_Q(QFxListView);
+ q->setOptions(QFxListView::IsFocusRealm);
+}
+
+void QFxListViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visiblePos = 0;
+ visibleIndex = 0;
+ if (currentItem) {
+ FxListItem *tmpItem = currentItem;
+ currentItem = 0;
+ currentIndex = -1;
+ releaseItem(tmpItem);
+ }
+ createHighlight();
+ trackedItem = 0;
+}
+
+FxListItem *QFxListViewPrivate::getItem(int modelIndex)
+{
+ if (currentItem && modelIndex == currentIndex)
+ return currentItem;
+ if (FxListItem *listItem = visibleItem(modelIndex))
+ return listItem;
+ return createItem(modelIndex);
+}
+
+FxListItem *QFxListViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QFxListView);
+ // create object
+ FxListItem *listItem = 0;
+ if (QFxItem *item = model->item(modelIndex, false)) {
+ listItem = new FxListItem(item, q);
+ listItem->index = modelIndex;
+ // initialise attached properties
+ if (!sectionExpression.isEmpty()) {
+ QmlExpression e(listItem->item->itemContext(), sectionExpression, q);
+ e.setTrackChange(false);
+ listItem->attached->m_section = e.value().toString();
+ if (modelIndex > 0) {
+ if (FxListItem *item = visibleItem(modelIndex-1))
+ listItem->attached->m_prevSection = item->attached->section();
+ else
+ listItem->attached->m_prevSection = sectionAt(modelIndex-1);
+ }
+ }
+ // complete
+ model->completeItem();
+ listItem->item->setZ(modelIndex + 1);
+ listItem->item->setParent(q->viewport());
+ if (orient == Qt::Vertical)
+ QObject::connect(listItem->item, SIGNAL(heightChanged()), q, SLOT(itemResized()));
+ else
+ QObject::connect(listItem->item, SIGNAL(widthChanged()), q, SLOT(itemResized()));
+ }
+ return listItem;
+}
+
+void QFxListViewPrivate::releaseItem(FxListItem *item)
+{
+ Q_Q(QFxListView);
+ if (item != currentItem) {
+ if (orient == Qt::Vertical)
+ QObject::disconnect(item->item, SIGNAL(heightChanged()), q, SLOT(itemResized()));
+ else
+ QObject::disconnect(item->item, SIGNAL(widthChanged()), q, SLOT(itemResized()));
+ if (trackedItem == item) {
+ const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged());
+ const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged());
+ QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+ model->release(item->item);
+ delete item;
+ }
+}
+
+void QFxListViewPrivate::refill(qreal from, qreal to)
+{
+ Q_Q(QFxListView);
+ if (!isValid() || !q->isComponentComplete())
+ return;
+ from -= buffer;
+ to += buffer;
+ int modelIndex = 0;
+ qreal itemEnd = visiblePos-1;
+ if (!visibleItems.isEmpty()) {
+ visiblePos = visibleItems.first()->position();
+ itemEnd = visibleItems.last()->endPosition();
+ int i = visibleItems.count() - 1;
+ while (i > 0 && visibleItems.at(i)->index == -1)
+ --i;
+ modelIndex = visibleItems.at(i)->index + 1;
+ }
+
+ bool changed = false;
+ FxListItem *item = 0;
+ int pos = itemEnd + 1;
+ while (modelIndex < model->count() && pos <= to) {
+ //qDebug() << "refill: append item" << modelIndex;
+ item = getItem(modelIndex);
+ item->setPosition(pos);
+ pos += item->size();
+ visibleItems.append(item);
+ ++modelIndex;
+ changed = true;
+ }
+ while (visibleIndex > 0 && visiblePos > from) {
+ //qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+ item = getItem(visibleIndex-1);
+ --visibleIndex;
+ visiblePos -= item->size();
+ item->setPosition(visiblePos);
+ visibleItems.prepend(item);
+ changed = true;
+ }
+
+ while (visibleItems.count() > 1 && (item = visibleItems.first()) && item->endPosition() < from) {
+ if (item->attached->delayRemove())
+ break;
+ //qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endPosition();
+ if (item->index != -1)
+ visibleIndex++;
+ visibleItems.removeFirst();
+ releaseItem(item);
+ changed = true;
+ }
+ while (visibleItems.count() > 1 && (item = visibleItems.last()) && item->position() > to) {
+ if (item->attached->delayRemove())
+ break;
+ //qDebug() << "refill: remove last" << visibleIndex+visibleItems.count()-1;
+ visibleItems.removeLast();
+ releaseItem(item);
+ changed = true;
+ }
+ if (changed) {
+ if (visibleItems.count())
+ visiblePos = visibleItems.first()->position();
+ updateAverage();
+ if (!sectionExpression.isEmpty())
+ updateCurrentSection();
+ if (orient == Qt::Vertical)
+ q->setViewportHeight(endPosition() - startPosition());
+ else
+ q->setViewportWidth(endPosition() - startPosition());
+ }
+}
+
+void QFxListViewPrivate::layout()
+{
+ Q_Q(QFxListView);
+ if (!visibleItems.isEmpty()) {
+ int oldEnd = visibleItems.last()->endPosition();
+ int pos = visibleItems.first()->endPosition() + 1;
+ for (int i=1; i < visibleItems.count(); ++i) {
+ FxListItem *item = visibleItems.at(i);
+ item->setPosition(pos);
+ pos += item->size();
+ }
+ // move current item if it is after the visible items.
+ if (currentItem && currentIndex > visibleItems.last()->index)
+ currentItem->setPosition(currentItem->position() + (visibleItems.last()->endPosition() - oldEnd));
+ }
+ if (!isValid())
+ return;
+ q->refill();
+ q->trackedPositionChanged();
+ updateHighlight();
+ if (orient == Qt::Vertical) {
+ fixupY();
+ q->setViewportHeight(endPosition() - startPosition());
+ } else {
+ fixupX();
+ q->setViewportWidth(endPosition() - startPosition());
+ }
+}
+
+void QFxListViewPrivate::updateTrackedItem()
+{
+ Q_Q(QFxListView);
+ FxListItem *item = currentItem;
+ if (highlight)
+ item = highlight;
+
+ const char *notifier1 = orient == Qt::Vertical ? SIGNAL(topChanged()) : SIGNAL(leftChanged());
+ const char *notifier2 = orient == Qt::Vertical ? SIGNAL(heightChanged()) : SIGNAL(widthChanged());
+
+ if (trackedItem && item != trackedItem) {
+ QObject::disconnect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+
+ if (!trackedItem && item) {
+ trackedItem = item;
+ QObject::connect(trackedItem->item, notifier1, q, SLOT(trackedPositionChanged()));
+ QObject::connect(trackedItem->item, notifier2, q, SLOT(trackedPositionChanged()));
+ q->trackedPositionChanged();
+ }
+ if (trackedItem)
+ q->trackedPositionChanged();
+}
+
+void QFxListViewPrivate::createHighlight()
+{
+ Q_Q(QFxListView);
+ if (highlight) {
+ if (trackedItem == highlight)
+ trackedItem = 0;
+ delete highlight->item;
+ delete highlight;
+ highlight = 0;
+ delete highlightPosAnimator;
+ delete highlightSizeAnimator;
+ highlightPosAnimator = 0;
+ highlightSizeAnimator = 0;
+ }
+
+ if (currentItem) {
+ QFxItem *item = 0;
+ if (highlightComponent) {
+ QmlContext *highlightContext = new QmlContext(q->itemContext());
+ QObject *nobj = highlightComponent->create(highlightContext);
+ if (nobj) {
+ highlightContext->setParent(nobj);
+ item = qobject_cast<QFxItem *>(nobj);
+ if(!item) {
+ delete nobj;
+ } else {
+ item->setParent(q->viewport());
+ }
+ } else {
+ delete highlightContext;
+ }
+ } else {
+ item = new QFxItem;
+ item->setParent(q->viewport());
+ }
+ if (item) {
+ highlight = new FxListItem(item, q);
+ const QLatin1String posProp(orient == Qt::Vertical ? "y" : "x");
+ highlightPosAnimator = new QmlFollow(q);
+ highlightPosAnimator->setTarget(QmlMetaProperty(highlight->item, posProp));
+ highlightPosAnimator->setSpring(3);
+ highlightPosAnimator->setDamping(0.3);
+ highlightPosAnimator->setEnabled(autoHighlight);
+ const QLatin1String sizeProp(orient == Qt::Vertical ? "height" : "width");
+ highlightSizeAnimator = new QmlFollow(q);
+ highlightSizeAnimator->setTarget(QmlMetaProperty(highlight->item, sizeProp));
+ highlightSizeAnimator->setEnabled(autoHighlight);
+ }
+ }
+}
+
+void QFxListViewPrivate::updateHighlight()
+{
+ if ((!currentItem && highlight) || (currentItem && !highlight))
+ createHighlight();
+ updateTrackedItem();
+ if (currentItem && autoHighlight && highlight) {
+ // auto-update highlight
+ highlightPosAnimator->setSourceValue(currentItem->position());
+ highlightSizeAnimator->setSourceValue(currentItem->size());
+ if (orient == Qt::Vertical) {
+ if (highlight->item->width() == 0)
+ highlight->item->setWidth(currentItem->item->width());
+ } else {
+ if (highlight->item->height() == 0)
+ highlight->item->setHeight(currentItem->item->height());
+ }
+ }
+}
+
+void QFxListViewPrivate::updateSections()
+{
+ if (!sectionExpression.isEmpty()) {
+ QString prevSection;
+ if (visibleIndex > 0)
+ prevSection = sectionAt(visibleIndex-1);
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ QFxListViewAttached *attached = visibleItems.at(i)->attached;
+ attached->setPrevSection(prevSection);
+ prevSection = attached->section();
+ }
+ }
+}
+
+void QFxListViewPrivate::updateCurrentSection()
+{
+ if (sectionExpression.isEmpty() || visibleItems.isEmpty()) {
+ currentSection = QString();
+ return;
+ }
+ int index = 0;
+ while (visibleItems.at(index)->endPosition() < position() && index < visibleItems.count())
+ ++index;
+
+ if (index < visibleItems.count())
+ currentSection = visibleItems.at(index)->attached->section();
+ else
+ currentSection = visibleItems.first()->attached->section();
+}
+
+void QFxListViewPrivate::updateCurrent(int modelIndex)
+{
+ Q_Q(QFxListView);
+ if (!isValid() || modelIndex < 0 || modelIndex >= model->count()) {
+ if (currentItem) {
+ FxListItem *item = currentItem;
+ int index = currentIndex;
+ currentItem = 0;
+ currentIndex = 0;
+ updateHighlight();
+ if (!visibleItem(index))
+ releaseItem(item);
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ if (tmpCurrent) {
+ delete tmpCurrent;
+ tmpCurrent = 0;
+ }
+ int oldCurrentIndex = currentIndex;
+ FxListItem *oldCurrentItem = currentItem;
+ currentIndex = -1;
+ currentItem = visibleItem(modelIndex);
+ if (!currentItem) {
+ currentItem = getItem(modelIndex);
+ if (modelIndex == visibleIndex - 1) {
+ // We can calculate exact postion in this case
+ currentItem->setPosition(visibleItems.first()->position() - currentItem->size());
+ } else {
+ // Create current item now and position as best we can.
+ // Its position will be corrected when it becomes visible.
+ currentItem->setPosition(positionAt(modelIndex));
+ }
+ }
+ currentIndex = modelIndex;
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && oldCurrentItem->item != currentItem->item)
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ updateHighlight();
+ emit q->currentIndexChanged();
+ // Release the old current item
+ if (oldCurrentItem && !visibleItem(oldCurrentIndex)) {
+ if (oldCurrentItem->item == currentItem->item)
+ delete oldCurrentItem;
+ else
+ releaseItem(oldCurrentItem);
+ }
+}
+
+void QFxListViewPrivate::updateAverage()
+{
+ if (!visibleItems.count())
+ return;
+ qreal sum = 0.0;
+ for (int i = 0; i < visibleItems.count(); ++i)
+ sum += visibleItems.at(i)->size();
+ averageSize = sum / visibleItems.count();
+}
+
+void QFxListViewPrivate::fixupPosition()
+{
+ if (orient == Qt::Vertical)
+ fixupY();
+ else
+ fixupX();
+}
+
+void QFxListViewPrivate::fixupY()
+{
+ Q_Q(QFxListView);
+ QFxFlickablePrivate::fixupY();
+ if (orient == Qt::Horizontal)
+ return;
+ if (currItemMode == QFxListView::SnapAuto) {
+ if (currentItem) {
+ moveReason = Mouse;
+ _tl.clear();
+ _tl.move(_moveY, -(currentItem->position() - snapPos), GfxEasing(GfxEasing::InOutQuad), 200);
+ }
+ } else if (currItemMode == QFxListView::Snap) {
+ moveReason = Mouse;
+ int idx = snapIndex();
+ if (FxListItem *snapItem = visibleItem(idx)) {
+ int pos = snapItem->position() - snapPos;
+ if (pos > -q->maxYExtent())
+ pos = -q->maxYExtent();
+ else if (pos < -q->minYExtent())
+ pos = -q->minYExtent();
+ _tl.clear();
+ _tl.move(_moveY, -(pos), GfxEasing(GfxEasing::InOutQuad), 200);
+ }
+ }
+}
+
+void QFxListViewPrivate::fixupX()
+{
+ Q_Q(QFxListView);
+ QFxFlickablePrivate::fixupX();
+ if (orient == Qt::Vertical)
+ return;
+ if (currItemMode == QFxListView::SnapAuto) {
+ moveReason = Mouse;
+ _tl.clear();
+ _tl.move(_moveX, -(currentItem->position() - snapPos), GfxEasing(GfxEasing::InOutQuad), 200);
+ } else if (currItemMode == QFxListView::Snap) {
+ moveReason = Mouse;
+ int idx = snapIndex();
+ if (FxListItem *snapItem = visibleItem(idx)) {
+ int pos = snapItem->position() - snapPos;
+ if (pos > -q->maxXExtent())
+ pos = -q->maxXExtent();
+ else if (pos < -q->minXExtent())
+ pos = -q->minXExtent();
+ _tl.clear();
+ _tl.move(_moveX, -(pos), GfxEasing(GfxEasing::InOutQuad), 200);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass ListView
+ \inherits Flickable
+ \brief The ListView element provides a list view of items provided by a model.
+
+ The model is typically provided by a QAbstractListModel "C++ model object", but can also be created directly in XML.
+
+ The items are laid out vertically or horizontally and may be flicked to scroll.
+
+ The below example creates a very simple vertical list, using an XML model.
+ \image trivialListView.png
+ \code
+ <resources>
+ <ListModel id="contactModel">
+ <Contact>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+ <Component id="contactDelegate">
+ <Rect pen.color="blue" z="-1" height="20" width="80" color="white" radius="2">
+ <Text id="name" text="{firstName + ' ' + lastName}" font.size="11"/>
+ </Rect>
+ </Component>
+ </resources>
+
+ <ListView id="list" width="320" height="240" clip="true"
+ model="{contactModel}" delegate="{contactDelegate}"/>
+ \endcode
+*/
+
+QFxListView::QFxListView(QFxItem *parent)
+ : QFxFlickable(*(new QFxListViewPrivate), parent)
+{
+ Q_D(QFxListView);
+ d->init();
+}
+
+QFxListView::~QFxListView()
+{
+ Q_D(QFxListView);
+ if (d->ownModel)
+ delete d->model;
+}
+
+/*!
+ \qmlproperty model ListView::model
+ This property holds the model providing data for the list.
+
+ The model provides a set of data that is used to create the items for the view.
+ For large or dynamic datasets the model is usually provided by a C++ model object.
+ The C++ model object must be a \l QListModelInterface subclass, a \l VisualModel,
+ or a simple list.
+
+ Models can also be created directly in XML, using the \l ListModel element. For example:
+ \code
+ <ListModel id="contactModel">
+ <Contact>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+
+ <ListView model="{contactModel}" .../>
+ \endcode
+*/
+QVariant QFxListView::model() const
+{
+ Q_D(const QFxListView);
+ return d->modelVariant;
+}
+
+void QFxListView::setModel(const QVariant &model)
+{
+ Q_D(QFxListView);
+ if (d->model) {
+ disconnect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ disconnect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ }
+ d->clear();
+ d->modelVariant = model;
+ QObject *object = qvariant_cast<QObject*>(model);
+ QFxVisualItemModel *vim = 0;
+ if (object && (vim = qobject_cast<QFxVisualItemModel *>(object))) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = vim;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel(itemContext());
+ d->ownModel = true;
+ }
+ d->model->setModel(model);
+ }
+ if (d->model) {
+ if (d->currentIndex >= d->model->count() || d->currentIndex < 0)
+ setCurrentIndex(0);
+ else
+ d->updateCurrent(d->currentIndex);
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ refill();
+ emit countChanged();
+ }
+}
+
+/*!
+ \qmlproperty component ListView::delegate
+
+ The delegate provides a template describing what each item in the view should look and act like.
+
+ Here is an example delegate:
+ \code
+ <Component id="contactDelegate">
+ <Item id="wrapper">
+ <Image id="pic" width="100" height="100" file="{portrait}"/>
+ <Text id="name" text="{firstName + ' ' + lastName}"
+ anchors.left="{pic.right}" anchors.leftMargin="5"/>
+ </Item>
+ </Component>
+ ...
+ <ListView delegate="{contactDelegate}" .../>
+ \endcode
+*/
+QmlComponent *QFxListView::delegate() const
+{
+ Q_D(const QFxListView);
+ return d->model ? d->model->delegate() : 0;
+}
+
+void QFxListView::setDelegate(QmlComponent *delegate)
+{
+ Q_D(QFxListView);
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel(itemContext());
+ d->ownModel = true;
+ }
+ d->model->setDelegate(delegate);
+ d->updateCurrent(d->currentIndex);
+ refill();
+}
+
+/*!
+ \qmlproperty int ListView::currentIndex
+ \qmlproperty Item ListView::current
+
+ \c currentIndex holds the index of the current item.
+ \c current is the current item. Note that the position of the current item
+ may only be approximate until it becomes visible in the view.
+*/
+int QFxListView::currentIndex() const
+{
+ Q_D(const QFxListView);
+ return d->currentIndex;
+}
+
+void QFxListView::setCurrentIndex(int index)
+{
+ Q_D(QFxListView);
+ d->moveReason = QFxListViewPrivate::Other;
+ if (d->isValid() && index != d->currentIndex && index < d->model->count() && index >= 0)
+ d->updateCurrent(index);
+ else
+ d->currentIndex = index;
+}
+
+QFxItem *QFxListView::currentItem()
+{
+ Q_D(QFxListView);
+ if (!d->currentItem) {
+ // Always return something valid
+ if (!d->tmpCurrent) {
+ d->tmpCurrent = new QFxItem;
+ d->tmpCurrent->setParent(viewport());
+ }
+ return d->tmpCurrent;
+ }
+ return d->currentItem->item;
+}
+
+/*!
+ \qmlproperty int ListView::count
+ This property holds the number of items in the view.
+*/
+int QFxListView::count() const
+{
+ Q_D(const QFxListView);
+ if (d->model)
+ return d->model->count();
+ return 0;
+}
+
+/*!
+ \qmlproperty component ListView::highlight
+ This property holds the component to use as the highlight.
+
+ An instance of the highlight component will be created for each list.
+ The geometry of the resultant component instance will be managed by the list
+ so as to stay with the current item, unless the autoHighlight property is false.
+
+ The below example demonstrates how to make a simple highlight
+ for a vertical list.
+ \code
+ <Component id="ListHighlight">
+ <Rect color="lightsteelblue" radius="4"/>
+ </Component>
+ <ListView highlight="{ListHighlight}">
+ \endcode
+ \image ListViewHighlight.png
+
+ \sa autoHighlight
+*/
+QmlComponent *QFxListView::highlight() const
+{
+ Q_D(const QFxListView);
+ return d->highlightComponent;
+}
+
+void QFxListView::setHighlight(QmlComponent *highlight)
+{
+ Q_D(QFxListView);
+ delete d->highlightComponent;
+ d->highlightComponent = highlight;
+ d->updateCurrent(d->currentIndex);
+}
+
+/*!
+ \qmlproperty bool ListView::autoHighlight
+ This property holds whether the highlight is managed by the view.
+
+ If autoHighlight is true, the highlight will be moved smoothly
+ to follow the current item. If autoHighlight is false, the
+ highlight will not be moved by the view, and must be implemented
+ by the highlight, for example:
+
+ \code
+ <Component id="Highlight">
+ <Rect id="Wrapper" color="#242424" radius="4" width="320" height="60" >
+ <y>
+ <Follow source="{Wrapper.ListView.view.current.y}" spring="3" damping="0.2"/>
+ </y>
+ </Rect>
+ </Component>
+ \endcode
+*/
+bool QFxListView::autoHighlight() const
+{
+ Q_D(const QFxListView);
+ return d->autoHighlight;
+}
+
+void QFxListView::setAutoHighlight(bool autoHighlight)
+{
+ Q_D(QFxListView);
+ d->autoHighlight = autoHighlight;
+ if (d->highlightPosAnimator) {
+ d->highlightPosAnimator->setEnabled(d->autoHighlight);
+ d->highlightSizeAnimator->setEnabled(d->autoHighlight);
+ }
+ d->updateHighlight();
+}
+
+/*!
+ \qmlproperty enumeration ListView::currentItemPositioning
+ This property determines the current item positioning and selection characteristics.
+
+ The modes supported are:
+ \list
+ \i Free - For Mouse, the current item may be positioned anywhere,
+ whether within the visible area, or outside. during Keyboard interaction,
+ the current item can move within the visible area, and the view will
+ scroll to keep the highlight visible.
+ \i Snap -
+ \i SnapAuto -
+ \endlist
+*/
+QFxListView::CurrentItemPositioning QFxListView::currentItemPositioning() const
+{
+ Q_D(const QFxListView);
+ return d->currItemMode;
+}
+
+void QFxListView::setCurrentItemPositioning(CurrentItemPositioning mode)
+{
+ Q_D(QFxListView);
+ d->currItemMode = mode;
+}
+
+/*!
+ \qmlproperty int ListView::snapPosition
+
+ When currentItemPositioning is set to Snap or SnapAuto, the
+ \c snapPosition determines where the top of the items will
+ snap to.
+*/
+int QFxListView::snapPosition() const
+{
+ Q_D(const QFxListView);
+ return d->snapPos;
+}
+
+void QFxListView::setSnapPosition(int pos)
+{
+ Q_D(QFxListView);
+ d->snapPos = pos;
+}
+
+/*!
+ \qmlproperty enumeration ListView::orientation
+ This property holds the orientation of the list.
+
+ Possible values are \c Qt::Vertical (default) and \c Qt::Horizontal.
+
+ Vertical Example:
+ \image ListViewVertical.png
+ Horizontal Example:
+ \image ListViewHorizontal.png
+*/
+Qt::Orientation QFxListView::orientation() const
+{
+ Q_D(const QFxListView);
+ return d->orient;
+}
+
+void QFxListView::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QFxListView);
+ if (d->orient != orientation) {
+ d->orient = orientation;
+ if (d->orient == Qt::Vertical)
+ setViewportWidth(-1);
+ else
+ setViewportHeight(-1);
+ d->clear();
+ refill();
+ d->updateCurrent(d->currentIndex);
+ }
+}
+
+/*!
+ \qmlproperty bool ListView::wrap
+ This property holds whether the list wraps key navigation
+
+ If this property is true then key presses to move off of one end of the list will cause the
+ selection to jump to the other side.
+*/
+bool QFxListView::isWrapEnabled() const
+{
+ Q_D(const QFxListView);
+ return d->wrap;
+}
+
+void QFxListView::setWrapEnabled(bool wrap)
+{
+ Q_D(QFxListView);
+ d->wrap = wrap;
+}
+
+/*!
+ \qmlproperty int ListView::cacheBuffer
+ This property holds the number of off-screen pixels to cache.
+
+ This property determines the number of pixels above the top of the list
+ and below the bottom of the list to cache. Setting this value can make
+ scrolling the list smoother at the expense of additional memory usage.
+*/
+
+/*!
+ \property QFxListView::cacheBuffer
+ \brief sets the number of off-screen pixels to cache.
+
+ This property determines the number of pixels above the top of the list
+ and below the bottom of the list to cache. Setting this value can make
+ scrolling the list smoother at the expense of additional memory usage.
+*/
+int QFxListView::cacheBuffer() const
+{
+ Q_D(const QFxListView);
+ return d->buffer;
+}
+
+void QFxListView::setCacheBuffer(int b)
+{
+ Q_D(QFxListView);
+ if(d->buffer != b) {
+ d->buffer = b;
+ if (isComponentComplete())
+ refill();
+ }
+}
+
+/*!
+ \qmlproperty string ListView::sectionExpression
+ This property holds the expression to be evaluated for the section attached property.
+
+ Each item in the list has attached properties named \c section and
+ \c prevSection. These may be used to place a section header for
+ related items. The example below assumes that the model is alphabetically
+ sorted. The section expression is the first character of the \c description
+ property. If \c section and \c prevSection differ, the item will
+ display a section header.
+
+ \code
+ <Component id="Delegate">
+ <Item id="wrapper" x="0" width="240" height="{Separator.height + Desc.height}">
+ <Item id="Separator" height="{wrapper.ListView.prevSection != wrapper.ListView.section ? 10 : 0}" width="240">
+ <Text text="{wrapper.ListView.section}" anchors.fill="{parent}"/>
+ </Item>
+ <Text id="Desc" text="{description} width="{parent.width}" height="30"/>
+ </Item>
+ </Component>
+ <ListView anchors.fill="{parent}" sectionExpression="{String(description).charAt(0)}" delegate="{Delegate}" model="{Model}"/>
+ \endcode
+*/
+QString QFxListView::sectionExpression() const
+{
+ Q_D(const QFxListView);
+ return d->sectionExpression;
+}
+
+void QFxListView::setSectionExpression(const QString &expression)
+{
+ Q_D(QFxListView);
+ if(d->sectionExpression != expression) {
+ d->sectionExpression = expression;
+ emit sectionExpressionChanged();
+ }
+}
+
+QString QFxListView::currentSection() const
+{
+ Q_D(const QFxListView);
+ return d->currentSection;
+}
+
+/*!
+ \reimp
+*/
+void QFxListView::setHeight(int height)
+{
+ Q_D(QFxListView);
+ QFxFlickable::setHeight(height);
+ if (d->orient == Qt::Vertical && isComponentComplete())
+ refill();
+}
+
+/*!
+ \reimp
+*/
+void QFxListView::setWidth(int width)
+{
+ Q_D(QFxListView);
+ QFxFlickable::setWidth(width);
+ if (d->orient == Qt::Horizontal && isComponentComplete())
+ refill();
+}
+
+void QFxListView::viewportMoved()
+{
+ Q_D(QFxListView);
+ QFxFlickable::viewportMoved();
+ refill();
+ if (isFlicking() || d->pressed)
+ d->moveReason = QFxListViewPrivate::Mouse;
+ if (d->currItemMode == SnapAuto && d->moveReason == QFxListViewPrivate::Mouse) {
+ // Update current index
+ int idx = d->snapIndex();
+ if (idx >= 0 && idx != d->currentIndex)
+ d->updateCurrent(idx);
+ }
+}
+
+/*!
+ \reimp
+*/
+qreal QFxListView::minYExtent() const
+{
+ Q_D(const QFxListView);
+ if (d->orient == Qt::Horizontal)
+ return QFxFlickable::minYExtent();
+ qreal extent = -d->startPosition();
+ if (d->currItemMode == SnapAuto)
+ extent += d->snapPos;
+
+ return extent;
+}
+
+/*!
+ \reimp
+*/
+qreal QFxListView::maxYExtent() const
+{
+ Q_D(const QFxListView);
+ if (d->orient == Qt::Horizontal)
+ return QFxFlickable::maxYExtent();
+ qreal extent;
+ if (d->currItemMode == SnapAuto)
+ extent = -(d->positionAt(count()-1) - d->snapPos);
+ else
+ extent = -(d->endPosition() - height());
+ if (extent > 0)
+ extent = 0;
+ return extent;
+}
+
+/*!
+ \reimp
+*/
+qreal QFxListView::minXExtent() const
+{
+ Q_D(const QFxListView);
+ if (d->orient == Qt::Vertical)
+ return QFxFlickable::minXExtent();
+ qreal extent = -d->startPosition();
+ if (d->currItemMode == SnapAuto)
+ extent += d->snapPos;
+
+ return extent;
+}
+
+/*!
+ \reimp
+*/
+qreal QFxListView::maxXExtent() const
+{
+ Q_D(const QFxListView);
+ if (d->orient == Qt::Vertical)
+ return QFxFlickable::maxXExtent();
+ qreal extent;
+ if (d->currItemMode == SnapAuto)
+ extent = -(d->positionAt(count()-1) - d->snapPos);
+ else
+ extent = -(d->endPosition() - width());
+ if (extent > 0)
+ extent = 0;
+ return extent;
+}
+
+void QFxListView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QFxListView);
+ if (d->model && d->model->count() && !d->locked) {
+ if ((d->orient == Qt::Horizontal && event->key() == Qt::Key_Left)
+ || (d->orient == Qt::Vertical && event->key() == Qt::Key_Up)) {
+ if (currentIndex() > 0 || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxListViewPrivate::Key;
+ int index = currentIndex()-1;
+ d->updateCurrent(index >= 0 ? index : d->model->count()-1);
+ event->accept();
+ }
+ return;
+ } else if ((d->orient == Qt::Horizontal && event->key() == Qt::Key_Right)
+ || (d->orient == Qt::Vertical && event->key() == Qt::Key_Down)) {
+ if (currentIndex() < d->model->count() - 1 || d->wrap) {
+ d->keyPressed = true;
+ d->moveReason = QFxListViewPrivate::Key;
+ int index = currentIndex()+1;
+ d->updateCurrent(index < d->model->count() ? index : 0);
+ event->accept();
+ }
+ return;
+ }
+ }
+ d->moveReason = QFxListViewPrivate::Other;
+ QFxFlickable::keyPressEvent(event);
+}
+
+void QFxListView::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QFxListView);
+ d->keyPressed = false;
+ QFxFlickable::keyReleaseEvent(event);
+}
+
+void QFxListView::componentComplete()
+{
+ Q_D(QFxListView);
+ QFxFlickable::componentComplete();
+ if (d->currentIndex < 0)
+ d->updateCurrent(0);
+ refill();
+ d->fixupPosition();
+}
+
+void QFxListView::refill()
+{
+ Q_D(QFxListView);
+ d->refill(d->position(), d->position()+d->size()-1);
+}
+
+void QFxListView::trackedPositionChanged()
+{
+ Q_D(QFxListView);
+ if (!d->trackedItem)
+ return;
+ if (!isFlicking() && !d->pressed && d->moveReason != QFxListViewPrivate::Mouse) {
+ switch (d->currItemMode) {
+ case Free:
+ if (d->trackedItem->position() < d->position()) {
+ d->setPosition(d->trackedItem->position());
+ } else if (d->trackedItem->endPosition() > d->position() + d->size()) {
+ qreal pos = d->trackedItem->endPosition() - d->size();
+ if (d->trackedItem->size() > d->size())
+ pos = d->trackedItem->position();
+ d->setPosition(pos);
+ }
+ d->fixupPosition();
+ break;
+ case Snap:
+ if (d->trackedItem->position() < d->startPosition() + d->snapPos)
+ d->setPosition(d->startPosition());
+ else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->snapPos + d->trackedItem->size())
+ d->setPosition(d->endPosition() - d->size());
+ else
+ d->setPosition(d->trackedItem->position() - d->snapPos);
+ break;
+ case SnapAuto:
+ d->setPosition(d->trackedItem->position() - d->snapPos);
+ break;
+ }
+ } else if (d->fixCurrentVisibility && d->currentItem && !d->pressed) {
+ /*
+ if (d->trackedItem->position() < d->position()
+ && d->currentItem->position() < d->position()) {
+ d->setPosition(d->trackedItem->position());
+ } else if (d->size() && d->trackedItem->size() <= d->size()
+ && d->trackedItem->endPosition() > d->position() + d->size()
+ && d->currentItem->endPosition() > d->position() + d->size()) {
+ d->setPosition(d->trackedItem->endPosition() - d->size());
+ }
+ if (d->trackedItem->position() == d->currentItem->position())
+ d->fixCurrentVisibility = false;
+ */
+ }
+}
+
+void QFxListView::itemResized()
+{
+ Q_D(QFxListView);
+ QFxItem *item = qobject_cast<QFxItem*>(sender());
+ if (item) {
+ d->activeItem = item; // Ick - don't delete the sender
+ d->layout();
+ d->activeItem = 0;
+ d->fixupPosition();
+ }
+}
+
+void QFxListView::itemsInserted(int modelIndex, int count)
+{
+ Q_D(QFxListView);
+ if (!d->visibleItems.count() || d->model->count() <= 1) {
+ refill();
+ d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1)));
+ emit countChanged();
+ return;
+ }
+
+ int index = d->mapFromModel(modelIndex);
+ if (index == -1) {
+ int i = d->visibleItems.count() - 1;
+ while (i > 0 && d->visibleItems.at(i)->index == -1)
+ --i;
+ if (d->visibleItems.at(i)->index + 1 == modelIndex) {
+ // Special case of appending an item to the model.
+ index = d->visibleIndex + d->visibleItems.count();
+ } else {
+ if (modelIndex + count - 1 < d->visibleIndex) {
+ // Insert before visible items
+ d->visibleIndex += count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxListItem *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem != d->currentItem)
+ listItem->index += count;
+ }
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem)
+ d->currentItem->index = d->currentIndex;
+ }
+ emit countChanged();
+ return;
+ }
+ }
+
+ // At least some of the added items will be visible
+ int insertCount = count;
+ if (index < d->visibleIndex) {
+ insertCount -= d->visibleIndex - index;
+ index = d->visibleIndex;
+ modelIndex = d->visibleIndex;
+ }
+
+ index -= d->visibleIndex;
+ int to = d->buffer+d->position()+d->size()-1;
+ // index can be the next item past the end of the visible items list (i.e. appended)
+ int pos = index < d->visibleItems.count() ? d->visibleItems.at(index)->position()
+ : d->visibleItems.at(index-1)->endPosition()+1;
+ int initialPos = pos;
+ QList<FxListItem*> added;
+ for (int i = 0; i < insertCount && pos <= to; ++i) {
+ FxListItem *item = d->createItem(modelIndex + i);
+ d->visibleItems.insert(index, item);
+ item->setPosition(pos);
+ added.append(item);
+ pos += item->size();
+ ++index;
+ }
+ if (d->currentIndex >= modelIndex) {
+ // adjust current item index
+ d->currentIndex += count;
+ if (d->currentItem) {
+ d->currentItem->index = d->currentIndex;
+ d->currentItem->setPosition(d->currentItem->position() + (pos - initialPos));
+ }
+ }
+ if (pos > to) {
+ // We didn't insert all our new items, which means anything
+ // beyond the current index is not visible - remove it.
+ while (d->visibleItems.count() > index)
+ d->releaseItem(d->visibleItems.takeLast());
+ } else {
+ // Update the indexes of the following visible items.
+ for (; index < d->visibleItems.count(); ++index) {
+ FxListItem *listItem = d->visibleItems.at(index);
+ if (listItem != d->currentItem) {
+ listItem->setPosition(listItem->position() + (pos - initialPos));
+ if (listItem->index != -1)
+ listItem->index += count;
+ }
+ }
+ }
+ // everything is in order now - emit add() signal
+ foreach(FxListItem *item, added)
+ item->attached->emitAdd();
+
+ emit countChanged();
+}
+
+void QFxListView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QFxListView);
+ int index = d->mapFromModel(modelIndex);
+ if (index == -1) {
+ if (modelIndex + count - 1 < d->visibleIndex) {
+ // Items removed before our visible items.
+ d->visibleIndex -= count;
+ for (int i = 0; i < d->visibleItems.count(); ++i) {
+ FxListItem *listItem = d->visibleItems.at(i);
+ if (listItem->index != -1 && listItem != d->currentItem)
+ listItem->index -= count;
+ }
+ }
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem) {
+ FxListItem *item = d->currentItem;
+ d->currentItem = 0;
+ d->releaseItem(item);
+ }
+ d->currentIndex = -1;
+ d->updateCurrent(qMin(modelIndex, d->model->count()-1));
+ }
+ emit countChanged();
+ return;
+ }
+
+ // Remove the items from the visible list, skipping anything already marked for removal
+ QList<FxListItem*>::Iterator it = d->visibleItems.begin();
+ while (it != d->visibleItems.end()) {
+ FxListItem *item = *it;
+ if (item->index == -1 || item->index < modelIndex) {
+ // already removed, or before removed items
+ ++it;
+ } else if (item->index >= modelIndex + count) {
+ // after removed items
+ if (item != d->currentItem)
+ item->index -= count;
+ ++it;
+ } else {
+ // removed item
+ item->attached->emitRemove();
+ if (item->attached->delayRemove()) {
+ item->index = -1;
+ connect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved()), Qt::QueuedConnection);
+ ++it;
+ } else {
+ it = d->visibleItems.erase(it);
+ d->releaseItem(item);
+ }
+ }
+ }
+
+ // fix current
+ if (d->currentIndex >= modelIndex + count) {
+ d->currentIndex -= count;
+ if (d->currentItem)
+ d->currentItem->index -= count;
+ } else if (d->currentIndex >= modelIndex && d->currentIndex < modelIndex + count) {
+ // current item has been removed.
+ if (d->currentItem && !d->currentItem->attached->delayRemove()) {
+ FxListItem *item = d->currentItem;
+ d->currentItem = 0;
+ d->releaseItem(item);
+ }
+ d->currentItem = 0;
+ d->currentIndex = -1;
+ d->updateCurrent(qMin(modelIndex, d->model->count()-1));
+ }
+
+ // update visibleIndex
+ for (it = d->visibleItems.begin(); it != d->visibleItems.end(); ++it) {
+ if ((*it)->index != -1) {
+ d->visibleIndex = (*it)->index;
+ break;
+ }
+ }
+
+ if (d->visibleItems.isEmpty()) {
+ d->visibleIndex = 0;
+ d->setPosition(0);
+ if (d->model->count() == 0)
+ update();
+ else
+ refill();
+ } else {
+ // Correct the positioning of the items
+ d->layout();
+ }
+
+ emit countChanged();
+}
+
+void QFxListView::destroyRemoved()
+{
+ Q_D(QFxListView);
+ for (QList<FxListItem*>::Iterator it = d->visibleItems.begin();
+ it != d->visibleItems.end();) {
+ FxListItem *listItem = *it;
+ if (listItem->index == -1 && listItem->attached->delayRemove() == false) {
+ d->releaseItem(listItem);
+ it = d->visibleItems.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Correct the positioning of the items
+ d->layout();
+}
+
+QObject *QFxListView::qmlAttachedProperties(QObject *obj)
+{
+ return QFxListViewAttached::properties(obj);
+}
+
+QML_DEFINE_TYPE(QFxListView,ListView);
+
+QT_END_NAMESPACE
+#include "qfxlistview.moc"
diff --git a/src/declarative/fx/qfxlistview.h b/src/declarative/fx/qfxlistview.h
new file mode 100644
index 0000000..f15db0c
--- /dev/null
+++ b/src/declarative/fx/qfxlistview.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXLISTVIEW_H
+#define QFXLISTVIEW_H
+
+#include <qfxflickable.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxVisualItemModel;
+class QFxListViewPrivate;
+class Q_DECLARATIVE_EXPORT QFxListView : public QFxFlickable
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QFxListView);
+
+ Q_ENUMS(CurrentItemPositioning);
+ Q_PROPERTY(QVariant model READ model WRITE setModel);
+ Q_CLASSINFO("DefaultProperty", "delegate");
+ Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate);
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged);
+ Q_PROPERTY(QFxItem *current READ currentItem NOTIFY currentIndexChanged);
+ Q_PROPERTY(int count READ count NOTIFY countChanged);
+ Q_PROPERTY(QmlComponent *highlight READ highlight WRITE setHighlight);
+ Q_PROPERTY(bool autoHighlight READ autoHighlight WRITE setAutoHighlight);
+ Q_PROPERTY(CurrentItemPositioning currentItemPositioning READ currentItemPositioning WRITE setCurrentItemPositioning);
+ Q_PROPERTY(int snapPosition READ snapPosition WRITE setSnapPosition);
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation);
+ Q_PROPERTY(bool wrap READ isWrapEnabled WRITE setWrapEnabled);
+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer);
+ Q_PROPERTY(QString sectionExpression READ sectionExpression WRITE setSectionExpression NOTIFY sectionExpressionChanged);
+ Q_PROPERTY(QString currentSection READ currentSection NOTIFY currentSectionChanged);
+
+public:
+ QFxListView(QFxItem *parent=0);
+ ~QFxListView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QmlComponent *delegate() const;
+ void setDelegate(QmlComponent *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ QFxItem *currentItem();
+ int count() const;
+
+ QmlComponent *highlight() const;
+ void setHighlight(QmlComponent *highlight);
+
+ bool autoHighlight() const;
+ void setAutoHighlight(bool);
+
+ enum CurrentItemPositioning { Free, Snap, SnapAuto };
+ CurrentItemPositioning currentItemPositioning() const;
+ void setCurrentItemPositioning(CurrentItemPositioning mode);
+
+ int snapPosition() const;
+ void setSnapPosition(int pos);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation);
+
+ bool isWrapEnabled() const;
+ void setWrapEnabled(bool);
+
+ int cacheBuffer() const;
+ void setCacheBuffer(int);
+
+ QString sectionExpression() const;
+ void setSectionExpression(const QString &);
+ QString currentSection() const;
+
+ virtual void setHeight(int height);
+ virtual void setWidth(int width);
+
+ static QObject *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void countChanged();
+ void currentIndexChanged();
+ void currentSectionChanged();
+ void sectionExpressionChanged();
+
+protected:
+ virtual void viewportMoved();
+ virtual qreal minYExtent() const;
+ virtual qreal maxYExtent() const;
+ virtual qreal minXExtent() const;
+ virtual qreal maxXExtent() const;
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+ virtual void componentComplete();
+
+private:
+ void refill();
+
+private Q_SLOTS:
+ void trackedPositionChanged();
+ void itemResized();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void destroyRemoved();
+};
+
+QML_DECLARE_TYPE(QFxListView);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/fx/qfxmouseregion.cpp b/src/declarative/fx/qfxmouseregion.cpp
new file mode 100644
index 0000000..2bf7aa7
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion.cpp
@@ -0,0 +1,589 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxmouseregion.h"
+#include "qfxmouseregion_p.h"
+#include <QGraphicsSceneMouseEvent>
+
+
+QT_BEGIN_NAMESPACE
+static const int DragThreshold = 5;
+static const int PressAndHoldDelay = 800;
+
+QML_DEFINE_TYPE(QFxDrag,Drag);
+QFxDrag::QFxDrag(QObject *parent)
+: QObject(parent), _target(0), _xmin(0), _xmax(0), _ymin(0), _ymax(0)
+{
+}
+
+QFxDrag::~QFxDrag()
+{
+}
+
+QFxItem *QFxDrag::target() const
+{
+ return _target;
+}
+
+void QFxDrag::setTarget(QFxItem *t)
+{
+ _target = t;
+}
+
+QString QFxDrag::axis() const
+{
+ return _axis;
+}
+
+void QFxDrag::setAxis(const QString &a)
+{
+ _axis = a;
+}
+
+/*!
+ \property QFxDrag::xmin
+ \brief the minimum x position for the target
+
+ If x-axis dragging is enabled, xmin limits how far to the left the target can be dragged. If x-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::xmin() const
+{
+ return _xmin;
+}
+
+void QFxDrag::setXmin(int m)
+{
+ _xmin = m;
+}
+
+/*!
+ \property QFxDrag::xmax
+ \brief the maximum x position for the target
+
+ If x-axis dragging is enabled, xmax limits how far to the right the target can be dragged. If x-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::xmax() const
+{
+ return _xmax;
+}
+
+void QFxDrag::setXmax(int m)
+{
+ _xmax = m;
+}
+
+/*!
+ \property QFxDrag::ymin
+ \brief the minimum y position for the target
+
+ If y-axis dragging is enabled, ymin limits how far up the target can be dragged. If y-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::ymin() const
+{
+ return _ymin;
+}
+
+void QFxDrag::setYmin(int m)
+{
+ _ymin = m;
+}
+
+/*!
+ \property QFxDrag::ymax
+ \brief the maximum y position for the target
+
+ If y-axis dragging is enabled, ymax limits how far down the target can be dragged. If y-axis dragging is not enabled, this property has no effect.
+*/
+int QFxDrag::ymax() const
+{
+ return _ymax;
+}
+
+void QFxDrag::setYmax(int m)
+{
+ _ymax = m;
+}
+
+/*!
+ \qmlclass MouseRegion
+ \brief The MouseRegion element enables simple mouse handling.
+ \inherits Item
+
+ A MouseRegion is typically used in conjunction with a visible element, where the MouseRegion effectively 'proxies' mouse handling for that element. For example, we can put a MouseRegion in a Rect that changes the Rect color to red when clicked:
+ \code
+ <Rect width="100" height="100">
+ <MouseRegion anchors.fill="{parent}" onClick="parent.color = 'red';"/>
+ </Rect>
+ \endcode
+
+ For the mouse handlers the variable mouseButton is set to be one of 'Left', 'Right', 'Middle',
+ or 'None'. This allows you to distinguish left and right clicking. Below we have the previous
+ example extended so as to give a different color when you right click.
+ \code
+ <Rect width="100" height="100">
+ <MouseRegion anchors.fill="{parent}" onClick="if(mouseButton=='Right') { parent.color='blue';} else { parent.color = 'red';}"/>
+ </Rect>
+ \endcode
+
+ For basic key handling, see \l KeyActions.
+
+ MouseRegion is an invisible element: it is never painted.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onEntered
+
+ This handler is called when the mouse enters the mouse region.
+
+ \warning This handler is not yet implemented.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onExited
+
+ This handler is called when the mouse exists the mouse region.
+
+ \warning This handler is not yet implemented.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onReenteredWhilePressed
+
+ This handler is called when the mouse reenters the mouse region while pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onExitedWhilePressed
+
+ This handler is called when the mouse exists the mouse region while pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onClicked
+
+ This handler is called when there is a click. A click is defined as a press followed by a release,
+ both inside the MouseRegion (pressing, moving outside the MouseRegion, and then moving back inside and
+ releasing is also considered a click).
+ The x and y parameters tell you the position of the release of the click. The followsPressAndHold parameter tells
+ you whether or not the release portion of the click followed a long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressed
+
+ This handler is called when there is a press.
+ The x and y parameters tell you the position of the press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onReleased
+
+ This handler is called when there is a release.
+ The x and y parameters tell you the position of the release. The isClick parameter tells you whether
+ or not the release is part of a click. The followsPressAndHold parameter tells you whether or not the
+ release followed a long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressAndHold
+
+ This handler is called when there is a long press (currently 800ms).
+ The x and y parameters tell you the position of the long press.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onDoubleClicked
+
+ This handler is called when there is a double-click (a press followed by a release followed by a press).
+ The x and y parameters tell you the position of the double-click.
+*/
+
+QML_DEFINE_TYPE(QFxMouseRegion,MouseRegion);
+/*!
+ \internal
+ \class QFxMouseRegion
+ \brief The QFxMouseRegion class provides a simple mouse handling abstraction for use within Qml.
+
+ \ingroup coreitems
+
+ All QFxItem derived classes can do mouse handling but the QFxMouseRegion class exposes mouse
+ handling data as properties and tracks flicking and dragging of the mouse.
+
+ A QFxMouseRegion object can be instantiated in Qml using the tag \l MouseRegion.
+ */
+QFxMouseRegion::QFxMouseRegion(QFxItem *parent)
+ : QFxItem(*(new QFxMouseRegionPrivate), parent)
+{
+ Q_D(QFxMouseRegion);
+ d->init();
+}
+
+QFxMouseRegion::QFxMouseRegion(QFxMouseRegionPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxMouseRegion);
+ d->init();
+}
+
+QFxMouseRegion::~QFxMouseRegion()
+{
+}
+
+/*!
+ \qmlproperty int MouseRegion::mouseX
+ \qmlproperty int MouseRegion::mouseY
+
+ The coordinates of the mouse while pressed. The coordinates are relative to the item that was pressed.
+*/
+int QFxMouseRegion::mouseX() const
+{
+ Q_D(const QFxMouseRegion);
+ return int(d->lastPos.x());
+}
+
+int QFxMouseRegion::mouseY() const
+{
+ Q_D(const QFxMouseRegion);
+ return int(d->lastPos.y());
+}
+
+/*!
+ \qmlproperty bool MouseRegion::enabled
+ This property holds whether the item accepts mouse events.
+*/
+bool QFxMouseRegion::isEnabled() const
+{
+ Q_D(const QFxMouseRegion);
+ return d->absorb;
+}
+
+void QFxMouseRegion::setEnabled(bool a)
+{
+ Q_D(QFxMouseRegion);
+ d->absorb = a;
+}
+
+void QFxMouseRegionPrivate::bindButtonValue(Qt::MouseButton b)
+{
+ Q_Q(QFxMouseRegion);
+ QString bString;
+ switch(b){
+ case Qt::LeftButton:
+ bString = QLatin1String("Left"); break;
+ case Qt::RightButton:
+ bString = QLatin1String("Right"); break;
+ case Qt::MidButton:
+ bString = QLatin1String("Middle"); break;
+ default:
+ bString = QLatin1String("None"); break;
+ }
+ q->itemContext()->setContextProperty(QLatin1String("mouseButton"), bString);
+}
+
+void QFxMouseRegion::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ d->moved = false;
+ if(!d->absorb)
+ QFxItem::mousePressEvent(event);
+ else {
+ if (!d->inside) {
+ d->inside = true;
+ emit hoveredChanged();
+ }
+ d->longPress = false;
+ d->lastPos = event->pos();
+ d->dragX = drag()->axis().contains(QLatin1String("x"));
+ d->dragY = drag()->axis().contains(QLatin1String("y"));
+ d->dragged = false;
+ d->start = event->pos();
+ d->startScene = event->scenePos();
+ // ### we should only start timer if pressAndHold is connected to (but connectNotify doesn't work)
+ d->pressAndHoldTimer.start(PressAndHoldDelay, this);
+ setKeepMouseGrab(false);
+ d->bindButtonValue(event->button());
+ setPressed(true);
+ emit positionChanged();
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb) {
+ QFxItem::mouseMoveEvent(event);
+ return;
+ }
+
+ d->lastPos = event->pos();
+
+ // ### we should skip this if these signals aren't used
+ const QRect &bounds = itemBoundingRect();
+ bool contains = bounds.contains(d->lastPos.toPoint());
+ if (d->inside && !contains) {
+ d->inside = false;
+ emit hoveredChanged();
+ emit exitedWhilePressed();
+ } else if (!d->inside && contains) {
+ d->inside = true;
+ emit hoveredChanged();
+ emit reenteredWhilePressed();
+ }
+
+ if(drag()->target()) {
+ if(!d->moved) {
+ if(d->dragX) d->startX = int(drag()->target()->x()); //### change startX and startY to qreal?
+ if(d->dragY) d->startY = int(drag()->target()->y());
+ }
+
+ QPointF startLocalPos;
+ QPointF curLocalPos;
+ if (drag()->target()->parent()) {
+ startLocalPos = drag()->target()->parent()->mapFromScene(d->startScene);
+ curLocalPos = drag()->target()->parent()->mapFromScene(event->scenePos());
+ } else {
+ startLocalPos = d->startScene;
+ curLocalPos = event->scenePos();
+ }
+
+ int dx = int(qAbs(curLocalPos.x() - startLocalPos.x()));
+ int dy = int(qAbs(curLocalPos.y() - startLocalPos.y()));
+ if ((d->dragX && !(dx < DragThreshold)) || (d->dragY && !(dy < DragThreshold)))
+ d->dragged = true;
+ if (!keepMouseGrab()) {
+ if ((!d->dragY && dy < DragThreshold && d->dragX && dx > DragThreshold)
+ || (!d->dragX && dx < DragThreshold && d->dragY && dy > DragThreshold)
+ || (d->dragX && d->dragY)) {
+ setKeepMouseGrab(true);
+ }
+ }
+
+ if(d->dragX) {
+ qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
+ if (x < drag()->xmin())
+ x = drag()->xmin();
+ else if (x > drag()->xmax())
+ x = drag()->xmax();
+ drag()->target()->setX(x);
+ }
+ if(d->dragY) {
+ qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
+ if (y < drag()->ymin())
+ y = drag()->ymin();
+ else if (y > drag()->ymax())
+ y = drag()->ymax();
+ drag()->target()->setY(y);
+ }
+ }
+ d->moved = true;
+ emit positionChanged();
+ event->accept();
+}
+
+
+void QFxMouseRegion::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::mouseReleaseEvent(event);
+ else {
+ setPressed(false);
+ //d->inside = false;
+ //emit hoveredChanged();
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::mouseDoubleClickEvent(event);
+ else {
+ //d->inside = true;
+ //emit hoveredChanged();
+ setPressed(true);
+ emit this->doubleClicked(d->lastPos.x(), d->lastPos.y());
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::hoverEnterEvent(event);
+ else {
+ setHovered(true);
+ emit entered();
+ }
+}
+
+void QFxMouseRegion::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if(!d->absorb)
+ QFxItem::hoverLeaveEvent(event);
+ else {
+ setHovered(false);
+ emit exited();
+ }
+}
+
+void QFxMouseRegion::mouseUngrabEvent()
+{
+ Q_D(QFxMouseRegion);
+ if (d->pressed) {
+ // if our mouse grab has been removed (probably by Flickable), fix our
+ // state
+ d->pressed = false;
+ //d->inside = false;
+ setKeepMouseGrab(false);
+ emit pressedChanged();
+ //emit hoveredChanged();
+ }
+}
+
+void QFxMouseRegion::timerEvent(QTimerEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if (event->timerId() == d->pressAndHoldTimer.timerId()) {
+ d->pressAndHoldTimer.stop();
+ if (d->pressed && d->dragged == false && d->inside == true) {
+ d->longPress = true;
+ emit pressAndHold(d->lastPos.x(), d->lastPos.y());
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool MouseRegion::containsMouse
+ This property holds whether the mouse is currently inside the mouse region.
+
+ \warning This property is only partially implemented -- it is only valid when the mouse is pressed, and not for hover events.
+*/
+bool QFxMouseRegion::hovered()
+{
+ Q_D(QFxMouseRegion);
+ return d->hovered || d->inside;
+}
+
+/*!
+ \qmlproperty bool MouseRegion::pressed
+ This property holds whether the mouse region is currently pressed.
+*/
+bool QFxMouseRegion::pressed()
+{
+ Q_D(QFxMouseRegion);
+ return d->pressed;
+}
+
+void QFxMouseRegion::setHovered(bool h)
+{
+ Q_D(QFxMouseRegion);
+ if(d->hovered != h) {
+ d->hovered = h;
+ emit hoveredChanged();
+ }
+}
+
+void QFxMouseRegion::setPressed(bool p)
+{
+ Q_D(QFxMouseRegion);
+ bool isclick = d->pressed == true && p == false && d->dragged == false && d->inside == true;
+
+ if(d->pressed != p) {
+ d->pressed = p;
+ if(d->pressed)
+ emit pressed(d->lastPos.x(), d->lastPos.y());
+ else {
+ emit released(d->lastPos.x(), d->lastPos.y(), isclick, d->longPress);
+ if (isclick)
+ emit clicked(d->lastPos.x(), d->lastPos.y(), d->longPress);
+ }
+
+ emit pressedChanged();
+ }
+}
+
+/*!
+ \property QFxMouseRegion::drag
+ \brief The current drag being performed on the Mouse Region.
+*/
+QFxDrag *QFxMouseRegion::drag()
+{
+ Q_D(QFxMouseRegion);
+ return &(d->drag);
+}
+
+/*!
+ \qmlproperty Item MouseRegion::drag.target
+ \qmlproperty string MouseRegion::drag.axis
+ \qmlproperty int MouseRegion::drag.xmin
+ \qmlproperty int MouseRegion::drag.xmax
+ \qmlproperty int MouseRegion::drag.ymin
+ \qmlproperty int MouseRegion::drag.ymax
+
+ drag provides a convenient way to make an item draggable.
+
+ \list
+ \i \c target specifies the item to drag.
+ \i \c axis specifies whether dragging can be done horizontally (x), vertically (y), or both (x,y)
+ \i the min and max properties limit how far the target can be dragged along the corresponding axes.
+ \endlist
+
+ The following example uses drag to blur an image as it moves to the right:
+ \code
+ <Item id="blurtest" width="600" height="200">
+ <Image id="pic" file="pic.png" anchors.verticalCenter="{parent.verticalCenter}" >
+ <filter><Blur radius="{pic.x/10}"/></filter>
+ <MouseRegion anchors.fill="{parent}"
+ drag.target="{pic}"
+ drag.axis="x"
+ drag.xmin="0"
+ drag.xmax="{blurtest.width-pic.width}" />
+ </Image>
+ </Item>
+ \endcode
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxmouseregion.h b/src/declarative/fx/qfxmouseregion.h
new file mode 100644
index 0000000..ee8b577
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXMOUSEREGION_H
+#define QFXMOUSEREGION_H
+
+#include <qfxitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT QFxDrag : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFxItem *target READ target WRITE setTarget)
+ Q_PROPERTY(QString axis READ axis WRITE setAxis)
+ Q_PROPERTY(int xmin READ xmin WRITE setXmin)
+ Q_PROPERTY(int xmax READ xmax WRITE setXmax)
+ Q_PROPERTY(int ymin READ ymin WRITE setYmin)
+ Q_PROPERTY(int ymax READ ymax WRITE setYmax)
+public:
+ QFxDrag(QObject *parent=0);
+ ~QFxDrag();
+
+ QFxItem *target() const;
+ void setTarget(QFxItem *);
+ QString axis() const;
+ void setAxis(const QString &);
+ int xmin() const;
+ void setXmin(int);
+ int xmax() const;
+ void setXmax(int);
+ int ymin() const;
+ void setYmin(int);
+ int ymax() const;
+ void setYmax(int);
+
+private:
+ QFxItem *_target;
+ QString _axis;
+ int _xmin;
+ int _xmax;
+ int _ymin;
+ int _ymax;
+ Q_DISABLE_COPY(QFxDrag)
+};
+QML_DECLARE_TYPE(QFxDrag);
+
+class QFxMouseRegionPrivate;
+class Q_DECLARATIVE_EXPORT QFxMouseRegion : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int mouseX READ mouseX NOTIFY positionChanged)
+ Q_PROPERTY(int mouseY READ mouseY NOTIFY positionChanged)
+ Q_PROPERTY(bool containsMouse READ hovered NOTIFY hoveredChanged)
+ Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
+ Q_PROPERTY(QFxDrag *drag READ drag)
+public:
+ QFxMouseRegion(QFxItem *parent=0);
+ ~QFxMouseRegion();
+
+ int mouseX() const;
+ int mouseY() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool);
+
+ bool hovered();
+ bool pressed();
+
+ void setHovered(bool);
+ void setPressed(bool);
+
+ QFxDrag *drag();
+
+Q_SIGNALS:
+ void hoveredChanged();
+ void pressedChanged();
+ void positionChanged();
+
+ void pressed(int x, int y);
+ void pressAndHold(int x, int y);
+ void released(int x, int y, bool isClick, bool followsPressAndHold);
+ void clicked(int x, int y, bool followsPressAndHold);
+ void doubleClicked(int x, int y);
+ void entered();
+ void exited();
+ void exitedWhilePressed();
+ void reenteredWhilePressed();
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+ void mouseUngrabEvent();
+ void timerEvent(QTimerEvent *event);
+
+private:
+ void handlePress();
+ void handleRelease();
+
+protected:
+ QFxMouseRegion(QFxMouseRegionPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxMouseRegion)
+ Q_DECLARE_PRIVATE(QFxMouseRegion)
+};
+QML_DECLARE_TYPE(QFxMouseRegion);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXMOUSEREGION_H
diff --git a/src/declarative/fx/qfxmouseregion_p.h b/src/declarative/fx/qfxmouseregion_p.h
new file mode 100644
index 0000000..09e1b98
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXMOUSEREGION_P_H
+#define QFXMOUSEREGION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdatetime.h"
+#include "qbasictimer.h"
+#include "qfxitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QFxMouseRegionPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxMouseRegion)
+
+public:
+ QFxMouseRegionPrivate()
+ : absorb(true), hovered(false), inside(true), pressed(false), longPress(0), drag(0)
+ {
+ }
+
+ void init()
+ {
+ Q_Q(QFxMouseRegion);
+ q->setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
+ q->setOptions(QSimpleCanvasItem::HoverEvents | QSimpleCanvasItem::MouseEvents);
+ }
+
+ void bindButtonValue(Qt::MouseButton);
+
+ bool absorb;
+ bool hovered;
+ bool inside;
+ bool pressed;
+ bool longPress;
+ QFxDrag drag;
+ bool moved;
+ bool dragX;
+ bool dragY;
+ bool dragged;
+ QPointF start;
+ QPointF startScene;
+ int startX;
+ int startY;
+ QPointF lastPos;
+ QBasicTimer pressAndHoldTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXMOUSEREGION_P_H
diff --git a/src/declarative/fx/qfxpainted.cpp b/src/declarative/fx/qfxpainted.cpp
new file mode 100644
index 0000000..a1eec69
--- /dev/null
+++ b/src/declarative/fx/qfxpainted.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxpainted.h"
+#include "qfxpainted_p.h"
+
+
+QT_BEGIN_NAMESPACE
+/*!
+ \class QFxPainted
+ \brief QFxPainted is an abstract base class for QFxView items that paint using QPainter.
+
+ \ingroup coreitems
+
+ This is a convenience class allowing easy use of QPainter within a custom item.
+ The contents of the item are cached behind the scenes. Any time you change the contents
+ you should call markDirty to make sure the cache is refreshed the next time painting occurs.
+
+ \code
+ class GradientRect : public QFxPainted
+ {
+ Q_OBJECT
+ public:
+ GradientRect() : QFxPainted()
+ {
+ connect(this, SIGNAL(widthChanged()), this, SLOT(markDirty()));
+ connect(this, SIGNAL(heightChanged()), this, SLOT(markDirty()));
+ }
+
+ void paint(QPainter *painter)
+ {
+ painter->fillRect(0, 0, width(), height(), QBrush(QLinearGradient(0,0,width(),height())));
+ }
+ };
+ \endcode
+
+ \warning Dirty is only ever automatically set by QFxPainted at construction. Any other changes (including resizes) to the item need to be handled by the subclass (as in the example above).
+ \warning Frequent calls to markDirty will result in sub-optimal painting performance.
+*/
+
+/*!
+ Constructs the painted item.
+*/
+
+//### what options do we need to set?
+QFxPainted::QFxPainted(QFxItem *parent)
+ : QFxItem(*(new QFxPaintedPrivate), parent)
+{
+ setOptions(HasContents, true);
+}
+
+/*!
+ Destroys the item.
+*/
+QFxPainted::~QFxPainted()
+{
+}
+
+/*! \internal
+*/
+QFxPainted::QFxPainted(QFxPaintedPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ setOptions(HasContents, true);
+}
+
+/*!
+ \fn QFxPainted::paint(QPainter *painter)
+
+ Implement this method to paint the item. The painting will be cached and
+ paint() will only be called again if \l markDirty() has been called.
+
+ \sa markDirty()
+*/
+
+/*!
+ The contents of the item are cached behind the scenes. Any time you change the contents
+ you should call markDirty to make sure the cache is refreshed the next time painting occurs.
+*/
+void QFxPainted::markDirty()
+{
+ Q_D(QFxPainted);
+ if (d->dirty)
+ return;
+ d->dirty = true;
+
+ // release cache memory (will be reallocated upon paintContents, if visible)
+#if defined(QFX_RENDER_QPAINTER)
+ d->cachedImage = QImage();
+#elif defined(QFX_RENDER_OPENGL)
+ d->cachedTexture.clear();
+#endif
+
+ update();
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxPainted::paintContents(QPainter &p)
+{
+ Q_D(QFxPainted);
+ if (d->dirty) {
+ d->cachedImage = QImage(width(), height(), QImage::Format_ARGB32_Premultiplied);
+ d->cachedImage.fill(0);
+ QPainter painter(&(d->cachedImage));
+ paint(&painter);
+ d->dirty = false;
+ }
+ p.drawImage(0, 0, d->cachedImage);
+}
+#elif defined(QFX_RENDER_OPENGL2)
+void QFxPainted::paintGLContents(GLPainter &painter)
+{
+ Q_D(QFxPainted);
+ if (d->dirty) {
+ QImage img = QImage(width(), height(), QImage::Format_ARGB32);
+ img.fill(0);
+ QPainter p(&(img));
+ paint(&p);
+ d->cachedTexture.setImage(img);
+ d->dirty = false;
+ }
+
+ //### mainly copied from QFxImage code
+ QGLShaderProgram *shader = painter.useTextureShader();
+
+ GLfloat vertices[8];
+ GLfloat texVertices[8];
+ GLTexture *tex = &d->cachedTexture;
+
+ float widthV = d->cachedTexture.width();
+ float heightV = d->cachedTexture.height();
+
+ vertices[0] = 0; vertices[1] = heightV;
+ vertices[2] = widthV; vertices[3] = heightV;
+ vertices[4] = 0; vertices[5] = 0;
+ vertices[6] = widthV; vertices[7] = 0;
+
+ texVertices[0] = 0; texVertices[1] = 0;
+ texVertices[2] = 1; texVertices[3] = 0;
+ texVertices[4] = 0; texVertices[5] = 1;
+ texVertices[6] = 1; texVertices[7] = 1;
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2);
+
+ glBindTexture(GL_TEXTURE_2D, tex->texture());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+}
+
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpainted.h b/src/declarative/fx/qfxpainted.h
new file mode 100644
index 0000000..32f5dcb
--- /dev/null
+++ b/src/declarative/fx/qfxpainted.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPAINTED_H
+#define QFXPAINTED_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxPaintedPrivate;
+class Q_DECLARATIVE_EXPORT QFxPainted : public QFxItem
+{
+Q_OBJECT
+public:
+ QFxPainted(QFxItem *parent);
+ ~QFxPainted();
+
+ virtual void paint(QPainter *painter) = 0;
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#elif defined(QFX_RENDER_OPENGL2)
+ void paintGLContents(GLPainter &);
+#endif
+
+protected Q_SLOTS:
+ void markDirty();
+
+protected:
+ QFxPainted(QFxPaintedPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxPainted)
+ Q_DECLARE_PRIVATE(QFxPainted)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXPAINTED_H
diff --git a/src/declarative/fx/qfxpainted_p.h b/src/declarative/fx/qfxpainted_p.h
new file mode 100644
index 0000000..68ac83e
--- /dev/null
+++ b/src/declarative/fx/qfxpainted_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPAINTED_P_H
+#define QFXPAINTED_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFxPaintedPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxPainted)
+
+public:
+ QFxPaintedPrivate()
+ : dirty(true)
+ {
+ }
+
+ bool dirty;
+
+#if defined(QFX_RENDER_QPAINTER)
+ QSimpleCanvasConfig::Image cachedImage;
+#elif defined(QFX_RENDER_OPENGL)
+ GLTexture cachedTexture;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXPAINTED_P_H
diff --git a/src/declarative/fx/qfxparticles.cpp b/src/declarative/fx/qfxparticles.cpp
new file mode 100644
index 0000000..3526541
--- /dev/null
+++ b/src/declarative/fx/qfxparticles.cpp
@@ -0,0 +1,1063 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "gfxtimeline.h"
+#include "qfxitem_p.h"
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#define M_PI_2 (M_PI / 2.)
+#endif
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+#include <qfxpixmap.h>
+#include <qfxperf.h>
+#include <private/qmlanimation_p.h>
+
+#include "qfxparticles.h"
+
+
+QT_BEGIN_NAMESPACE
+#define PI_SQR 9.8696044
+// parabolic approximation
+inline qreal fastSin(qreal theta)
+{
+ const qreal b = 4 / M_PI;
+ const qreal c = -4 / PI_SQR;
+
+ qreal y = b * theta + c * theta * qAbs(theta);
+ return y;
+}
+
+inline qreal fastCos(qreal theta)
+{
+ theta += M_PI_2;
+ if (theta > M_PI)
+ theta -= 2 * M_PI;
+
+ return fastSin(theta);
+}
+
+class QFxParticle
+{
+public:
+ QFxParticle(int time) : lifeSpan(1000), fadeOutAge(800)
+ , opacity(0), birthTime(time), x_velocity(0), y_velocity(0)
+ , state(FadeIn), data(0)
+ {
+ }
+
+ int lifeSpan;
+ int fadeOutAge;
+ qreal x;
+ qreal y;
+ qreal opacity;
+ int birthTime;
+ qreal x_velocity;
+ qreal y_velocity;
+ enum State { FadeIn, Solid, FadeOut };
+ State state;
+ void *data;
+};
+
+//---------------------------------------------------------------------------
+
+QML_DEFINE_TYPE(QFxParticleMotion,ParticleMotion);
+
+/*!
+ \class QFxParticleMotion
+ \ingroup effects
+ \brief The QFxParticleMotion class is the base class for particle motion.
+
+ This class causes the particles to remain static.
+
+ \sa QFxParticles
+*/
+QFxParticleMotion::QFxParticleMotion(QObject *parent) :
+ QObject(parent)
+{
+}
+
+/*!
+ Move the \a particle to its new position. \a interval is the number of
+ milliseconds elapsed since it was last moved.
+*/
+void QFxParticleMotion::advance(QFxParticle &particle, int interval)
+{
+ Q_UNUSED(particle);
+ Q_UNUSED(interval);
+}
+
+/*!
+ The \a particle has just been created. Some motion strategies require
+ additional state information. This can be allocated by this function.
+*/
+void QFxParticleMotion::created(QFxParticle &particle)
+{
+ Q_UNUSED(particle);
+}
+
+/*!
+ The \a particle is about to be destroyed. Any additional memory
+ that has been allocated for the particle should be freed.
+*/
+void QFxParticleMotion::destroy(QFxParticle &particle)
+{
+ Q_UNUSED(particle);
+}
+
+/*!
+ \qmlclass ParticleMotionLinear
+ \brief The ParticleMotionLinear element moves particles linearly.
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionLinear
+ \ingroup effects
+ \brief The QFxParticleMotionLinear class moves the particles linearly.
+
+ \sa QFxParticles
+*/
+
+QML_DEFINE_TYPE(QFxParticleMotionLinear,ParticleMotionLinear);
+
+void QFxParticleMotionLinear::advance(QFxParticle &p, int interval)
+{
+ p.x += interval * p.x_velocity;
+ p.y += interval * p.y_velocity;
+}
+
+/*!
+ \qmlclass ParticleMotionGravity
+ \brief The ParticleMotionGravity element moves particles towards a point.
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionGravity
+ \ingroup effects
+ \brief The QFxParticleMotionGravity class moves the particles towards a point.
+
+ \sa QFxParticles
+*/
+
+QML_DEFINE_TYPE(QFxParticleMotionGravity,ParticleMotionGravity);
+
+/*!
+ \qmlproperty int ParticleMotionGravity::xattractor
+ \qmlproperty int ParticleMotionGravity::yattractor
+ These properties hold the x and y coordinates of the point attracting the particles.
+*/
+
+/*!
+ \qmlproperty int ParticleMotionGravity::acceleration
+ This property holds the acceleration to apply to the particles.
+*/
+
+/*!
+ \property QFxParticleMotionGravity::xattractor
+ \brief the x coordinate of the point attracting the particles.
+*/
+
+/*!
+ \property QFxParticleMotionGravity::yattractor
+ \brief the y coordinate of the point attracting the particles.
+*/
+
+/*!
+ \property QFxParticleMotionGravity::acceleration
+ \brief the acceleration to apply to the particles.
+*/
+
+void QFxParticleMotionGravity::advance(QFxParticle &p, int interval)
+{
+ qreal xdiff = p.x - _xAttr;
+ qreal ydiff = p.y - _yAttr;
+
+ qreal xcomp = xdiff / (xdiff + ydiff);
+ qreal ycomp = ydiff / (xdiff + ydiff);
+
+ p.x_velocity += xcomp * _accel * interval;
+ p.y_velocity += ycomp * _accel * interval;
+
+ p.x += interval * p.x_velocity;
+ p.y += interval * p.y_velocity;
+}
+
+/*!
+ \qmlclass ParticleMotionWander
+ \brief The ParticleMotionWander element moves particles in a somewhat random fashion.
+
+ The particles will continue roughly in the original direction, however will randomly
+ drift to each side.
+
+ The code below produces an effect similar to falling snow.
+
+ \code
+ <Rect width="240" height="320" color="black">
+ <Particles y="0" width="{parent.width}" height="30"
+ src="star.png" lifeSpan="5000" count="50"
+ angle="70" angleDeviation="36"
+ velocity="30" velocityDeviation="10">
+ <ParticleMotionWander xvariance="30" pace="100"/>
+ </Particles>
+ </Rect>
+ \endcode
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionWander
+ \ingroup effects
+ \brief The QFxParticleMotionWander class moves particles in a somewhat random fashion.
+
+ The particles will continue roughly in the original direction, however will randomly
+ drift to each side.
+
+ \sa QFxParticles
+*/
+
+/*!
+ \qmlproperty QFxParticleMotionWander::xvariance
+ \qmlproperty QFxParticleMotionWander::yvariance
+
+ These properties set the amount to wander in the x and y directions.
+*/
+
+/*!
+ \qmlproperty QFxParticleMotionWander::pace
+ This property holds how quickly the paricles will move from side to side.
+*/
+
+QML_DEFINE_TYPE(QFxParticleMotionWander,ParticleMotionWander);
+
+void QFxParticleMotionWander::advance(QFxParticle &p, int interval)
+{
+ if (!particles)
+ particles = qobject_cast<QFxParticles*>(parent());
+ if (particles) {
+ Data *d = (Data*)p.data;
+ if (_xvariance != 0.) {
+ qreal xdiff = p.x_velocity - d->x_targetV;
+ if ((xdiff > d->x_peak && d->x_var > 0.0) || (xdiff < -d->x_peak && d->x_var < 0.0)) {
+ d->x_var = -d->x_var;
+ d->x_peak = _xvariance + _xvariance * qreal(rand()) / RAND_MAX;
+ }
+ p.x_velocity += d->x_var * interval;
+ }
+ p.x += interval * p.x_velocity;
+
+ if (_yvariance != 0.) {
+ qreal ydiff = p.y_velocity - d->y_targetV;
+ if ((ydiff > d->y_peak && d->y_var > 0.0) || (ydiff < -d->y_peak && d->y_var < 0.0)) {
+ d->y_var = -d->y_var;
+ d->y_peak = _yvariance + _yvariance * qreal(rand()) / RAND_MAX;
+ }
+ p.y_velocity += d->y_var * interval;
+ }
+ p.y += interval * p.y_velocity;
+ }
+}
+
+void QFxParticleMotionWander::created(QFxParticle &p)
+{
+ if (!p.data) {
+ Data *d = new Data;
+ p.data = (void*)d;
+ d->x_targetV = p.x_velocity;
+ d->y_targetV = p.y_velocity;
+ d->x_peak = _xvariance;
+ d->y_peak = _yvariance;
+ d->x_var = _pace * qreal(rand()) / RAND_MAX / 1000.0;
+ d->y_var = _pace * qreal(rand()) / RAND_MAX / 1000.0;
+ }
+}
+
+void QFxParticleMotionWander::destroy(QFxParticle &p)
+{
+ if (p.data)
+ delete (Data*)p.data;
+}
+
+//---------------------------------------------------------------------------
+class QFxParticlesPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxParticles)
+public:
+ QFxParticlesPrivate()
+ : count(1), lifeSpan(1000), lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300)
+ , angle(0), angleDev(0), velocity(0), velocityDev(0)
+ , addParticleTime(0), addParticleCount(0), lastAdvTime(0), stream(false), streamDelay(0)
+ , emitting(true), motion(0), clock(this)
+#if defined(QFX_RENDER_OPENGL)
+ , texDirty(true)
+#endif
+ {
+ }
+
+ ~QFxParticlesPrivate()
+ {
+ }
+
+ void init() {}
+ void tick(int time);
+ void createParticle(int time);
+ void updateOpacity(QFxParticle &p, int age);
+
+ QString source;
+ QUrl url;
+ QSimpleCanvasConfig::Image image;
+ int count;
+ int lifeSpan;
+ int lifeSpanDev;
+ int fadeInDur;
+ int fadeOutDur;
+ qreal angle;
+ qreal angleDev;
+ qreal velocity;
+ qreal velocityDev;
+ int addParticleTime;
+ int addParticleCount;
+ int lastAdvTime;
+ bool stream;
+ int streamDelay;
+ bool emitting;
+ QFxParticleMotion *motion;
+
+ QList<QFxParticle> particles;
+ QTickAnimationProxy<QFxParticlesPrivate, &QFxParticlesPrivate::tick> clock;
+
+#if defined(QFX_RENDER_OPENGL)
+ bool texDirty;
+ GLTexture tex;
+#endif
+};
+
+//TODO: Stop the clock if no visible particles and not emitting (restart on emittingChanged)
+void QFxParticlesPrivate::tick(int time)
+{
+ Q_Q(QFxParticles);
+ if (!motion)
+ motion = new QFxParticleMotionLinear(q);
+
+ int oldCount = particles.count();
+ int removed = 0;
+ int interval = time - lastAdvTime;
+ for (int i = 0; i < particles.count(); ) {
+ QFxParticle &particle = particles[i];
+ int age = time - particle.birthTime;
+ if (age >= particle.lifeSpan) {
+ QFxParticle part = particles.takeAt(i);
+ motion->destroy(part);
+ ++removed;
+ } else {
+ updateOpacity(particle, age);
+ motion->advance(particle, interval);
+ ++i;
+ }
+ }
+
+ while(removed-- && particles.count() < count && emitting)
+ createParticle(time);
+
+ if (!addParticleTime)
+ addParticleTime = time;
+
+ if(particles.count() < count && emitting) {
+ qreal perc = (lifeSpanDev <= 0)?(1.):(qreal(time - addParticleTime) / qreal(lifeSpanDev));
+ int percCount = addParticleCount + (int)perc * (count - addParticleCount);
+ int streamWidth = -1;
+ if(stream){
+ if(streamDelay > time){
+ streamWidth = 0;
+ }else{
+ int missed = time - streamDelay;
+ qreal streamWidthReal = qreal(count)/qreal(lifeSpan);
+ if(streamWidthReal < 1){
+ streamDelay = time + (int)(1.0/streamWidthReal);
+ streamWidth = 1;
+ streamWidth += missed/streamDelay;
+ }else{
+ streamWidth = qRound(streamWidthReal * (time-lastAdvTime));
+ }
+ }
+ }
+ while(particles.count() < count && particles.count() < percCount && streamWidth--)
+ createParticle(time);
+ }
+
+ lastAdvTime = time;
+ if (oldCount || particles.count()) {
+ if (q->itemParent())
+ q->itemParent()->update();
+ else
+ q->update();
+ } else if (!count) {
+ lastAdvTime = 0;
+ clock.stop();
+ }
+}
+
+void QFxParticlesPrivate::createParticle(int time)
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::CreateParticle> x;
+#endif
+ Q_Q(QFxParticles);
+ QFxParticle p(time);
+ p.x = q->x() + q->width() * qreal(rand()) / RAND_MAX - image.width()/2.0;
+ p.y = q->y() + q->height() * qreal(rand()) / RAND_MAX - image.height()/2.0;
+ p.lifeSpan = lifeSpan;
+ if (lifeSpanDev)
+ p.lifeSpan += int(lifeSpanDev/2 - lifeSpanDev * qreal(rand()) / RAND_MAX);
+ p.fadeOutAge = p.lifeSpan - fadeOutDur;
+ if (fadeInDur == 0.) {
+ p.state= QFxParticle::Solid;
+ p.opacity = 1.0;
+ }
+ qreal a = angle;
+ if (angleDev)
+ a += angleDev/2 - angleDev * qreal(rand()) / RAND_MAX;
+ if (a > M_PI)
+ a = a - 2 * M_PI;
+ qreal v = velocity;
+ if (velocityDev)
+ v += velocityDev/2 - velocityDev * qreal(rand()) / RAND_MAX;
+ p.x_velocity = v * fastCos(a);
+ p.y_velocity = v * fastSin(a);
+ particles.append(p);
+ motion->created(particles.last());
+}
+
+void QFxParticlesPrivate::updateOpacity(QFxParticle &p, int age)
+{
+ switch (p.state) {
+ case QFxParticle::FadeIn:
+ if (age <= fadeInDur) {
+ p.opacity = qreal(age) / fadeInDur;
+ break;
+ } else {
+ p.opacity = 1.0;
+ p.state = QFxParticle::Solid;
+ // Fall through
+ }
+ case QFxParticle::Solid:
+ if (age <= p.fadeOutAge) {
+ break;
+ } else {
+ p.state = QFxParticle::FadeOut;
+ // Fall through
+ }
+ case QFxParticle::FadeOut:
+ p.opacity = qreal(p.lifeSpan - age) / fadeOutDur;
+ break;
+ }
+}
+
+QML_DEFINE_TYPE(QFxParticles,Particles);
+
+/*!
+ \qmlclass Particles
+ \brief The Particles element generates and moves particles.
+ \inherits Item
+
+ The particles created by this element cannot be dealt with directly, they can only be controlled through the parameters of the Particles element. The particles are all the same pixmap, specified by the user.
+
+ The particles are painted relative to the parent of the Particles element. Moving the
+ Particles element will not move the particles already emitted.
+
+ The below example creates two differently behaving particle sources.
+ The top one has particles falling from the top like snow,
+ the lower one has particles expelled up like a fountain.
+
+ \code
+ <Rect width="240" height="320" color="black">
+ <Particles y="0" width="{parent.width}" height="30"
+ src="star.png" lifeSpan="5000" count="50"
+ angle="70" angleDeviation="36"
+ velocity="30" velocityDeviation="10">
+ <ParticleMotionWander xvariance="30" pace="100"/>
+ </Particles>
+ <Particles y="300" x="120" width="1" height="1"
+ src="star.png" lifeSpan="5000" count="200"
+ angle="270" angleDeviation="45"
+ velocity="50" velocityDeviation="30">
+ <ParticleMotionGravity yattractor="1000"
+ xattractor="0" acceleration="25"/>
+ </Particles>
+ </Rect>
+ \endcode
+ \image particles.gif
+*/
+
+/*!
+ \internal
+ \class QFxParticles
+ \ingroup effects
+ \brief The QFxParticles class generates and moves particles.
+*/
+
+QFxParticles::QFxParticles(QFxItem *parent)
+ : QFxItem(*(new QFxParticlesPrivate), parent)
+{
+ Q_D(QFxParticles);
+ d->init();
+ setOptions(HasContents);
+}
+
+QFxParticles::QFxParticles(QFxParticlesPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxParticles);
+ d->init();
+ setOptions(HasContents);
+}
+
+QFxParticles::~QFxParticles()
+{
+}
+
+/*!
+ \qmlproperty string Particles::src
+ This property holds the URL of the particle image.
+*/
+
+/*!
+ \property QFxParticles::src
+ \brief the URL of the particle image.
+*/
+QString QFxParticles::url() const
+{
+ Q_D(const QFxParticles);
+ return d->source;
+}
+
+void QFxParticles::imageLoaded()
+{
+ Q_D(QFxParticles);
+ d->image = QFxPixmap(d->url);
+#if defined(QFX_RENDER_OPENGL)
+ d->texDirty = true;
+ d->tex.clear();
+#endif
+ update();
+}
+
+void QFxParticles::setUrl(const QString &name)
+{
+ Q_D(QFxParticles);
+
+ if (name == d->source)
+ return;
+
+ if (!d->source.isEmpty())
+ QFxPixmap::cancelGet(d->url, this, SLOT(imageLoaded()));
+ if (name.isEmpty()) {
+ d->source = name;
+ d->url = QUrl();
+ d->image = QSimpleCanvasConfig::Image();
+#if defined(QFX_RENDER_OPENGL)
+ d->texDirty = true;
+ d->tex.clear();
+#endif
+ update();
+ } else {
+ d->source = name;
+ d->url = itemContext()->resolvedUrl(name);
+ QFxPixmap::get(itemContext()->engine(), d->url, this, SLOT(imageLoaded()));
+ }
+}
+
+/*!
+ \qmlproperty int Particles::count
+ This property holds the target number of particles
+*/
+
+/*!
+ \property QFxParticles::count
+ \brief the target number of particles
+*/
+int QFxParticles::count() const
+{
+ Q_D(const QFxParticles);
+ return d->count;
+}
+
+void QFxParticles::setCount(int cnt)
+{
+ Q_D(QFxParticles);
+ if (cnt != d->count) {
+ if (!d->count && d->clock.state() != QAbstractAnimation::Running)
+ d->clock.start(); // infinity??
+ d->count = cnt;
+ d->addParticleTime = 0;
+ d->addParticleCount = d->particles.count();
+ update();
+ }
+}
+
+/*!
+ \qmlproperty int Particles::lifeSpan
+ \qmlproperty int Particles::lifeSpanDeviation
+
+ These properties describe the life span of each particle.
+
+ The default lifespan for a particle is 1000ms.
+
+ lifeSpanDeviation randomly varies the lifeSpan up to the specified variation. For
+ example, the following creates particles whose lifeSpan will vary
+ from 150ms to 250ms:
+
+ \code
+ <Particles src="star.png" lifeSpan="200" lifeSpanDeviation="100"/>
+ \endcode
+*/
+
+/*!
+ \property QFxParticles::lifeSpan
+ \brief the life span of each particle.
+
+ Default value is 1000ms.
+
+ \sa QFxParticles::lifeSpanDeviation
+*/
+int QFxParticles::lifeSpan() const
+{
+ Q_D(const QFxParticles);
+ return d->lifeSpan;
+}
+
+void QFxParticles::setLifeSpan(int ls)
+{
+ Q_D(QFxParticles);
+ d->lifeSpan = ls;
+}
+
+/*!
+ \property QFxParticles::lifeSpanDeviation
+ \brief the maximum possible deviation from the set lifeSpan.
+
+ Randomly varies the lifeSpan up to the specified variation. For
+ example, the following creates particles whose lifeSpan will vary
+ from 150ms to 250ms:
+
+\code
+<Particles src="star.png" lifeSpan="200" lifeSpanDeviation="100"/>
+\endcode
+
+ \sa QFxParticles::lifeSpan
+*/
+int QFxParticles::lifeSpanDeviation() const
+{
+ Q_D(const QFxParticles);
+ return d->lifeSpanDev;
+}
+
+void QFxParticles::setLifeSpanDeviation(int dev)
+{
+ Q_D(QFxParticles);
+ d->lifeSpanDev = dev;
+}
+
+/*!
+ \qmlproperty int Particles::fadeInDuration
+ \qmlproperty int Particles::fadeOutDuration
+ These properties hold the time taken to fade the particles in and out.
+
+ By default fade in is 200ms and fade out is 300ms.
+*/
+
+/*!
+ \property QFxParticles::fadeInDuration
+ \brief the time taken to fade in the particles.
+
+ Default value is 200ms.
+*/
+int QFxParticles::fadeInDuration() const
+{
+ Q_D(const QFxParticles);
+ return d->fadeInDur;
+}
+
+void QFxParticles::setFadeInDuration(int dur)
+{
+ Q_D(QFxParticles);
+ if (dur >= 0.0)
+ d->fadeInDur = dur;
+}
+
+/*!
+ \property QFxParticles::fadeOutDuration
+ \brief the time taken to fade out the particles.
+
+ Default value is 300ms.
+*/
+int QFxParticles::fadeOutDuration() const
+{
+ Q_D(const QFxParticles);
+ return d->fadeOutDur;
+}
+
+void QFxParticles::setFadeOutDuration(int dur)
+{
+ Q_D(QFxParticles);
+ if (dur >= 0.0)
+ d->fadeOutDur = dur;
+}
+
+/*!
+ \qmlproperty real Particles::angle
+ \qmlproperty real Particles::angleDeviation
+
+ These properties control particle direction.
+
+ angleDeviation randomly varies the direction up to the specified variation. For
+ example, the following creates particles whose initial direction will
+ vary from 15 degrees to 105 degrees:
+
+ \code
+ <Particles src="star.png" angle="60" angleDeviation="90"/>
+ \endcode
+*/
+
+/*!
+ \property QFxParticles::angle
+ \brief the initial angle of direction.
+
+ \sa QFxParticles::angleDeviation
+*/
+qreal QFxParticles::angle() const
+{
+ Q_D(const QFxParticles);
+ return d->angle * 180.0 / M_PI;
+}
+
+void QFxParticles::setAngle(qreal angle)
+{
+ Q_D(QFxParticles);
+ d->angle = angle * M_PI / 180.0;
+}
+
+/*!
+ \property QFxParticles::angleDeviation
+ \brief the maximum possible deviation from the set angle.
+
+ Randomly varies the direction up to the specified variation. For
+ example, the following creates particles whose initial direction will
+ vary from 15 degrees to 105 degrees:
+
+\code
+<Particles src="star.png" angle="60" angleDeviation="90"/>
+\endcode
+
+ \sa QFxParticles::angle
+*/
+qreal QFxParticles::angleDeviation() const
+{
+ Q_D(const QFxParticles);
+ return d->angleDev * 180.0 / M_PI;
+}
+
+void QFxParticles::setAngleDeviation(qreal dev)
+{
+ Q_D(QFxParticles);
+ d->angleDev = dev * M_PI / 180.0;;
+}
+
+/*!
+ \qmlproperty real Particles::velocity
+ \qmlproperty real Particles::velocityDeviation
+
+ These properties control the velocity of the particles.
+
+ velocityDeviation randomly varies the velocity up to the specified variation. For
+ example, the following creates particles whose initial velocity will
+ vary from 40 to 60.
+
+ \code
+ <Particles src="star.png" velocity="50" velocityDeviation="20"/>
+ \endcode
+*/
+
+/*!
+ \property QFxParticles::velocity
+ \brief the initial velocity of the particles.
+
+ \sa QFxParticles::velocityDeviation
+*/
+qreal QFxParticles::velocity() const
+{
+ Q_D(const QFxParticles);
+ return d->velocity * 1000.0;
+}
+
+void QFxParticles::setVelocity(qreal velocity)
+{
+ Q_D(QFxParticles);
+ d->velocity = velocity / 1000.0;
+}
+
+/*!
+ \property QFxParticles::velocityDeviation
+ \brief the maximum possible deviation from the set velocity.
+
+ Randomly varies the velocity up to the specified variation. For
+ example, the following creates particles whose initial velocity will
+ vary from 40 to 60.
+
+\code
+<Particles src="star.png" velocity="50" velocityDeviation="20"/>
+\endcode
+
+ \sa QFxParticles::velocity
+*/
+qreal QFxParticles::velocityDeviation() const
+{
+ Q_D(const QFxParticles);
+ return d->velocityDev * 1000.0;
+}
+
+void QFxParticles::setVelocityDeviation(qreal velocity)
+{
+ Q_D(QFxParticles);
+ d->velocityDev = velocity / 1000.0;
+}
+
+/*!
+ \qmlproperty bool Particles::streamIn
+ This property determines whether the particles stream in at a constant rate
+
+ When stream is set to true the particles will stream in at a constant rate.
+ Otherwise the particles will appear as a clump. Note that this only affects the
+ start of the particle effect, variables such as lifespan deviation can cause the
+ particles to unclump over time.
+*/
+/*!
+ \property QFxParticles::streamIn
+ \brief determines whether the particles stream in at a constant rate
+
+ When stream is set to true the particles will stream in at a constant rate.
+ Otherwise the particles will appear as a clump. Note that this only affects the
+ start of the particle effect, variables such as lifespan deviation can cause the
+
+*/
+//The name may need a rethink
+bool QFxParticles::streamIn() const
+{
+ Q_D(const QFxParticles);
+ return d->stream;
+}
+
+void QFxParticles::setStreamIn(bool b)
+{
+ Q_D(QFxParticles);
+ d->stream = b;
+}
+
+/*!
+ \qmlproperty bool Particles::emitting
+ This property determines whether new particles are created
+
+ If emitting is set to false no new particles will be created. This means that
+ when a particle reaches the end of its lifespan it is not replaced. This
+ property can be used to turn particles on and off with a more natural look.
+
+ The default setting is true. Note that if it initialized to false no particles
+ will be produced until it is set to true.
+*/
+/*!
+ \property bool Particles::emitting
+ If emitting is set to false no new particles will be created. This means that
+ when a particle reaches the end of its lifespan it is not replaced. This
+ property can be used to turn particles on and off with a more natural look.
+
+ The default setting is true. Note that if it initialized to false no particles
+ will be produced until it is set to true.
+*/
+bool QFxParticles::emitting() const
+{
+ Q_D(const QFxParticles);
+ return d->emitting;
+}
+
+void QFxParticles::setEmitting(bool r)
+{
+ Q_D(QFxParticles);
+ d->emitting = r;
+}
+/*!
+ \qmlproperty ParticleMotion Particles::motion
+ This property sets the type of motion to apply to the particles.
+
+ When a particle is created it will have an initial direction and velocity.
+ The motion of the particle during its lifeSpan is then influenced by the
+ motion property.
+
+ Default motion is ParticleMotionLinear.
+*/
+
+/*!
+ \property QFxParticles::motion
+ \brief sets the type of motion to apply to the particles.
+
+ When a particle is created it will have an initial direction and velocity.
+ The motion of the particle during its lifeSpan is then influenced by the
+ motion property.
+
+ Default motion is QFxParticleMotionLinear.
+*/
+QFxParticleMotion *QFxParticles::motion() const
+{
+ Q_D(const QFxParticles);
+ return d->motion;
+}
+
+void QFxParticles::setMotion(QFxParticleMotion *motion)
+{
+ Q_D(QFxParticles);
+ d->motion = motion;
+}
+
+void QFxParticles::dump(int depth)
+{
+ Q_D(QFxParticles);
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << "URL:" << d->url << "Count:" << d->count;
+ QFxItem::dump(depth);
+}
+
+QString QFxParticles::propertyInfo() const
+{
+ Q_D(const QFxParticles);
+ return d->url.toString();
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxParticles::paintContents(QPainter &p)
+{
+ Q_D(QFxParticles);
+ if (d->image.isNull())
+ return;
+
+ const int myX = x();
+ const int myY = y();
+ for (int i = 0; i < d->particles.count(); ++i) {
+ const QFxParticle &particle = d->particles.at(i);
+ p.setOpacity(particle.opacity);
+ p.drawImage(particle.x-myX, particle.y-myY, d->image);
+ }
+}
+#elif defined(QFX_RENDER_OPENGL2)
+void QFxParticles::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxParticles);
+ if (d->image.isNull())
+ return;
+
+ if (d->texDirty && !d->image.isNull()) {
+ d->tex.setImage(d->image);
+ d->tex.setHorizontalWrap(GLTexture::Repeat);
+ d->tex.setVerticalWrap(GLTexture::Repeat);
+ }
+ d->texDirty = false;
+
+ SingleTextureOpacityShader *shader = basicShaders()->singleTextureOpacity();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+
+ glBindTexture(GL_TEXTURE_2D, d->tex.texture());
+
+ const int myX = (int)x();
+ const int myY = (int)y();
+ float widthV = d->image.width();
+ float heightV = d->image.height();
+ for (int i = 0; i < d->particles.count(); ++i) {
+ const QFxParticle &particle = d->particles.at(i);
+ float left = particle.x - myX;
+ float right = particle.x - myX + widthV;
+ float top = particle.y - myY;
+ float bottom = particle.y - myY + heightV;
+
+ GLfloat vertices[] = { left, bottom,
+ right, bottom,
+ left, top,
+ right, top };
+
+ GLfloat texVertices[] = { 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1 };
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2);
+ shader->setOpacity(particle.opacity * p.activeOpacity);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+}
+#endif
+
+void QFxParticles::componentComplete()
+{
+ Q_D(QFxParticles);
+ QFxItem::componentComplete();
+ if (d->count)
+ d->clock.start(); // infinity??
+ if (d->lifeSpanDev > d->lifeSpan)
+ d->lifeSpanDev = d->lifeSpan;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxparticles.h b/src/declarative/fx/qfxparticles.h
new file mode 100644
index 0000000..d9c810d
--- /dev/null
+++ b/src/declarative/fx/qfxparticles.h
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPARTICLES_H
+#define QFXPARTICLES_H
+
+#include <qfxitem.h>
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QFxParticle;
+class QFxParticles;
+class QFxParticleMotion : public QObject
+{
+ Q_OBJECT
+public:
+ QFxParticleMotion(QObject *parent=0);
+
+ virtual void advance(QFxParticle &, int interval);
+ virtual void created(QFxParticle &);
+ virtual void destroy(QFxParticle &);
+};
+QML_DECLARE_TYPE(QFxParticleMotion);
+
+class QFxParticleMotionLinear : public QFxParticleMotion
+{
+ Q_OBJECT
+public:
+ QFxParticleMotionLinear(QObject *parent=0)
+ : QFxParticleMotion(parent) {}
+
+ virtual void advance(QFxParticle &, int interval);
+};
+QML_DECLARE_TYPE(QFxParticleMotionLinear);
+
+class QFxParticleMotionGravity : public QFxParticleMotion
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int xattractor READ xAttractor WRITE setXAttractor)
+ Q_PROPERTY(int yattractor READ yAttractor WRITE setYAttractor)
+ Q_PROPERTY(int acceleration READ acceleration WRITE setAcceleration)
+public:
+ QFxParticleMotionGravity(QObject *parent=0)
+ : QFxParticleMotion(parent), _xAttr(0), _yAttr(0), _accel(0.00005) {}
+
+ int xAttractor() const { return _xAttr; }
+ void setXAttractor(int x) { _xAttr = x; }
+
+ int yAttractor() const { return _yAttr; }
+ void setYAttractor(int y) { _yAttr = y; }
+
+ int acceleration() const { return int(_accel * 1000000); }
+ void setAcceleration(int accel) { _accel = qreal(accel)/1000000.0; }
+
+ virtual void advance(QFxParticle &, int interval);
+
+private:
+ int _xAttr;
+ int _yAttr;
+ qreal _accel;
+};
+QML_DECLARE_TYPE(QFxParticleMotionGravity);
+
+class QFxParticleMotionWander : public QFxParticleMotion
+{
+ Q_OBJECT
+public:
+ QFxParticleMotionWander()
+ : QFxParticleMotion(), particles(0), _xvariance(0), _yvariance(0) {}
+
+ virtual void advance(QFxParticle &, int interval);
+ virtual void created(QFxParticle &);
+ virtual void destroy(QFxParticle &);
+
+ struct Data {
+ qreal x_targetV;
+ qreal y_targetV;
+ qreal x_peak;
+ qreal y_peak;
+ qreal x_var;
+ qreal y_var;
+ };
+
+ Q_PROPERTY(int xvariance READ xVariance WRITE setXVariance);
+ int xVariance() const { return int(_xvariance * 1000); }
+ void setXVariance(int var) { _xvariance = var / 1000.0; }
+
+ Q_PROPERTY(int yvariance READ yVariance WRITE setYVariance);
+ int yVariance() const { return int(_yvariance * 1000); }
+ void setYVariance(int var) { _yvariance = var / 1000.0; }
+
+ Q_PROPERTY(int pace READ pace WRITE setPace);
+ int pace() const { return int(_pace * 1000); }
+ void setPace(int pace) { _pace = pace / 1000.0; }
+
+private:
+ QFxParticles *particles;
+ qreal _xvariance;
+ qreal _yvariance;
+ qreal _pace;
+};
+QML_DECLARE_TYPE(QFxParticleMotionWander);
+
+class QFxParticlesPrivate;
+class Q_DECLARATIVE_EXPORT QFxParticles : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString src READ url WRITE setUrl);
+ Q_PROPERTY(int count READ count WRITE setCount);
+ Q_PROPERTY(int lifeSpan READ lifeSpan WRITE setLifeSpan);
+ Q_PROPERTY(int lifeSpanDeviation READ lifeSpanDeviation WRITE setLifeSpanDeviation);
+ Q_PROPERTY(int fadeInDuration READ fadeInDuration WRITE setFadeInDuration);
+ Q_PROPERTY(int fadeOutDuration READ fadeOutDuration WRITE setFadeOutDuration);
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle);
+ Q_PROPERTY(qreal angleDeviation READ angleDeviation WRITE setAngleDeviation);
+ Q_PROPERTY(qreal velocity READ velocity WRITE setVelocity);
+ Q_PROPERTY(qreal velocityDeviation READ velocityDeviation WRITE setVelocityDeviation);
+ Q_PROPERTY(bool streamIn READ streamIn WRITE setStreamIn);
+ Q_PROPERTY(bool emitting READ emitting WRITE setEmitting);
+ Q_PROPERTY(QFxParticleMotion *motion READ motion WRITE setMotion);
+ Q_CLASSINFO("DefaultProperty", "motion");
+
+public:
+ QFxParticles(QFxItem *parent=0);
+ ~QFxParticles();
+
+ QString url() const;
+ void setUrl(const QString &);
+
+ int count() const;
+ void setCount(int cnt);
+
+ int lifeSpan() const;
+ void setLifeSpan(int);
+
+ int lifeSpanDeviation() const;
+ void setLifeSpanDeviation(int);
+
+ int fadeInDuration() const;
+ void setFadeInDuration(int);
+
+ int fadeOutDuration() const;
+ void setFadeOutDuration(int);
+
+ qreal angle() const;
+ void setAngle(qreal);
+
+ qreal angleDeviation() const;
+ void setAngleDeviation(qreal);
+
+ qreal velocity() const;
+ void setVelocity(qreal);
+
+ qreal velocityDeviation() const;
+ void setVelocityDeviation(qreal);
+
+ bool streamIn() const;
+ void setStreamIn(bool);
+
+ bool emitting() const;
+ void setEmitting(bool);
+
+ QFxParticleMotion *motion() const;
+ void setMotion(QFxParticleMotion *);
+
+ virtual void dump(int depth);
+ virtual QString propertyInfo() const;
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &p);
+#elif defined(QFX_RENDER_OPENGL2)
+ void paintGLContents(GLPainter &);
+#endif
+
+protected:
+ virtual void componentComplete();
+ QFxParticles(QFxParticlesPrivate &dd, QFxItem *parent);
+
+private Q_SLOTS:
+ void imageLoaded();
+
+private:
+ Q_DISABLE_COPY(QFxParticles)
+ Q_DECLARE_PRIVATE(QFxParticles)
+};
+QML_DECLARE_TYPE(QFxParticles);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/declarative/fx/qfxpath.cpp b/src/declarative/fx/qfxpath.cpp
new file mode 100644
index 0000000..199f5fb
--- /dev/null
+++ b/src/declarative/fx/qfxpath.cpp
@@ -0,0 +1,745 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxpath.h"
+#include "qfxpath_p.h"
+#include <qfxperf.h>
+#include <private/qbezier_p.h>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxPath,Path);
+QML_DEFINE_TYPE(QFxPathElement,PathElement);
+QML_DEFINE_TYPE(QFxCurve,Curve);
+QML_DEFINE_TYPE(QFxPathAttribute,PathAttribute);
+QML_DEFINE_TYPE(QFxPathPercent,PathPercent);
+QML_DEFINE_TYPE(QFxPathLine,PathLine);
+QML_DEFINE_TYPE(QFxPathQuad,PathQuad);
+QML_DEFINE_TYPE(QFxPathCubic,PathCubic);
+
+/*!
+ \qmlclass Path
+ \brief The Path element defines a path for use by \l PathView.
+
+ \sa PathElement, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+
+/*!
+ \internal
+ \class QFxPath
+ \ingroup utility
+ \brief The QFxPath class defines a path.
+ \sa QFxPathView
+*/
+QFxPath::QFxPath(QObject *parent)
+ : QObject(*(new QFxPathPrivate), parent)
+{
+}
+
+QFxPath::QFxPath(QFxPathPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+}
+
+QFxPath::~QFxPath()
+{
+}
+
+/*!
+ \qmlproperty int Path::startX
+ This property holds the starting x position of the path.
+*/
+
+/*!
+ \property QFxPath::startX
+ \brief the starting x position of the path.
+*/
+
+int QFxPath::startX() const
+{
+ Q_D(const QFxPath);
+ return d->startX;
+}
+
+void QFxPath::setStartX(int x)
+{
+ Q_D(QFxPath);
+ d->startX = x;
+}
+
+/*!
+ \qmlproperty int Path::startY
+ This property holds the starting y position of the path.
+*/
+
+/*!
+ \property QFxPath::startY
+ \brief the starting y position of the path.
+*/
+
+int QFxPath::startY() const
+{
+ Q_D(const QFxPath);
+ return d->startY;
+}
+
+void QFxPath::setStartY(int y)
+{
+ Q_D(QFxPath);
+ d->startY = y;
+}
+
+/*!
+ \qmlproperty list<PathElement> Path::pathElements
+ This property holds the elements composing the path.
+
+ \default
+
+ A path can contain the following path elements:
+ \list
+ \i \l PathLine - a straight line to a given position.
+ \i \l PathQuad - a quadratic Bezier curve to a given position with a control point.
+ \i \l PathCubic - a cubic Bezier curve to a given position with two control points.
+ \i \l PathAttribute - an attribute at a given position in the path.
+ \i \l PathPercent - a way to spread out items along various segments of the path.
+ \endlist
+
+ \code
+ <Path startX="240" startY="350">
+ <PathAttribute name="scale" value="1.0"/>
+ <PathAttribute name="opacity" value="1"/>
+ <PathQuad x="240" y="150" controlX="660" controlY="250"/>
+ <PathAttribute name="scale" value="0.1"/>
+ <PathAttribute name="opacity" value="-0.5"/>
+ <PathCubic x="240" y="350" control1X="-180" control1Y="250" control2X="0" control2Y="25"/>
+ </Path>
+ \endcode
+*/
+
+QList<QFxPathElement *>* QFxPath::pathElements()
+{
+ Q_D(QFxPath);
+ return &(d->_pathElements);
+}
+
+void QFxPath::interpolate(int idx, const QString &name, qreal value)
+{
+ Q_D(QFxPath);
+ if(!idx)
+ return;
+
+ qreal lastValue = 0;
+ qreal lastPercent = 0;
+ int search = idx - 1;
+ while(search >= 0) {
+ const AttributePoint &point = d->_attributePoints.at(search);
+ if(point.values.contains(name)) {
+ lastValue = point.values.value(name);
+ lastPercent = point.origpercent;
+ break;
+ }
+ --search;
+ }
+
+ ++search;
+
+ const AttributePoint &curPoint = d->_attributePoints.at(idx);
+
+ for(int ii = search; ii < idx; ++ii) {
+ AttributePoint &point = d->_attributePoints[ii];
+
+ qreal val = lastValue + (value - lastValue) * (point.origpercent - lastPercent) / (curPoint.origpercent - lastPercent);
+ point.values.insert(name, val);
+ }
+}
+
+void QFxPath::endpoint(const QString &name)
+{
+ Q_D(QFxPath);
+ const AttributePoint &first = d->_attributePoints.first();
+ qreal val = first.values.value(name);
+ for(int ii = d->_attributePoints.count() - 1; ii >= 0; ii--) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if(point.values.contains(name)) {
+ for(int jj = ii + 1; jj < d->_attributePoints.count(); ++jj) {
+ AttributePoint &setPoint = d->_attributePoints[jj];
+ setPoint.values.insert(name, val);
+ }
+ return;
+ }
+ }
+}
+
+void QFxPath::processPath()
+{
+ Q_D(QFxPath);
+
+ d->_pointCache.clear();
+ d->_attributePoints.clear();
+ d->_path = QPainterPath();
+
+ AttributePoint first;
+ for(int ii = 0; ii < d->_attributes.count(); ++ii)
+ first.values[d->_attributes.at(ii)] = 0;
+ d->_attributePoints << first;
+
+ d->_path.moveTo(d->startX, d->startY);
+
+ foreach (QFxPathElement *pathElement, d->_pathElements) {
+ if(QFxCurve *curve = qobject_cast<QFxCurve *>(pathElement)) {
+ curve->addToPath(d->_path);
+ AttributePoint p;
+ p.origpercent = d->_path.length();
+ d->_attributePoints << p;
+ } else if(QFxPathAttribute *attribute = qobject_cast<QFxPathAttribute *>(pathElement)) {
+ AttributePoint &point = d->_attributePoints.last();
+ point.values[attribute->name()] = attribute->value();
+ interpolate(d->_attributePoints.count() - 1, attribute->name(), attribute->value());
+ } else if(QFxPathPercent *percent = qobject_cast<QFxPathPercent *>(pathElement)) {
+ AttributePoint &point = d->_attributePoints.last();
+ point.values[QLatin1String("_qfx_percent")] = percent->value();
+ interpolate(d->_attributePoints.count() - 1, QLatin1String("_qfx_percent"), percent->value());
+ }
+ }
+
+ // Fixup end points
+ const AttributePoint &last = d->_attributePoints.last();
+ for(int ii = 0; ii < d->_attributes.count(); ++ii) {
+ if(!last.values.contains(d->_attributes.at(ii)))
+ endpoint(d->_attributes.at(ii));
+ }
+
+ // Adjust percent
+ qreal length = d->_path.length();
+ qreal prevpercent = 0;
+ qreal prevorigpercent = 0;
+ for(int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if(point.values.contains(QLatin1String("_qfx_percent"))) { //special string for QFxPathPercent
+ if ( ii > 0) {
+ qreal scale = (d->_attributePoints[ii].origpercent/length - prevorigpercent) /
+ (point.values.value(QLatin1String("_qfx_percent"))-prevpercent);
+ d->_attributePoints[ii].scale = scale;
+ }
+ d->_attributePoints[ii].origpercent /= length;
+ d->_attributePoints[ii].percent = point.values.value(QLatin1String("_qfx_percent"));
+ prevorigpercent = d->_attributePoints[ii].origpercent;
+ prevpercent = d->_attributePoints[ii].percent;
+ } else {
+ d->_attributePoints[ii].origpercent /= length;
+ d->_attributePoints[ii].percent = d->_attributePoints[ii].origpercent;
+ }
+ }
+
+ emit changed();
+}
+
+void QFxPath::componentComplete()
+{
+ Q_D(QFxPath);
+ QSet<QString> attrs;
+ // First gather up all the attributes
+ foreach (QFxPathElement *pathElement, d->_pathElements) {
+ if(QFxPathAttribute *attribute =
+ qobject_cast<QFxPathAttribute *>(pathElement))
+ attrs.insert(attribute->name());
+ }
+ d->_attributes = attrs.toList();
+
+ processPath();
+
+ foreach (QFxPathElement *pathElement, d->_pathElements)
+ connect(pathElement, SIGNAL(changed()), this, SLOT(processPath()));
+}
+
+QPainterPath QFxPath::path() const
+{
+ Q_D(const QFxPath);
+ return d->_path;
+}
+
+QStringList QFxPath::attributes() const
+{
+ Q_D(const QFxPath);
+ return d->_attributes;
+}
+#include <QTime>
+
+static inline QBezier nextBezier(const QPainterPath &path, int *from, qreal *bezLength)
+{
+ const int lastElement = path.elementCount() - 1;
+ for (int i=*from; i <= lastElement; ++i) {
+ const QPainterPath::Element &e = path.elementAt(i);
+
+ switch (e.type) {
+ case QPainterPath::MoveToElement:
+ break;
+ case QPainterPath::LineToElement:
+ {
+ QLineF line(path.elementAt(i-1), e);
+ *bezLength = line.length();
+ QPointF a = path.elementAt(i-1);
+ QPointF delta = e - a;
+ *from = i+1;
+ return QBezier::fromPoints(a, a + delta / 3, a + 2 * delta / 3, e);
+ }
+ case QPainterPath::CurveToElement:
+ {
+ QBezier b = QBezier::fromPoints(path.elementAt(i-1),
+ e,
+ path.elementAt(i+1),
+ path.elementAt(i+2));
+ *bezLength = b.length();
+ *from = i+3;
+ return b;
+ }
+ default:
+ break;
+ }
+ }
+ *from = lastElement;
+ *bezLength = 0;
+ return QBezier();
+}
+
+void QFxPath::createPointCache() const
+{
+ Q_D(const QFxPath);
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::PathCache> pc;
+#endif
+ qreal pathLength = d->_path.length();
+ const int points = int(pathLength*2);
+ const int lastElement = d->_path.elementCount() - 1;
+ d->_pointCache.resize(points+1);
+
+ int currElement = 0;
+ qreal bezLength = 0;
+ QBezier currBez = nextBezier(d->_path, &currElement, &bezLength);
+ qreal currLength = bezLength;
+ qreal epc = currLength / pathLength;
+
+ for (int i = 0; i < d->_pointCache.size(); i++) {
+ //find which set we are in
+ qreal prevPercent = 0;
+ qreal prevOrigPercent = 0;
+ for(int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ qreal percent = qreal(i)/points;
+ const AttributePoint &point = d->_attributePoints.at(ii);
+ if(percent < point.percent || ii == d->_attributePoints.count() - 1) { //### || is special case for very last item
+ qreal elementPercent = (percent - prevPercent);
+
+ qreal spc = prevOrigPercent + elementPercent * point.scale;
+
+ while (spc > epc) {
+ if (currElement > lastElement)
+ break;
+ currBez = nextBezier(d->_path, &currElement, &bezLength);
+ if (bezLength == 0.0) {
+ currLength = pathLength;
+ epc = 1.0;
+ break;
+ }
+ currLength += bezLength;
+ epc = currLength / pathLength;
+ }
+ qreal realT = (pathLength * spc - (currLength - bezLength)) / bezLength;
+ d->_pointCache[i] = currBez.pointAt(qBound(qreal(0), realT, qreal(1)));
+ break;
+ }
+ prevOrigPercent = point.origpercent;
+ prevPercent = point.percent;
+ }
+ }
+}
+
+QPointF QFxPath::pointAt(qreal p) const
+{
+ Q_D(const QFxPath);
+ if (d->_pointCache.isEmpty()) {
+ createPointCache();
+ }
+ int idx = qRound(p*d->_pointCache.size());
+ if (idx >= d->_pointCache.size())
+ idx = d->_pointCache.size() - 1;
+ else if (idx < 0)
+ idx = 0;
+ return d->_pointCache.at(idx);
+}
+
+qreal QFxPath::attributeAt(const QString &name, qreal percent) const
+{
+ Q_D(const QFxPath);
+ if(percent < 0 || percent > 1)
+ return 0;
+
+ for(int ii = 0; ii < d->_attributePoints.count(); ++ii) {
+ const AttributePoint &point = d->_attributePoints.at(ii);
+
+ if(point.percent == percent) {
+ return point.values.value(name);
+ } else if(point.percent > percent) {
+ qreal lastValue =
+ ii?(d->_attributePoints.at(ii - 1).values.value(name)):0;
+ qreal lastPercent =
+ ii?(d->_attributePoints.at(ii - 1).percent):0;
+ qreal curValue = point.values.value(name);
+ qreal curPercent = point.percent;
+
+ return lastValue + (curValue - lastValue) * (percent - lastPercent) / (curPercent - lastPercent);
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+
+int QFxCurve::x() const
+{
+ return _x;
+}
+
+void QFxCurve::setX(int x)
+{
+ if (_x != x) {
+ _x = x;
+ emit changed();
+ }
+}
+
+int QFxCurve::y() const
+{
+ return _y;
+}
+
+void QFxCurve::setY(int y)
+{
+ if (_y != y) {
+ _y = y;
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathAttribute
+ \brief The PathAttribute allows to set an attribute at a given position in the path.
+*/
+
+/*!
+ \internal
+ \class QFxPathAttribute
+ \ingroup utility
+ \brief The QFxPathAttribute class allows to set the value of an attribute at a given position in the path.
+
+ \sa QFxPath
+*/
+
+
+/*!
+ \qmlproperty string PathAttribute::name
+ the name of the attribute to change.
+*/
+
+/*!
+ the name of the attribute to change.
+*/
+
+QString QFxPathAttribute::name() const
+{
+ return _name;
+}
+
+void QFxPathAttribute::setName(const QString &name)
+{
+ _name = name;
+}
+
+/*!
+ \qmlproperty string PathAttribute::value
+ the new value of the attribute.
+*/
+
+/*!
+ the new value of the attribute.
+*/
+qreal QFxPathAttribute::value() const
+{
+ return _value;
+}
+
+void QFxPathAttribute::setValue(qreal value)
+{
+ if (_value != value) {
+ _value = value;
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathLine
+ \brief The PathLine defines a straight line.
+
+*/
+
+/*!
+ \internal
+ \class QFxPathLine
+ \ingroup utility
+ \brief The QFxPathLine class defines a straight line.
+
+ \sa QFxPath
+*/
+
+void QFxPathLine::addToPath(QPainterPath &path)
+{
+ path.lineTo(x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathQuad
+ \brief The PathQuad defines a quadratic Bezier curve with a control point.
+
+*/
+
+/*!
+ \internal
+ \class QFxPathQuad
+ \ingroup utility
+ \brief The QFxPathQuad class defines a quadratic Bezier curve with a control point.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlproperty string PathQuad::controlX
+ the x position of the control point.
+*/
+
+/*!
+ the x position of the control point.
+*/
+int QFxPathQuad::controlX() const
+{
+ return _controlX;
+}
+
+void QFxPathQuad::setControlX(int x)
+{
+ if (_controlX != x) {
+ _controlX = x;
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty string PathQuad::controlY
+ the y position of the control point.
+*/
+
+/*!
+ the y position of the control point.
+*/
+int QFxPathQuad::controlY() const
+{
+ return _controlY;
+}
+
+void QFxPathQuad::setControlY(int y)
+{
+ if (_controlY != y) {
+ _controlY = y;
+ emit changed();
+ }
+}
+
+void QFxPathQuad::addToPath(QPainterPath &path)
+{
+ path.quadTo(controlX(), controlY(), x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathCubic
+ \brief The PathCubic defines a cubic Bezier curve with two control points.
+
+*/
+
+/*!
+ \internal
+ \class QFxPathCubic
+ \ingroup utility
+ \brief The QFxPathCubic class defines a cubic Bezier curve with two control points.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlproperty string PathCubic::control1X
+ the x position of the first control point.
+*/
+
+/*!
+ \property QFxPathCubic::control1X
+ \brief the x position of the first control point.
+*/
+int QFxPathCubic::control1X() const
+{
+ return _control1X;
+}
+
+void QFxPathCubic::setControl1X(int x)
+{
+ if (_control1X != x) {
+ _control1X = x;
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty string PathCubic::control1Y
+ the y position of the first control point.
+*/
+
+/*!
+ \property QFxPathCubic::control1Y
+ \brief the y position of the first control point.
+*/
+int QFxPathCubic::control1Y() const
+{
+ return _control1Y;
+}
+
+void QFxPathCubic::setControl1Y(int y)
+{
+ if (_control1Y != y) {
+ _control1Y = y;
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty string PathCubic::control2X
+ the x position of the second control point.
+*/
+
+/*!
+ \property QFxPathCubic::control2X
+ \brief the x position of the second control point.
+*/
+int QFxPathCubic::control2X() const
+{
+ return _control2X;
+}
+
+void QFxPathCubic::setControl2X(int x)
+{
+ if (_control2X != x) {
+ _control2X = x;
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty string PathCubic::control2Y
+ the y position of the second control point.
+*/
+
+/*!
+ \property QFxPathCubic::control2Y
+ \brief the y position of the second control point.
+*/
+int QFxPathCubic::control2Y() const
+{
+ return _control2Y;
+}
+
+void QFxPathCubic::setControl2Y(int y)
+{
+ if (_control2Y != y) {
+ _control2Y = y;
+ emit changed();
+ }
+}
+
+void QFxPathCubic::addToPath(QPainterPath &path)
+{
+ path.cubicTo(control1X(), control1Y(), control2X(), control2Y(), x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathPercent
+ \brief The PathPercent manipulates the way a path is interpreted.
+
+*/
+
+/*!
+ \internal
+ \class QFxPathPercent
+ \ingroup utility
+ \brief The QFxPathPercent class manipulates the way a path is interpreted.
+
+ QFxPathPercent allows you to bunch up items (or spread out items) along various
+ segments of a QFxPathView's path.
+
+ \sa QFxPath
+
+*/
+
+qreal QFxPathPercent::value() const
+{
+ return _value;
+}
+
+void QFxPathPercent::setValue(qreal value)
+{
+ _value = value;
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpath.h b/src/declarative/fx/qfxpath.h
new file mode 100644
index 0000000..a9c48ed
--- /dev/null
+++ b/src/declarative/fx/qfxpath.h
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPATH_H
+#define QFXPATH_H
+
+#include <QObject>
+#include <QPainterPath>
+#include <qml.h>
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxPathElement : public QObject
+{
+ Q_OBJECT
+public:
+ QFxPathElement(QObject *parent=0) : QObject(parent) {}
+Q_SIGNALS:
+ void changed();
+};
+QML_DECLARE_TYPE(QFxPathElement);
+
+class Q_DECLARATIVE_EXPORT QFxPathAttribute : public QFxPathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY changed)
+public:
+ QFxPathAttribute(QObject *parent=0) : QFxPathElement(parent), _value(0) {}
+
+
+ QString name() const;
+ void setName(const QString &name);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+private:
+ QString _name;
+ qreal _value;
+};
+QML_DECLARE_TYPE(QFxPathAttribute);
+
+class Q_DECLARATIVE_EXPORT QFxCurve : public QFxPathElement
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int x READ x WRITE setX NOTIFY changed)
+ Q_PROPERTY(int y READ y WRITE setY NOTIFY changed)
+public:
+ QFxCurve(QObject *parent=0) : QFxPathElement(parent), _x(0), _y(0) {}
+
+ int x() const;
+ void setX(int x);
+
+ int y() const;
+ void setY(int y);
+
+ virtual void addToPath(QPainterPath &) {}
+
+private:
+ int _x;
+ int _y;
+};
+QML_DECLARE_TYPE(QFxCurve);
+
+class Q_DECLARATIVE_EXPORT QFxPathLine : public QFxCurve
+{
+ Q_OBJECT
+public:
+ QFxPathLine(QObject *parent=0) : QFxCurve(parent) {}
+
+ void addToPath(QPainterPath &path);
+};
+QML_DECLARE_TYPE(QFxPathLine);
+
+class Q_DECLARATIVE_EXPORT QFxPathQuad : public QFxCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int controlX READ controlX WRITE setControlX NOTIFY changed)
+ Q_PROPERTY(int controlY READ controlY WRITE setControlY NOTIFY changed)
+public:
+ QFxPathQuad(QObject *parent=0) : QFxCurve(parent), _controlX(0), _controlY(0) {}
+
+ int controlX() const;
+ void setControlX(int x);
+
+ int controlY() const;
+ void setControlY(int y);
+
+ void addToPath(QPainterPath &path);
+
+private:
+ int _controlX;
+ int _controlY;
+};
+QML_DECLARE_TYPE(QFxPathQuad);
+
+class Q_DECLARATIVE_EXPORT QFxPathCubic : public QFxCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int control1X READ control1X WRITE setControl1X NOTIFY changed)
+ Q_PROPERTY(int control1Y READ control1Y WRITE setControl1Y NOTIFY changed)
+ Q_PROPERTY(int control2X READ control2X WRITE setControl2X NOTIFY changed)
+ Q_PROPERTY(int control2Y READ control2Y WRITE setControl2Y NOTIFY changed)
+public:
+ QFxPathCubic(QObject *parent=0) : QFxCurve(parent), _control1X(0), _control1Y(0), _control2X(0), _control2Y(0) {}
+
+ int control1X() const;
+ void setControl1X(int x);
+
+ int control1Y() const;
+ void setControl1Y(int y);
+
+ int control2X() const;
+ void setControl2X(int x);
+
+ int control2Y() const;
+ void setControl2Y(int y);
+
+ void addToPath(QPainterPath &path);
+
+private:
+ int _control1X;
+ int _control1Y;
+ int _control2X;
+ int _control2Y;
+};
+QML_DECLARE_TYPE(QFxPathCubic);
+
+class Q_DECLARATIVE_EXPORT QFxPathPercent : public QFxPathElement
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal value READ value WRITE setValue)
+public:
+ QFxPathPercent(QObject *parent=0) : QFxPathElement(parent) {}
+
+ qreal value() const;
+ void setValue(qreal value);
+
+private:
+ qreal _value;
+};
+QML_DECLARE_TYPE(QFxPathPercent);
+
+class QFxPathPrivate;
+class Q_DECLARATIVE_EXPORT QFxPath : public QObject, public QmlParserStatus
+{
+ Q_OBJECT
+
+ Q_INTERFACES(QmlParserStatus);
+ Q_PROPERTY(QList<QFxPathElement *>* pathElements READ pathElements)
+ Q_PROPERTY(int startX READ startX WRITE setStartX)
+ Q_PROPERTY(int startY READ startY WRITE setStartY)
+ Q_CLASSINFO("DefaultProperty", "pathElements")
+ Q_INTERFACES(QmlParserStatus)
+public:
+ QFxPath(QObject *parent=0);
+ ~QFxPath();
+
+ QList<QFxPathElement *>* pathElements();
+
+ int startX() const;
+ void setStartX(int x);
+
+ int startY() const;
+ void setStartY(int y);
+
+ QPainterPath path() const;
+ QStringList attributes() const;
+ qreal attributeAt(const QString &, qreal) const;
+ QPointF pointAt(qreal) const;
+
+Q_SIGNALS:
+ void changed();
+
+protected:
+ virtual void componentComplete();
+ QFxPath(QFxPathPrivate &dd, QObject *parent);
+
+private Q_SLOTS:
+ void processPath();
+
+private:
+ struct AttributePoint {
+ AttributePoint() : percent(0), scale(1), origpercent(0) {}
+ AttributePoint(const AttributePoint &other)
+ : percent(other.percent), scale(other.scale), origpercent(other.origpercent), values(other.values) {}
+ AttributePoint &operator=(const AttributePoint &other) {
+ percent = other.percent; scale = other.scale; origpercent = other.origpercent; values = other.values; return *this;
+ }
+ qreal percent; //massaged percent along the painter path
+ qreal scale;
+ qreal origpercent; //'real' percent along the painter path
+ QHash<QString, qreal> values;
+ };
+
+ void interpolate(int idx, const QString &name, qreal value);
+ void endpoint(const QString &name);
+ void createPointCache() const;
+
+private:
+ Q_DISABLE_COPY(QFxPath)
+ Q_DECLARE_PRIVATE(QFxPath)
+};
+QML_DECLARE_TYPE(QFxPath);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXPATH_H
diff --git a/src/declarative/fx/qfxpath_p.h b/src/declarative/fx/qfxpath_p.h
new file mode 100644
index 0000000..d4a419a
--- /dev/null
+++ b/src/declarative/fx/qfxpath_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPATH_P_H
+#define QFXPATH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qobject_p.h"
+#include "qfxpath.h"
+#include "qml.h"
+
+
+QT_BEGIN_NAMESPACE
+class QFxPathPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QFxPath)
+
+public:
+ QFxPathPrivate() : startX(0), startY(0) { }
+
+ QPainterPath _path;
+ QList<QFxPathElement*> _pathElements;
+ mutable QVector<QPointF> _pointCache;
+ QList<QFxPath::AttributePoint> _attributePoints;
+ QStringList _attributes;
+ int startX;
+ int startY;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxpathview.cpp b/src/declarative/fx/qfxpathview.cpp
new file mode 100644
index 0000000..79b0f8e
--- /dev/null
+++ b/src/declarative/fx/qfxpathview.cpp
@@ -0,0 +1,841 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <math.h>
+#include <QDebug>
+#include <QPen>
+#include <QEvent>
+#include <gfxeasing.h>
+#include "qmlbindablevalue.h"
+#include "qmlstate.h"
+#include "qlistmodelinterface.h"
+#include "qmlopenmetaobject.h"
+
+#include "qfxpathview.h"
+#include "qfxpathview_p.h"
+#include <QGraphicsSceneEvent>
+#include <QTimer>
+
+static const int FlickThreshold = 5;
+
+QT_BEGIN_NAMESPACE
+
+QML_DEFINE_TYPE(QFxPathView,PathView);
+
+class QFxPathViewAttached : public QObject
+{
+ Q_OBJECT
+public:
+ QFxPathViewAttached(QObject *parent)
+ : QObject(parent), mo(new QmlOpenMetaObject(this))
+ {
+ }
+
+ QVariant value(const QByteArray &name) const
+ {
+ return mo->value(name);
+ }
+ void setValue(const QByteArray &name, const QVariant &val)
+ {
+ mo->setValue(name, val);
+ }
+
+private:
+ QmlOpenMetaObject *mo;
+};
+
+
+/*!
+ \internal
+ \class QFxPathView
+ \brief The QFxPathView class lays out items provided by a model on a path.
+
+ \ingroup views
+
+ The model must be a \l QListModelInterface subclass.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlclass PathView
+ \brief The PathView element lays out model-provided items on a path.
+ \inherits Item
+
+ The model is typically provided by a QAbstractListModel "C++ model object", but can also be created directly in XML.
+
+ The items are laid out along a path defined by a \l Path and may be flicked to scroll.
+
+ \code
+ <PathView id="pathview" delegate="{contactDelegate}">
+ <resources><Component id="contactDelegate">...</Component></resources>
+ <model>...</model>
+ <path>...</path>
+ </PathView>
+ \endcode
+
+ \image pathview.gif
+
+ \sa Path
+*/
+
+QFxPathView::QFxPathView(QFxItem *parent)
+ : QFxItem(*(new QFxPathViewPrivate), parent)
+{
+ Q_D(QFxPathView);
+ d->init();
+}
+
+QFxPathView::QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxPathView);
+ d->init();
+}
+
+QFxPathView::~QFxPathView()
+{
+}
+
+/*!
+ \qmlproperty model PathView::model
+ This property holds the model providing data for the view.
+
+ The model provides a set of data that is used to create the items for the view.
+ For large or dynamic datasets the model is usually provided by a C++ model object.
+ However, models can also be created directly in XML, for example:
+ \code
+<model>
+ <ListModel>
+ <Contact>
+ <portrait>pics/john.png</portrait>
+ <firstName>John</firstName>
+ <lastName>Smith</lastName>
+ </Contact>
+ <Contact>
+ <portrait>pics/bill.png</portrait>
+ <firstName>Bill</firstName>
+ <lastName>Jones</lastName>
+ </Contact>
+ <Contact>
+ <portrait>pics/jane.png</portrait>
+ <firstName>Jane</firstName>
+ <lastName>Doe</lastName>
+ </Contact>
+ </ListModel>
+</model>
+ \endcode
+*/
+
+/*!
+ \property QFxPathView::model
+ \brief the model providing data for the view.
+
+ The model must be either a \l QListModelInterface or
+ \l QFxVisualItemModel subclass.
+*/
+QVariant QFxPathView::model() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->model() : QVariant();
+}
+
+void QFxPathView::setModel(const QVariant &model)
+{
+ Q_D(QFxPathView);
+ if (QFxVisualItemModel *m = qvariant_cast<QFxVisualItemModel*>(model)) {
+ if (d->ownModel) {
+ delete d->model;
+ d->ownModel = false;
+ }
+ d->model = m;
+ } else {
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel;
+ d->ownModel = true;
+ }
+ d->model->setModel(model);
+ }
+ d->regenerate();
+ d->fixOffset();
+}
+
+/*!
+ \qmlproperty int PathView::count
+ This property holds the number of items in the model.
+*/
+int QFxPathView::count() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->count() : 0;
+}
+
+/*!
+ \qmlproperty Path PathView::path
+ \default
+ This property holds the path used to lay out the items.
+ For more information see the \l Path documentation.
+*/
+QFxPath *QFxPathView::path() const
+{
+ Q_D(const QFxPathView);
+ return d->path;
+}
+
+void QFxPathView::setPath(QFxPath *path)
+{
+ Q_D(QFxPathView);
+ d->path = path;
+ connect(d->path, SIGNAL(changed()), this, SLOT(refill()));
+ d->regenerate();
+}
+
+/*!
+ \qmlproperty int PathView::currentIndex
+ This property holds the index of the current item.
+*/
+int QFxPathView::currentIndex() const
+{
+ Q_D(const QFxPathView);
+ return d->currentIndex;
+}
+
+void QFxPathView::setCurrentIndex(int idx)
+{
+ Q_D(QFxPathView);
+ if (d->model && d->model->count())
+ idx = qAbs(idx % d->model->count());
+ if (d->model && idx != d->currentIndex) {
+ d->currentIndex = idx;
+ d->snapToCurrent();
+ int itemIndex = (idx - d->firstIndex + d->model->count()) % d->model->count();
+ if(itemIndex < d->items.count())
+ d->items.at(itemIndex)->setFocus(true);
+ emit currentIndexChanged();
+ }
+}
+
+/*!
+ \qmlproperty real PathView::offset
+
+ The offset specifies how far along the path the items are from their initial positions.
+*/
+qreal QFxPathView::offset() const
+{
+ Q_D(const QFxPathView);
+ return d->_offset;
+}
+
+void QFxPathView::setOffset(qreal offset)
+{
+ Q_D(QFxPathView);
+ d->setOffset(offset);
+ d->updateCurrent();
+}
+
+void QFxPathViewPrivate::setOffset(qreal o)
+{
+ Q_Q(QFxPathView);
+ if (_offset != o) {
+ _offset = fmod(o, 100.0);
+ if (_offset < 0)
+ _offset = 100.0 + _offset;
+ q->refill();
+ }
+}
+
+/*!
+ \qmlproperty real PathView::snapPosition
+ This property holds the position (0-100) the current item snaps to.
+*/
+
+/*!
+ \property QFxPathView::snapPosition
+ \brief sets the position (0-100) the current item snaps to.
+
+ This property determines the position the nearest item will snap to.
+*/
+qreal QFxPathView::snapPosition() const
+{
+ Q_D(const QFxPathView);
+ return d->snapPos;
+}
+
+void QFxPathView::setSnapPosition(qreal pos)
+{
+ Q_D(QFxPathView);
+ d->snapPos = pos/100;
+ d->fixOffset();
+}
+
+/*!
+ \qmlproperty real PathView::dragMargin
+ This property holds the maximum distance from the path that initiate mouse dragging.
+
+ By default the path can only be dragged by clicking on an item. If
+ dragMargin is greater than zero, a drag can be initiated by clicking
+ within dragMargin pixels of the path.
+*/
+qreal QFxPathView::dragMargin() const
+{
+ Q_D(const QFxPathView);
+ return d->dragMargin;
+}
+
+void QFxPathView::setDragMargin(qreal dragMargin)
+{
+ Q_D(QFxPathView);
+ d->dragMargin = dragMargin;
+}
+
+/*!
+ \qmlproperty component PathView::delegate
+
+ The delegate provides a template describing what each item in the view should look and act like.
+
+ Here is an example delegate:
+ \code
+ <PathView delegate="{contactDelegate}" ...>
+ <resources>
+ <Component id="contactDelegate">
+ <Item id="wrapper" scale="{PathView.sc}" opacity="{PathView.op}" z="{PathView.z}">
+ <Image id="pic" width="100" height="100" file="{portrait}"
+ anchors.horizontalCenter="{parent.horizontalCenter}"/>
+ <Text id="name" text="{firstName + ' ' + lastName}"
+ font.size="20"
+ anchors.top="{pic.bottom}" anchors.topMargin="5"
+ anchors.horizontalCenter="{parent.horizontalCenter}"/>
+ </Item>
+ </Component>
+ </resources>
+ ...
+ </PathView>
+ \endcode
+*/
+
+/*!
+ \property QFxPathView::delegate
+ \brief the component to use to render the items.
+
+ The delegate is a component that the view will instantiate and destroy
+ as needed to display the items.
+
+*/
+QmlComponent *QFxPathView::delegate() const
+{
+ Q_D(const QFxPathView);
+ return d->model ? d->model->delegate() : 0;
+}
+
+void QFxPathView::setDelegate(QmlComponent *c)
+{
+ Q_D(QFxPathView);
+ if (!d->ownModel) {
+ d->model = new QFxVisualItemModel;
+ d->ownModel = true;
+ }
+ d->model->setDelegate(c);
+ d->regenerate();
+}
+
+/*!
+ \property QFxPathView::pathItemCount
+ \brief the number of items visible on the path at any one time
+ */
+/*!
+ \qmlproperty int PathView::pathItemCount
+ This property holds the number of items visible on the path at any one time
+*/
+int QFxPathView::pathItemCount() const
+{
+ Q_D(const QFxPathView);
+ return d->pathItems;
+}
+
+void QFxPathView::setPathItemCount(int i)
+{
+ Q_D(QFxPathView);
+ if(i == d->pathItems)
+ return;
+ d->pathItems = i;
+ d->regenerate();
+}
+
+QPointF QFxPathViewPrivate::pointNear(const QPointF &point, qreal *nearPercent) const
+{
+ //XXX maybe do recursively at increasing resolution.
+ qreal mindist = 1e10; // big number
+ QPointF nearPoint = path->pointAt(0);
+ qreal nearPc = 0;
+ for (qreal i=1; i < 1000; i++) {
+ QPointF pt = path->pointAt(i/1000.0);
+ QPointF diff = pt - point;
+ qreal dist = diff.x()*diff.x() + diff.y()*diff.y();
+ if (dist < mindist) {
+ nearPoint = pt;
+ nearPc = i;
+ mindist = dist;
+ }
+ }
+
+ if (nearPercent)
+ *nearPercent = nearPc / 10.0;
+
+ return nearPoint;
+}
+
+
+void QFxPathView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ QPointF scenePoint = mapToScene(event->pos());
+ int idx = 0;
+ for (; idx < d->items.count(); ++idx) {
+ QRectF rect = d->items.at(idx)->boundingRect();
+ rect = d->items.at(idx)->mapToScene(rect);
+ if (rect.contains(scenePoint))
+ break;
+ }
+ if (idx == d->items.count() && d->dragMargin == 0.) // didn't click on an item
+ return;
+
+ d->startPoint = d->pointNear(event->pos(), &d->startPc);
+ if (idx == d->items.count()) {
+ qreal distance = qAbs(event->pos().x() - d->startPoint.x()) + qAbs(event->pos().y() - d->startPoint.y());
+ if (distance > d->dragMargin)
+ return;
+ }
+
+ d->stealMouse = false;
+ d->lastElapsed = 0;
+ d->lastDist = 0;
+ d->lastPosTime.start();
+ d->tl.clear();
+}
+
+void QFxPathView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ if (d->lastPosTime.isNull())
+ return;
+
+ if (!d->stealMouse) {
+ QPointF delta = event->pos() - d->startPoint;
+ if (qAbs(delta.x()) > FlickThreshold && qAbs(delta.y()) > FlickThreshold)
+ d->stealMouse = true;
+ }
+
+ if (d->stealMouse) {
+ d->moveReason = QFxPathViewPrivate::Mouse;
+ qreal newPc;
+ d->pointNear(event->pos(), &newPc);
+ qreal diff = newPc - d->startPc;
+ if (diff) {
+ setOffset(d->_offset + diff);
+
+ if (diff > 50)
+ diff -= 100;
+ else if (diff < -50)
+ diff += 100;
+
+ d->lastElapsed = d->lastPosTime.restart();
+ d->lastDist = diff;
+ d->startPc = newPc;
+ }
+ }
+}
+
+void QFxPathView::mouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_D(QFxPathView);
+ if (d->lastPosTime.isNull())
+ return;
+
+ qreal elapsed = qreal(d->lastElapsed + d->lastPosTime.elapsed()) / 1000.;
+ qreal velocity = elapsed > 0. ? d->lastDist / elapsed : 0;
+ if (d->model && d->model->count() && qAbs(velocity) > 5) {
+ if (velocity > 100)
+ velocity = 100;
+ else if (velocity < -100)
+ velocity = -100;
+ qreal inc = fmod(d->_offset - d->snapPos, 100.0 / d->model->count());
+ qreal dist = qAbs(velocity/2 - fmod(velocity/2, 100.0 / d->model->count()) - inc);
+ d->moveOffset.setValue(d->_offset);
+ d->tl.accel(d->moveOffset, velocity, 10, dist);
+ d->tl.execute(d->fixupOffsetEvent);
+ } else {
+ d->fixOffset();
+ }
+
+ d->lastPosTime = QTime();
+ d->stealMouse = false;
+}
+
+bool QFxPathView::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxPathView);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapToScene(QRectF(0, 0, width(), height()));
+ QFxItem *grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if ((d->stealMouse || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if (grabber && d->stealMouse && !grabber->keepMouseGrab())
+ mouseGrabberItem()->ungrabMouse();
+
+ return d->stealMouse;
+ } else if (!d->lastPosTime.isNull()) {
+ d->lastPosTime = QTime();
+ }
+ return false;
+}
+
+bool QFxPathView::mouseFilter(QGraphicsSceneMouseEvent *e)
+{
+ if(!isVisible())
+ return false;
+
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ {
+ bool ret = sendMouseEvent(e);
+ if (e->type() == QEvent::GraphicsSceneMouseRelease)
+ return ret;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+void QFxPathViewPrivate::regenerate()
+{
+ Q_Q(QFxPathView);
+ if (!model || model->count() <= 0 || !model->delegate() || !path)
+ return;
+
+ for(int i=0; i<items.count(); i++){
+ QFxItem *p = items[i];
+ q->attachedProperties.remove(p);
+ model->release(p);
+ }
+ items.clear();
+
+ firstIndex = 0;
+ pathOffset = 0;
+
+ int numItems = (pathItems>=0 ? pathItems : model->count());
+ qreal minDiff = 1e9;
+ int minI = -1;
+ for(int i=0; i<numItems; i++){
+ QFxItem *item = model->item(i);
+ items.append(item);
+ item->setZ(i);
+ item->setParent(q);
+ qreal percent = i * (100.0 / (numItems));
+ percent /= 100.0;
+ updateItem(items.last(), percent);
+ qreal diff = qAbs(percent - snapPos);
+ if(diff < minDiff){
+ minDiff = diff;
+ minI = i;
+ }
+ }
+ q->setCurrentIndex(minI);
+
+ q->refill();
+}
+
+void QFxPathViewPrivate::updateItem(QFxItem *item, qreal percent)
+{
+ if(QObject *obj = QFxPathView::attachedProperties.value(item)) {
+ foreach(QString attr, path->attributes())
+ static_cast<QFxPathViewAttached *>(obj)->setValue(attr.toLatin1(), path->attributeAt(attr, percent));
+ }
+
+ QPointF pf = path->pointAt(percent);
+ item->setX(pf.x() - item->width()*item->scale()/2);
+ item->setY(pf.y() - item->height()*item->scale()/2);
+}
+
+void QFxPathView::refill()
+{
+ Q_D(QFxPathView);
+ if (!d->model || d->model->count() <= 0)
+ return;
+
+ QList<qreal> positions;
+ for(int i=0; i<d->items.count(); i++){
+ qreal percent = i * (100. / d->items.count());
+ percent = percent + d->_offset;
+ percent = fmod(percent,100.);
+ positions << qAbs(percent/100.0);
+ }
+
+ if(d->pathItems==-1){
+ for(int i=0; i<positions.count(); i++){
+ d->updateItem(d->items.at(i), positions[i]);
+ }
+ return;
+ }
+
+ QList<qreal> rotatedPositions;
+ for(int i=0; i<d->items.count(); i++)
+ rotatedPositions << positions[(i + d->pathOffset + d->items.count()) % d->items.count()];
+
+ int firstFind = -1;
+ int i;
+ for(i=0; i<d->items.count()-1; i++)
+ {
+ if(rotatedPositions[i] > rotatedPositions[i+1]){
+ firstFind = i;
+ break;
+ }
+ }
+ if(firstFind!=-1 ){
+ //A wraparound has occured
+ if(firstFind<(d->items.count()/2)){
+ while(firstFind-- >= 0){
+ QFxItem* p = d->items.takeFirst();
+ attachedProperties.remove(p);
+ d->model->release(p);
+ d->firstIndex++;
+ d->firstIndex%=d->model->count();
+ int index = (d->firstIndex + d->items.count())%d->model->count();
+ d->items << d->model->item(index);
+ d->items.last()->setZ(i);
+ d->items.last()->setParent(this);
+ d->pathOffset++;
+ d->pathOffset=d->pathOffset % d->items.count();
+ }
+ }else{
+ while(firstFind++ < (d->items.count()-1)){
+ QFxItem* p = d->items.takeLast();
+ attachedProperties.remove(p);
+ d->model->release(p);
+ d->firstIndex--;
+ if(d->firstIndex<0)
+ d->firstIndex = d->model->count() - 1;
+ d->items.prepend(d->model->item(d->firstIndex));
+ d->items.first()->setZ(d->firstIndex);
+ d->items.first()->setParent(this);
+ d->pathOffset--;
+ if(d->pathOffset<0)
+ d->pathOffset = d->items.count() - 1;
+ }
+ }
+ for(int i=0; i<d->items.count(); i++)
+ rotatedPositions[i] = positions[(i + d->pathOffset + d->items.count())
+ % d->items.count()];
+ }
+ for(int i=0; i<d->items.count(); i++){
+ d->updateItem(d->items.at(i), rotatedPositions[i]);
+ }
+}
+
+void QFxPathView::ticked()
+{
+ Q_D(QFxPathView);
+ d->updateCurrent();
+}
+
+// find the item closest to the snap position
+int QFxPathViewPrivate::calcCurrentIndex()
+{
+ int current = -1;
+ if (model && items.count()) {
+ _offset = fmod(_offset, 100.0);
+ if(_offset < 0)
+ _offset += 100.0;
+
+ if(pathItems == -1){
+ qreal delta = fmod(_offset - snapPos, 100.0);
+ if (delta < 0)
+ delta = 100.0 + delta;
+ int ii = model->count() - qRound(delta * model->count() / 100);
+ if(ii < 0)
+ ii = 0;
+ current = ii;
+ }else{
+ qreal bestDiff=1e9;
+ int bestI=-1;
+ for(int i=0; i<items.count(); i++){
+ qreal percent = i * (100. / items.count());
+ percent = percent + _offset;
+ percent = fmod(percent,100.);
+ qreal diff = qAbs(snapPos - (percent/100.0));
+ if(diff < bestDiff){
+ bestDiff = diff;
+ bestI = i;
+ }
+ }
+ int modelIndex = (bestI - pathOffset + items.count())%items.count();
+ modelIndex += firstIndex;
+ current = modelIndex;
+ }
+ current = qAbs(current % model->count());
+ }
+
+ return current;
+}
+
+void QFxPathViewPrivate::updateCurrent()
+{
+ Q_Q(QFxPathView);
+ if (moveReason != Mouse)
+ return;
+ int idx = calcCurrentIndex();
+ if (model && idx != currentIndex) {
+ currentIndex = idx;
+ int itemIndex = (idx - firstIndex + model->count()) % model->count();
+ if(itemIndex < items.count())
+ items.at(itemIndex)->setFocus(true);
+ emit q->currentIndexChanged();
+ }
+}
+
+void QFxPathViewPrivate::fixOffset()
+{
+ Q_Q(QFxPathView);
+ if (model && items.count()) {
+ int curr = calcCurrentIndex();
+ if (curr != currentIndex)
+ q->setCurrentIndex(curr);
+ else
+ snapToCurrent();
+ }
+}
+
+void QFxPathViewPrivate::snapToCurrent()
+{
+ if (!model || model->count() <= 0)
+ return;
+
+ int itemIndex = (currentIndex - firstIndex + model->count())%model->count();
+
+ //Rounds is the number of times round to make the current item visible
+ int rounds = itemIndex / items.count();
+ int otherWayRounds = (model->count() - (itemIndex))/items.count() + 1;
+ if(otherWayRounds < rounds)
+ rounds = -otherWayRounds;
+
+ itemIndex += pathOffset;
+ itemIndex %= items.count();
+ qreal targetOffset = fmod(100 + (snapPos*100) - 100.0 * itemIndex / items.count(), 100);
+
+ if (targetOffset < 0)
+ targetOffset = 100.0 + targetOffset;
+ if (targetOffset == _offset && rounds==0)
+ return;
+
+ moveReason = Other;
+ tl.clear();
+ moveOffset.setValue(_offset);
+
+ if(rounds!=0){
+ //Compensate if the targetOffset would bring the target it from off the screen
+ qreal distance = targetOffset - _offset;
+ if(distance <= -50)
+ rounds--;
+ if(distance > 50)
+ rounds++;
+ tl.move(moveOffset, targetOffset + 100.0*(-rounds), GfxEasing(GfxEasing::InOutQuad),
+ int(100*items.count()*qMax((qreal)(2.0/items.count()),(qreal)qAbs(rounds))));
+ tl.execute(fixupOffsetEvent);
+ return;
+ }
+
+ if (targetOffset - _offset > 50.0) {
+ qreal distance = 100 - targetOffset + _offset;
+ tl.move(moveOffset, 0.0, GfxEasing(GfxEasing::OutQuad), int(200 * _offset / distance));
+ tl.set(moveOffset, 100.0);
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InQuad), int(200 * (100-targetOffset) / distance));
+ } else if (targetOffset - _offset <= -50.0) {
+ qreal distance = 100 - _offset + targetOffset;
+ tl.move(moveOffset, 100.0, GfxEasing(GfxEasing::OutQuad), int(200 * (100-_offset) / distance));
+ tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InQuad), int(200 * targetOffset / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, GfxEasing(GfxEasing::InOutQuad), 200);
+ }
+}
+
+QHash<QObject*, QObject*> QFxPathView::attachedProperties;
+QObject *QFxPathView::qmlAttachedProperties(QObject *obj)
+{
+ if(!attachedProperties.contains(obj)) {
+ QFxPathViewAttached *rv = new QFxPathViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return attachedProperties.value(obj);
+}
+
+QT_END_NAMESPACE
+
+#include "qfxpathview.moc"
diff --git a/src/declarative/fx/qfxpathview.h b/src/declarative/fx/qfxpathview.h
new file mode 100644
index 0000000..6d4280d
--- /dev/null
+++ b/src/declarative/fx/qfxpathview.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPATHVIEW_H
+#define QFXPATHVIEW_H
+
+#include <qfxitem.h>
+#include <qfxpath.h>
+#include <gfxvalueproxy.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QListModelInterface;
+class QFxPathViewPrivate;
+class Q_DECLARATIVE_EXPORT QFxPathView : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel)
+ Q_PROPERTY(QFxPath *path READ path WRITE setPath)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
+ Q_PROPERTY(qreal offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(qreal snapPosition READ snapPosition WRITE setSnapPosition)
+ Q_PROPERTY(qreal dragMargin READ dragMargin WRITE setDragMargin)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate)
+ Q_PROPERTY(int pathItemCount READ pathItemCount WRITE setPathItemCount)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ QFxPathView(QFxItem *parent=0);
+ virtual ~QFxPathView();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QFxPath *path() const;
+ void setPath(QFxPath *);
+
+ int currentIndex() const;
+ void setCurrentIndex(int idx);
+
+ qreal offset() const;
+ void setOffset(qreal offset);
+
+ qreal snapPosition() const;
+ void setSnapPosition(qreal pos);
+
+ qreal dragMargin() const;
+ void setDragMargin(qreal margin);
+
+ int count() const;
+
+ QmlComponent *delegate() const;
+ void setDelegate(QmlComponent *);
+
+ int pathItemCount() const;
+ void setPathItemCount(int);
+
+ static QObject *qmlAttachedProperties(QObject *);
+
+Q_SIGNALS:
+ void currentIndexChanged();
+ void offsetChanged();
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
+ bool sendMouseEvent(QGraphicsSceneMouseEvent *event);
+ bool mouseFilter(QGraphicsSceneMouseEvent *e);
+
+private Q_SLOTS:
+ void refill();
+ void ticked();
+
+protected:
+ QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent);
+
+private:
+ static QHash<QObject*, QObject*> attachedProperties;
+ Q_DISABLE_COPY(QFxPathView)
+ Q_DECLARE_PRIVATE(QFxPathView)
+};
+QML_DECLARE_TYPE(QFxPathView);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXPATHVIEW_H
diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h
new file mode 100644
index 0000000..31933c0
--- /dev/null
+++ b/src/declarative/fx/qfxpathview_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPATHVIEW_P_H
+#define QFXPATHVIEW_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qdatetime.h"
+#include "qfxpathview.h"
+#include "qfxitem_p.h"
+#include "qfxvisualitemmodel.h"
+#include "qml.h"
+#include "private/qmlanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+typedef struct PathViewItem{
+ int index;
+ QFxItem* item;
+}PathViewItem;
+
+class QFxPathViewPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxPathView)
+
+public:
+ QFxPathViewPrivate()
+ : path(0), currentIndex(0), startPc(0), lastDist(0)
+ , lastElapsed(0), stealMouse(false), ownModel(false), activeItem(0)
+ , snapPos(0), dragMargin(0), moveOffset(this, &QFxPathViewPrivate::setOffset)
+ , firstIndex(0), pathItems(-1), pathOffset(0), model(0)
+ , moveReason(Other)
+ {
+ fixupOffsetEvent = GfxEvent::gfxEvent<QFxPathViewPrivate, &QFxPathViewPrivate::fixOffset>(&moveOffset, this);
+ }
+
+ void init()
+ {
+ Q_Q(QFxPathView);
+ _offset = 0;
+ q->setAcceptedMouseButtons(Qt::NoButton);
+ q->setOptions(QSimpleCanvasItem::MouseFilter | QSimpleCanvasItem::MouseEvents | QSimpleCanvasItem::IsFocusRealm);
+ q->connect(&tl, SIGNAL(updated()), q, SLOT(ticked()));
+ }
+
+ int calcCurrentIndex();
+ void updateCurrent();
+ void fixOffset();
+ void setOffset(qreal offset);
+ void regenerate();
+ void updateItem(QFxItem *, qreal);
+ void snapToCurrent();
+ QPointF pointNear(const QPointF &point, qreal *nearPercent=0) const;
+
+ QFxPath *path;
+ int currentIndex;
+ qreal startPc;
+ QPointF startPoint;
+ qreal lastDist;
+ int lastElapsed;
+ qreal _offset;
+ int stealMouse : 1;
+ int ownModel : 1;
+ QTime lastPosTime;
+ QPointF lastPos;
+ QFxItem *activeItem;
+ qreal snapPos;
+ qreal dragMargin;
+ QmlTimeLine tl;
+ GfxValueProxy<QFxPathViewPrivate> moveOffset;
+ GfxEvent fixupOffsetEvent;
+ int firstIndex;
+ int pathItems;
+ int pathOffset;
+ QList<QFxItem *> items;
+ QFxVisualItemModel *model;
+ QVariant modelVariant;
+ enum MovementReason { Other, Key, Mouse };
+ MovementReason moveReason;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp
new file mode 100644
index 0000000..883dbdf
--- /dev/null
+++ b/src/declarative/fx/qfxpixmap.cpp
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxpixmap.h"
+#include <QHash>
+#include <QNetworkReply>
+#include <qfxperf.h>
+#include <QtDeclarative/qmlengine.h>
+#include <QFile>
+
+
+QT_BEGIN_NAMESPACE
+class QFxPixmapCacheItem;
+typedef QHash<QString, QFxPixmapCacheItem *> QFxPixmapCache;
+static QFxPixmapCache qfxPixmapCache;
+
+class QFxPixmapCacheItem
+{
+public:
+ QFxPixmapCacheItem() : reply(0), refCount(1) {}
+ QString key;
+ QNetworkReply *reply;
+#if defined(QFX_RENDER_OPENGL)
+ QImage image;
+#else
+ QImage image;
+ QImage opaqueImage;
+#endif
+
+ int refCount;
+ void addRef() { ++refCount; }
+ void release() { Q_ASSERT(refCount > 0); --refCount; if(refCount == 0) { qfxPixmapCache.remove(key); delete this; } }
+};
+
+static QFxPixmapCacheItem qfxPixmapCacheDummyItem;
+
+class QFxPixmapPrivate
+{
+public:
+ QFxPixmapPrivate()
+ : opaque(false), pixmap(&qfxPixmapCacheDummyItem) { pixmap->addRef(); }
+
+ bool opaque;
+ QFxPixmapCacheItem *pixmap;
+};
+
+/*!
+ \internal
+ \class QFxPixmap
+ \ingroup utility
+ \brief Enacapsultes a pixmap for QFx items.
+
+ This class is NOT reentrant.
+ The pixmap cache will grow indefinately.
+ */
+QFxPixmap::QFxPixmap()
+: d(new QFxPixmapPrivate)
+{
+}
+
+QFxPixmap::QFxPixmap(const QUrl &url)
+: d(new QFxPixmapPrivate)
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::PixmapLoad> perf;
+#endif
+ QString key = url.toString();
+ QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key);
+ if(iter == qfxPixmapCache.end()) {
+ qWarning() << "QFxPixmap: URL not loaded" << url;
+ } else {
+ QNetworkReply *reply = (*iter)->reply;
+ if (reply) {
+ if (reply->error()) {
+ qWarning() << "Error loading" << url << reply->errorString();
+ } else {
+ (*iter)->image.load(reply, 0);
+ }
+ reply->deleteLater();
+ (*iter)->reply = 0;
+ }
+ (*iter)->addRef();
+ }
+
+ d->pixmap = *iter;
+}
+
+QFxPixmap::QFxPixmap(const QFxPixmap &o)
+: d(new QFxPixmapPrivate)
+{
+ d->opaque = o.d->opaque;
+ o.d->pixmap->addRef();
+ d->pixmap->release();
+ d->pixmap = o.d->pixmap;
+}
+
+QFxPixmap::~QFxPixmap()
+{
+ d->pixmap->release();
+ delete d;
+}
+
+QFxPixmap &QFxPixmap::operator=(const QFxPixmap &o)
+{
+ d->opaque = o.d->opaque;
+ o.d->pixmap->addRef();
+ d->pixmap->release();
+ d->pixmap = o.d->pixmap;
+ return *this;
+}
+
+bool QFxPixmap::isNull() const
+{
+ return d->pixmap->image.isNull();
+}
+
+bool QFxPixmap::opaque() const
+{
+ return d->opaque;
+}
+
+void QFxPixmap::setOpaque(bool o)
+{
+ d->opaque = o;
+}
+
+int QFxPixmap::width() const
+{
+ return d->pixmap->image.width();
+}
+
+int QFxPixmap::height() const
+{
+ return d->pixmap->image.height();
+}
+
+QPixmap QFxPixmap::pixmap() const
+{
+ return QPixmap::fromImage(d->pixmap->image);
+}
+
+void QFxPixmap::setPixmap(const QPixmap &pix)
+{
+ QFxPixmapCache::Iterator iter = qfxPixmapCache.find(QString::number(pix.cacheKey()));
+ if(iter == qfxPixmapCache.end()) {
+ QFxPixmapCacheItem *item = new QFxPixmapCacheItem;
+ item->key = QString::number(pix.cacheKey());
+ if(d->pixmap)
+ d->pixmap->release();
+ d->pixmap = item;
+ d->pixmap->image = pix.toImage();
+ qfxPixmapCache.insert(QString::number(pix.cacheKey()), item);
+ } else {
+ (*iter)->addRef();
+ d->pixmap = *iter;
+ }
+
+#if 0
+ int size = 0;
+ for(QFxPixmapCache::Iterator iter = qfxPixmapCache.begin(); iter != qfxPixmapCache.end(); ++iter) {
+ size += (*iter)->image.width() * (*iter)->image.height();
+ }
+ qWarning() << qfxPixmapCache.count() << size;
+#endif
+}
+
+QFxPixmap::operator const QSimpleCanvasConfig::Image &() const
+{
+#if defined(QFX_RENDER_OPENGL)
+ return d->pixmap->image;
+#else
+ if(d->opaque) {
+ if(!d->pixmap->image.isNull() && d->pixmap->opaqueImage.isNull()) {
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::PixmapLoad> perf;
+#endif
+ d->pixmap->opaqueImage = d->pixmap->image.convertToFormat(QPixmap::defaultDepth() == 16 ?
+ QImage::Format_RGB16 :
+ QImage::Format_RGB32);
+ }
+ return d->pixmap->opaqueImage;
+ } else {
+ if(!d->pixmap->image.isNull() && d->pixmap->image.format() != QImage::Format_ARGB32_Premultiplied) {
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::PixmapLoad> perf;
+#endif
+ d->pixmap->image = d->pixmap->image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+ return d->pixmap->image;
+ }
+#endif
+}
+
+/*!
+ Starts a network request to load \a url. When the URL is loaded,
+ the given slot is invoked. Note that if the image is already cached,
+ the slot may be invoked immediately.
+*/
+void QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
+{
+ QString key = url.toString();
+ QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key);
+ if(iter == qfxPixmapCache.end()) {
+ QFxPixmapCacheItem *item = new QFxPixmapCacheItem;
+ item->addRef(); // XXX - will never get deleted. Need to revisit caching
+ item->key = key;
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ if (url.scheme()==QLatin1String("file")) {
+ item->image.load(url.toLocalFile(), 0);
+ } else
+#endif
+ {
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ item->reply = engine->networkAccessManager()->get(req);
+ }
+ iter = qfxPixmapCache.insert(item->key, item);
+ } else {
+ (*iter)->addRef();
+ }
+ if ((*iter)->reply) {
+ // still loading
+ QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot);
+ } else {
+ // already loaded
+ QObject dummy;
+ QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot);
+ }
+}
+
+/*!
+ Stops the given slot being invoked if the given url finishes loading.
+ May also cancel loading (eg. if no other pending request).
+*/
+void QFxPixmap::cancelGet(const QUrl& url, QObject* obj, const char* slot)
+{
+ QString key = url.toString();
+ QFxPixmapCache::Iterator iter = qfxPixmapCache.find(key);
+ if(iter == qfxPixmapCache.end())
+ return;
+ if ((*iter)->reply)
+ QObject::disconnect((*iter)->reply, SIGNAL(finished()), obj, slot);
+ // XXX - loading not cancelled. Need to revisit caching
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h
new file mode 100644
index 0000000..9a3ba4e
--- /dev/null
+++ b/src/declarative/fx/qfxpixmap.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXPIXMAP_H
+#define QFXPIXMAP_H
+
+#include <QString>
+#include <qsimplecanvas.h>
+#include <qfxglobal.h>
+#include <QPixmap>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QmlEngine;
+class QFxPixmapPrivate;
+class Q_DECLARATIVE_EXPORT QFxPixmap
+{
+public:
+ QFxPixmap();
+ QFxPixmap(const QUrl& url); // url must have been passed to QFxPixmap::get, and finished.
+ QFxPixmap(const QFxPixmap &);
+ virtual ~QFxPixmap();
+
+ QFxPixmap &operator=(const QFxPixmap &);
+
+ static void get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
+ static void cancelGet(const QUrl& url, QObject* obj, const char* slot);
+
+ bool isNull() const;
+
+ bool opaque() const;
+ void setOpaque(bool);
+
+ int width() const;
+ int height() const;
+
+ QPixmap pixmap() const;
+ void setPixmap(const QPixmap &pix);
+
+ operator const QSimpleCanvasConfig::Image &() const;
+
+private:
+ QFxPixmapPrivate *d;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXPIXMAP_H
diff --git a/src/declarative/fx/qfxrect.cpp b/src/declarative/fx/qfxrect.cpp
new file mode 100644
index 0000000..718dc76
--- /dev/null
+++ b/src/declarative/fx/qfxrect.cpp
@@ -0,0 +1,851 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxrect.h"
+#include "qfxrect_p.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxPen,Pen);
+
+/*!
+ \internal
+ \class QFxPen
+ \ingroup utility
+ \brief The QFxPen class provides a pen used for drawing rect borders on a QFxView.
+
+ Example:
+ \code
+ <Rect pen.width="2" pen.color="red".../>
+ \endcode
+*/
+
+/*! \property QFxPen::width
+ \brief the width of the pen.
+
+ The default width is 1. If the width is less than 1 the pen is considered invalid
+ and won't be used.
+*/
+
+/*!
+ \property QFxPen::color
+ \brief the color of the pen.
+
+ color is most commonly specified in hexidecimal notation (#RRGGBB)
+ or as an
+ \htmlonly
+ <a href="http://www.w3.org/TR/SVG/types.html#ColorKeywords"> SVG color keyword name</a>
+ \endhtmlonly
+ (as defined by the World Wide Web Consortium). For example:
+ \code
+ <!-- rect with green border using hexidecimal notation -->
+ <Rect pen.color="#00FF00" .../>
+
+ <!-- rect with steelblue border using SVG color name-->
+ <Rect pen.color="steelblue" .../>
+ \endcode
+
+ For the full set of ways to specify color, see Qt's QColor::setNamedColor documentation.
+*/
+
+void QFxPen::setColor(const QColor &c)
+{
+ _color = c;
+ emit updated();
+ _valid = _color.alpha() ? true : false;
+}
+
+
+
+QML_DEFINE_TYPE(QFxRect,Rect);
+
+/*!
+ \qmlclass Rect QFxRect
+ \brief The Rect element allows you to add rectangles to a scene.
+ \inherits Item
+
+ A Rect is painted having a solid fill (color) and an optional border (pen). You can also create rounded rectangles using the radius property.
+
+ \code
+ <Rect width="100" height="100" color="red" pen.color="black" pen.width="5" radius="10"/>
+ \endcode
+
+ \image declarative-rect.png
+*/
+
+/*!
+ \internal
+ \class QFxRect
+ \brief The QFxRect class provides a rect item that you can add to a QFxView.
+
+ A Rect is painted having a solid fill (color) and an optional border (pen). You can also create rounded rectangles using the radius property.
+
+ \code
+ <Rect width="100" height="100" color="red" pen.color="black" pen.width="5" radius="10"/>
+ \endcode
+
+ \image declarative-rect.png
+
+ A QFxRect object can be instantiated in Qml using the tag \l Rect.
+
+ \ingroup coreitems
+*/
+QFxRect::QFxRect(QFxItem *parent)
+ : QFxItem(*(new QFxRectPrivate), parent)
+{
+ Q_D(QFxRect);
+ d->init();
+ setOptions(HasContents, true);
+}
+
+QFxRect::QFxRect(QFxRectPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxRect);
+ d->init();
+ setOptions(HasContents, true);
+}
+
+void QFxRect::doUpdate()
+{
+#if defined(QFX_RENDER_QPAINTER)
+ Q_D(QFxRect);
+ d->_rectImage = QSimpleCanvasConfig::Image();
+#endif
+#if defined(QFX_RENDER_OPENGL)
+ Q_D(QFxRect);
+ d->_rectTexture.clear();
+#endif
+ update();
+}
+
+/*!
+ \qmlproperty int Rect::pen.width
+ \qmlproperty color Rect::pen.color
+
+ The pen used to draw the border of the rect.
+*/
+/*!
+ \property QFxRect::pen
+ \brief the pen used to draw the border of the rect.
+*/
+QFxPen *QFxRect::pen()
+{
+ Q_D(QFxRect);
+ return d->pen();
+}
+
+/*!
+ \qmlproperty real Rect::radius
+ This property holds the corner radius used to draw a rounded rect.
+
+ If radius is non-zero, the rect will be painted as a rounded rectangle, otherwise it will be
+ painted as a normal rectangle. The same radius is used by all 4 corners; there is currently
+ no way to specify different radii for different corners.
+*/
+
+/*!
+ \property QFxRect::radius
+ \brief the corner radius used to draw a rounded rect.
+*/
+qreal QFxRect::radius() const
+{
+ Q_D(const QFxRect);
+ return d->_radius;
+}
+
+void QFxRect::setRadius(qreal radius)
+{
+ Q_D(QFxRect);
+ if (d->_radius == radius)
+ return;
+
+ d->_radius = radius;
+#if defined(QFX_RENDER_QPAINTER)
+ d->_rectImage = QSimpleCanvasConfig::Image();
+#elif defined(QFX_RENDER_OPENGL)
+ d->_rectTexture.clear();
+#endif
+ update();
+}
+
+void QFxRect::dump(int depth)
+{
+ Q_D(QFxRect);
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << "QFxRect:" << d->_color;
+ QFxItem::dump(depth);
+}
+
+/*!
+ \qmlproperty color Rect::color
+ This property holds the color used to fill the rect.
+
+ \code
+ <!-- green rect using hexidecimal notation -->
+ <Rect color="#00FF00" .../>
+
+ <!-- steelblue rect using SVG color name-->
+ <Rect color="steelblue" .../>
+ \endcode
+*/
+
+/*!
+ \property QFxRect::color
+ \brief the color used to fill the rect.
+*/
+QColor QFxRect::color() const
+{
+ Q_D(const QFxRect);
+ return d->_color;
+}
+
+void QFxRect::setColor(const QColor &c)
+{
+ Q_D(QFxRect);
+ if(d->_color == c)
+ return;
+
+ d->_color = c;
+#if defined(QFX_RENDER_QPAINTER)
+ d->_rectImage = QSimpleCanvasConfig::Image();
+#endif
+#if defined(QFX_RENDER_OPENGL)
+ d->_rectTexture.clear();
+#endif
+ update();
+}
+
+
+
+/*!
+ \qmlproperty color Rect::tintColor
+ This property holds The color to tint the rectangle.
+
+ This color will be drawn over the rect's color when the rect is painted. The tint color should usually be mostly transparent, or you will not be able to see the underlying color. The below example provides a slight red tint by having the tint color be pure red which is only 1/16th opaque.
+
+ \code
+ <Rect x="0" width="80" height="80" color="lightsteelblue"/>
+ <Rect x="100" width="80" height="80" color="lightsteelblue" tintColor="#10FF0000"/>
+ \endcode
+ \image declarative-rect_tint.png
+
+ This attribute is not intended to be used with a single color over the lifetime of an user interface. It is most useful when a subtle change is intended to be conveyed due to some event; you can then use the tint color to more effectively tune the visible color.
+*/
+
+/*!
+ \property QFxRect::tintColor
+ \brief The color to tint the rectangle.
+*/
+QColor QFxRect::tintColor() const
+{
+ Q_D(const QFxRect);
+ return d->_tintColor;
+}
+
+void QFxRect::setTintColor(const QColor &c)
+{
+ Q_D(QFxRect);
+ if(d->_tintColor == c)
+ return;
+
+ d->_tintColor = c;
+ update();
+}
+
+QColor QFxRectPrivate::getColor()
+{
+ if(_tintColor.isValid()) {
+ int a = _tintColor.alpha();
+ if(a == 0xFF)
+ return _tintColor;
+ else if(a == 0x00)
+ return _color;
+ else {
+ uint src = _tintColor.rgba();
+ uint dest = _color.rgba();
+
+ uint res = (((a * (src & 0xFF00FF)) +
+ ((0xFF - a) * (dest & 0xFF00FF))) >> 8) & 0xFF00FF;
+ res |= (((a * ((src >> 8) & 0xFF00FF)) +
+ ((0xFF - a) * ((dest >> 8) & 0xFF00FF)))) & 0xFF00FF00;
+ if((src & 0xFF000000) == 0xFF000000)
+ res |= 0xFF000000;
+
+ return QColor::fromRgba(res);
+ }
+ } else {
+ return _color;
+ }
+}
+
+/*!
+ \qmlproperty color Rect::gradientColor
+ This property holds the color to use at the base of the rectangle and blend upwards.
+
+ This property allows for the easy construction of simple horizontal gradients. Other gradients may by formed by adding rotation to the rect. The gradient will blend linearly from the rect's main color to the color specified for gradient color.
+
+ \code
+ <Rect y="0" width="80" height="80" color="lightsteelblue"/>
+ <Rect y="100" width="80" height="80" color="lightsteelblue" gradientColor="blue"/>
+ <Rect rotation="90" x="80" y="200" width="80" height="80" color="lightsteelblue"
+ gradientColor="blue"/>
+ <!-- The x offset is needed because the rotation is from the top left corner -->
+ \endcode
+ \image declarative-rect_gradient.png
+*/
+
+/*!
+ \property QFxRect::gradientColor
+ \brief The color to use at the base of the rectangle and blend upwards.
+*/
+
+QColor QFxRect::gradientColor() const
+{
+ Q_D(const QFxRect);
+ return d->_gradcolor;
+}
+
+void QFxRect::setGradientColor(const QColor &c)
+{
+ Q_D(QFxRect);
+ if(d->_gradcolor == c)
+ return;
+
+ d->_gradcolor = c;
+ update();
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxRect::generateRoundedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectImage.isNull()) {
+ d->_rectImage = QImage(d->_radius*2 + 1, d->_radius*2 + 1, QImage::Format_ARGB32_Premultiplied);
+ d->_rectImage.fill(0);
+ QPainter p(&(d->_rectImage));
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setPen(pn);
+ p.setBrush(d->_color);
+ p.drawRoundedRect(0, 0, d->_rectImage.width(), d->_rectImage.height(), d->_radius, d->_radius);
+ }
+}
+
+void QFxRect::generateBorderedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectImage.isNull()) {
+ d->_rectImage = QImage(d->pen()->width()*2 + 1, d->pen()->width()*2 + 1, QImage::Format_ARGB32_Premultiplied);
+ d->_rectImage.fill(0);
+ QPainter p(&(d->_rectImage));
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setPen(pn);
+ p.setBrush(d->_color);
+ p.drawRect(0, 0, d->_rectImage.width(), d->_rectImage.height());
+ }
+}
+#elif defined(QFX_RENDER_OPENGL)
+void QFxRect::generateRoundedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectTexture.isNull()) {
+ QImage roundRect(int(d->_radius*2 + 1), int(d->_radius*2 + 1), QImage::Format_ARGB32);
+ roundRect.fill(0);
+ QPainter p(&roundRect);
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setPen(pn);
+ p.setBrush(d->_color);
+ p.drawRoundedRect(0, 0, roundRect.width(), roundRect.height(), d->_radius, d->_radius);
+ d->_rectTexture.setImage(roundRect);
+ }
+}
+
+void QFxRect::generateBorderedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectTexture.isNull()) {
+ QImage borderedRect(d->pen()->width()*2 + 1, d->pen()->width()*2 + 1, QImage::Format_ARGB32_Premultiplied);
+ borderedRect.fill(0);
+ QPainter p(&(borderedRect));
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setPen(pn);
+ p.setBrush(d->_color);
+ p.drawRect(0, 0, borderedRect.width(), borderedRect.height());
+ d->_rectTexture.setImage(borderedRect);
+ }
+}
+#endif
+
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxRect::paintContents(QPainter &p)
+{
+ Q_D(QFxRect);
+ if (d->_radius > 0 || (d->_pen && d->_pen->isValid())
+ || d->_gradcolor.isValid())
+ drawRect(p);
+ /*
+ QLinearGradient grad(0, 0, 0, height());
+ grad.setColorAt(0, d->_color);
+ grad.setColorAt(1, d->_gradcolor);
+ p.setBrush(grad);
+ p.drawRect(0, 0, width(), height());
+ p.setBrush(QBrush());
+ */
+ else
+ p.fillRect(QRect(0, 0, width(), height()), d->getColor());
+}
+
+void QFxRect::drawRect(QPainter &p)
+{
+ Q_D(QFxRect);
+ if(d->_gradcolor.isValid() /*|| p.usingQt() */) {
+ // XXX This path is still slower than the image path
+ // Image path won't work for gradients though
+ p.save();
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setRenderHint(QPainter::Antialiasing);
+ p.setPen(pn);
+ if(d->_gradcolor.isValid()){
+ QLinearGradient grad(0, 0, 0, height());
+ grad.setColorAt(0, d->_color);
+ grad.setColorAt(1, d->_gradcolor);
+ p.setBrush(grad);
+ }else{
+ p.setBrush(d->_color);
+ }
+ if(d->_radius)
+ p.drawRoundedRect(0, 0, width(), height(), d->_radius, d->_radius);
+ else
+ p.drawRect(0, 0, width(), height());
+ p.restore();
+ } else {
+ int offset = 0;
+ if (d->_radius > 0) {
+ generateRoundedRect();
+ //### implicit conversion to int
+ offset = d->_radius;
+ } else {
+ generateBorderedRect();
+ offset = d->pen()->width();
+ }
+
+ //basically same code as QFxImage uses to paint sci images
+ int xSide = offset * 2;
+ int ySide = offset * 2;
+
+ // Upper left
+ p.drawImage(QRect(0, 0, offset, offset), d->_rectImage, QRect(0, 0, offset, offset));
+
+ // Upper middle
+ if(d->_rectImage.width() - xSide)
+ p.drawImage(QRect(offset, 0, width() - xSide, offset), d->_rectImage,
+ QRect(offset, 0, d->_rectImage.width() - xSide, offset));
+ // Upper right
+ if(d->_rectImage.width() - offset) {
+ p.drawImage(QPoint(width()-offset, 0), d->_rectImage,
+ QRect(d->_rectImage.width()-offset, 0, offset, offset));
+ }
+ // Middle left
+ if(d->_rectImage.height() - ySide)
+ p.drawImage(QRect(0, offset, offset, height() - ySide), d->_rectImage,
+ QRect(0, offset, offset, d->_rectImage.height() - ySide));
+
+ // Middle
+ if(d->_rectImage.width() - xSide && d->_rectImage.height() - ySide)
+ p.drawImage(QRect(offset, offset, width() - xSide, height() - ySide), d->_rectImage,
+ QRect(offset, offset, d->_rectImage.width() - xSide, d->_rectImage.height() - ySide));
+ // Midlle right
+ if(d->_rectImage.height() - ySide)
+ p.drawImage(QRect(width()-offset, offset, offset, height() - ySide), d->_rectImage,
+ QRect(d->_rectImage.width()-offset, offset, offset, d->_rectImage.height() - ySide));
+ // Lower left
+ p.drawImage(QPoint(0, height() - offset), d->_rectImage, QRect(0, d->_rectImage.height() - offset, offset, offset));
+
+ // Lower Middle
+ if(d->_rectImage.width() - xSide)
+ p.drawImage(QRect(offset, height() - offset, width() - xSide, offset), d->_rectImage,
+ QRect(offset, d->_rectImage.height() - offset, d->_rectImage.width() - xSide, offset));
+ // Lower Right
+ if(d->_rectImage.width() - offset)
+ p.drawImage(QPoint(width()-offset, height() - offset), d->_rectImage,
+ QRect(d->_rectImage.width()-offset, d->_rectImage.height() - offset, offset, offset));
+ }
+}
+#endif
+
+#if defined(QFX_RENDER_OPENGL2)
+#include "glbasicshaders.h"
+
+void QFxRect::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxRect);
+ if(d->_radius == 0 && (!d->_pen || !d->_pen->isValid())) {
+ if(d->_gradcolor.isValid()) {
+ float widthV = width();
+ float heightV = height();
+
+ GLfloat vertices[] = { 0, heightV,
+ widthV, heightV,
+ 0, 0,
+ widthV, 0 };
+
+ float r = d->_color.redF();
+ float g = d->_color.greenF();
+ float b = d->_color.blueF();
+ float a = d->_color.alphaF() * p.activeOpacity;
+
+ float r2 = d->_gradcolor.redF();
+ float g2 = d->_gradcolor.greenF();
+ float b2 = d->_gradcolor.blueF();
+ float a2 = d->_gradcolor.alphaF() * p.activeOpacity;
+
+ GLfloat colors[] = { r2, g2, b2, a2,
+ r2, g2, b2, a2,
+ r, g, b, a,
+ r, g, b, a };
+
+ ColorShader *shader = basicShaders()->color();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+
+ shader->setAttributeArray(ColorShader::Vertices, vertices, 2);
+ shader->setAttributeArray(ColorShader::Colors, colors, 4);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(ColorShader::Vertices);
+ shader->disableAttributeArray(ColorShader::Colors);
+ } else {
+ QGLShaderProgram *shader = p.useColorShader(d->getColor());
+
+ float widthV = width();
+ float heightV = height();
+
+ GLfloat vertices[] = { 0, heightV,
+ widthV, heightV,
+ 0, 0,
+ widthV, 0 };
+
+ shader->setAttributeArray(ConstantColorShader::Vertices, vertices, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(ConstantColorShader::Vertices);
+ }
+ } else {
+ qreal offset = 0;
+ if (d->_radius > 0) {
+ generateRoundedRect();
+ offset = d->_radius;
+ } else {
+ generateBorderedRect();
+ offset = d->pen()->width();
+ }
+
+ QGLShaderProgram *shader = p.useTextureShader();
+
+ float imgWidth = d->_rectTexture.width();
+ float imgHeight = d->_rectTexture.height();
+ if(!imgWidth || !imgHeight)
+ return;
+
+ float widthV = width();
+ float heightV = height();
+
+ float texleft = 0;
+ float texright = 1;
+ float textop = 1;
+ float texbottom = 0;
+ float imgleft = 0;
+ float imgright = widthV;
+ float imgtop = 0;
+ float imgbottom = heightV;
+
+ texleft = float(offset) / imgWidth;
+ imgleft = offset;
+ texright = 1. - float(offset) / imgWidth;
+ imgright = widthV - offset;
+ textop = 1. - float(offset) / imgHeight;
+ imgtop = offset;
+ texbottom = float(offset) / imgHeight;
+ imgbottom = heightV - offset;
+
+ //Bug 231768: Inappropriate interpolation was occuring on 3x3 textures
+ if(offset==1)
+ texleft=texright=textop=texbottom=0.5;
+
+ float vert1[] = { 0, 0,
+ 0, imgtop,
+ imgleft, 0,
+ imgleft, imgtop,
+ imgright, 0,
+ imgright, imgtop,
+ widthV, 0,
+ widthV, imgtop };
+ float tex1[] = { 0, 0,
+ 0, textop,
+ texleft, 0,
+ texleft, textop,
+ texright, 0,
+ texright, textop,
+ 1, 0,
+ 1, textop };
+ float vert2[] = { 0, imgtop,
+ 0, imgbottom,
+ imgleft, imgtop,
+ imgleft, imgbottom,
+ imgright, imgtop,
+ imgright, imgbottom,
+ widthV, imgtop,
+ widthV, imgbottom };
+ float tex2[] = { 0, textop,
+ 0, texbottom,
+ texleft, textop,
+ texleft, texbottom,
+ texright, textop,
+ texright, texbottom,
+ 1, textop,
+ 1, texbottom };
+ float vert3[] = { 0, imgbottom,
+ 0, heightV,
+ imgleft, imgbottom,
+ imgleft, heightV,
+ imgright, imgbottom,
+ imgright, heightV,
+ widthV, imgbottom,
+ widthV, heightV };
+ float tex3[] = { 0, texbottom,
+ 0, 0,
+ texleft, texbottom,
+ texleft, 0,
+ texright, texbottom,
+ texright, 0,
+ 1, texbottom,
+ 1, 0 };
+
+ glBindTexture(GL_TEXTURE_2D, d->_rectTexture.texture());
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert1, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex1, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert2, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex2, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+ shader->setAttributeArray(SingleTextureShader::Vertices, vert3, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, tex3, 2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+ }
+}
+#elif defined(QFX_RENDER_OPENGL1)
+void QFxRect::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxRect);
+
+ float widthV = width();
+ float heightV = height();
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(p.activeTransform.data());
+
+ if(d->_radius == 0 && (!d->_pen || !d->_pen->isValid())) {
+ GLfloat vertices[] = { 0, heightV,
+ widthV, heightV,
+ 0, 0,
+ widthV, 0 };
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(2,GL_FLOAT,0,vertices);
+
+ QColor c;
+ if(d->_gradcolor.isValid())
+ c = d->_color;
+ else
+ c = d->getColor();
+ float r = c.redF();
+ float g = c.greenF();
+ float b = c.blueF();
+ float a = c.alphaF() * p.activeOpacity;
+
+ float r2 = r; float g2 = g; float b2 = b; float a2 = a;
+
+ if(d->_gradcolor.isValid()) {
+ r2 = d->_gradcolor.redF();
+ g2 = d->_gradcolor.greenF();
+ b2 = d->_gradcolor.blueF();
+ a2 = d->_gradcolor.alphaF() * p.activeOpacity;
+ }
+
+ GLfloat colors[] = { r2, g2, b2, a2,
+ r2, g2, b2, a2,
+ r, g, b, a,
+ r, g, b, a };
+
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(4,GL_FLOAT,0,colors);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ } else {
+ qreal offset = 0;
+ if (d->_radius > 0) {
+ generateRoundedRect();
+ offset = d->_radius;
+ } else {
+ generateBorderedRect();
+ offset = d->pen()->width();
+ }
+
+ if(p.activeOpacity == 1.) {
+ GLint i = GL_REPLACE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ } else {
+ GLint i = GL_MODULATE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ glColor4f(1, 1, 1, p.activeOpacity);
+ }
+
+ float imgWidth = d->_rectTexture.width();
+ float imgHeight = d->_rectTexture.height();
+ if(!imgWidth || !imgHeight)
+ return;
+
+ float widthV = width();
+ float heightV = height();
+
+ float texleft = 0;
+ float texright = 1;
+ float textop = 1;
+ float texbottom = 0;
+ float imgleft = 0;
+ float imgright = widthV;
+ float imgtop = 0;
+ float imgbottom = heightV;
+
+ texleft = float(offset) / imgWidth;
+ imgleft = offset;
+ texright = 1. - float(offset) / imgWidth;
+ imgright = widthV - offset;
+ textop = 1. - float(offset) / imgHeight;
+ imgtop = offset;
+ texbottom = float(offset) / imgHeight;
+ imgbottom = heightV - offset;
+
+ float vert1[] = { 0, 0,
+ 0, imgtop,
+ imgleft, 0,
+ imgleft, imgtop,
+ imgright, 0,
+ imgright, imgtop,
+ widthV, 0,
+ widthV, imgtop };
+ float tex1[] = { 0, 1,
+ 0, textop,
+ texleft, 1,
+ texleft, textop,
+ texright, 1,
+ texright, textop,
+ 1, 1,
+ 1, textop };
+ float vert2[] = { 0, imgtop,
+ 0, imgbottom,
+ imgleft, imgtop,
+ imgleft, imgbottom,
+ imgright, imgtop,
+ imgright, imgbottom,
+ widthV, imgtop,
+ widthV, imgbottom };
+ float tex2[] = { 0, textop,
+ 0, texbottom,
+ texleft, textop,
+ texleft, texbottom,
+ texright, textop,
+ texright, texbottom,
+ 1, textop,
+ 1, texbottom };
+ float vert3[] = { 0, imgbottom,
+ 0, heightV,
+ imgleft, imgbottom,
+ imgleft, heightV,
+ imgright, imgbottom,
+ imgright, heightV,
+ widthV, imgbottom,
+ widthV, heightV };
+ float tex3[] = { 0, texbottom,
+ 0, 0,
+ texleft, texbottom,
+ texleft, 0,
+ texright, texbottom,
+ texright, 0,
+ 1, texbottom,
+ 1, 0 };
+
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, d->_rectTexture.texture());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, 0, vert1);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex1);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ glVertexPointer(2, GL_FLOAT, 0, vert2);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex2);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ glVertexPointer(2, GL_FLOAT, 0, vert3);
+ glTexCoordPointer(2, GL_FLOAT, 0, tex3);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 8);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+ }
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxrect.h b/src/declarative/fx/qfxrect.h
new file mode 100644
index 0000000..42e7b2f
--- /dev/null
+++ b/src/declarative/fx/qfxrect.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXRECT_H
+#define QFXRECT_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxPen : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int width READ width WRITE setWidth)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+public:
+ QFxPen(QObject *parent=0)
+ : QObject(parent), _width(1), _color("#000000"), _valid(false)
+ {}
+
+ int width() const { return _width; }
+ void setWidth(int w) { _width = w; emit updated(); _valid = (_width < 1) ? false : true; }
+
+ QColor color() const { return _color; }
+ void setColor(const QColor &c);
+
+ bool isValid() { return _valid; };
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ int _width;
+ QColor _color;
+ bool _valid;
+};
+QML_DECLARE_TYPE(QFxPen);
+
+class QFxRectPrivate;
+class Q_DECLARATIVE_EXPORT QFxRect : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+ Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor)
+ Q_PROPERTY(QColor gradientColor READ gradientColor WRITE setGradientColor)
+ Q_PROPERTY(QFxPen * pen READ pen)
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius)
+public:
+ QFxRect(QFxItem *parent=0);
+
+ QColor color() const;
+ void setColor(const QColor &);
+
+ QColor tintColor() const;
+ void setTintColor(const QColor &);
+
+ QColor gradientColor() const;
+ void setGradientColor(const QColor &);
+
+ QFxPen *pen();
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+
+ virtual void dump(int depth);
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#endif
+
+#if defined(QFX_RENDER_OPENGL)
+ void paintGLContents(GLPainter &);
+#endif
+
+private Q_SLOTS:
+ void doUpdate();
+
+private:
+ void generateRoundedRect();
+ void generateBorderedRect();
+#if defined(QFX_RENDER_QPAINTER)
+ void drawRect(QPainter &painter);
+#endif
+protected:
+ QFxRect(QFxRectPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxRect)
+ Q_DECLARE_PRIVATE(QFxRect)
+};
+QML_DECLARE_TYPE(QFxRect);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXRECT_H
diff --git a/src/declarative/fx/qfxrect_p.h b/src/declarative/fx/qfxrect_p.h
new file mode 100644
index 0000000..3cb46fa
--- /dev/null
+++ b/src/declarative/fx/qfxrect_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXRECT_P_H
+#define QFXRECT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFxRectPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxRect)
+
+public:
+ QFxRectPrivate()
+ : _pen(0), _radius(0)
+ {
+ }
+
+ ~QFxRectPrivate()
+ {
+ delete _pen;
+ }
+
+ void init()
+ {
+ }
+
+#if defined(QFX_RENDER_OPENGL)
+ GLTexture _rectTexture;
+#endif
+ QColor getColor();
+ QColor _color;
+ QColor _gradcolor;
+ QColor _tintColor;
+ QFxPen *pen() {
+ if(!_pen) {
+ Q_Q(QFxRect);
+ _pen = new QFxPen;
+ QObject::connect(_pen, SIGNAL(updated()), q, SLOT(doUpdate()));
+ }
+ return _pen;
+ }
+ QFxPen *_pen;
+ qreal _radius;
+#if defined(QFX_RENDER_QPAINTER)
+ QSimpleCanvasConfig::Image _rectImage;
+#endif
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXRECT_P_H
diff --git a/src/declarative/fx/qfxreflectionfilter.cpp b/src/declarative/fx/qfxreflectionfilter.cpp
new file mode 100644
index 0000000..a541083
--- /dev/null
+++ b/src/declarative/fx/qfxreflectionfilter.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxreflectionfilter.h"
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <glsave.h>
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glbasicshaders.h>
+#include <gltexture.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+class QFxReflectionFilterPrivate
+{
+public:
+ QFxReflectionFilterPrivate()
+ : alpha(1), height(-1), offset(0), scale(1)
+ {
+ }
+ qreal alpha;
+ int height;
+ int offset;
+ qreal scale;
+};
+
+/*!
+ \qmlclass Reflection
+ \inherits Filter
+ \brief The Reflection filter reflects an item and its contents.
+
+ Here is an example of various Reflections applied to an image.
+
+ \code
+ <HorizontalLayout>
+ <Image src="icon.png" >
+ <filter>
+ <Reflection />
+ </filter>
+ </Image>
+ <Image src="icon.png" >
+ <filter>
+ <Reflection offset="1" />
+ </filter>
+ </Image>
+ <Image src="icon.png" >
+ <filter>
+ <Reflection offset="1" alpha="0.5" />
+ </filter>
+ </Image>
+ <Image src="icon.png" >
+ <filter>
+ <Reflection offset="1" alpha="0.5" height="50" />
+ </filter>
+ </Image>
+ <Image src="icon.png" >
+ <filter>
+ <Reflection offset="1" alpha="0.5" height="50" scale="0.5" />
+ </filter>
+ </Image>
+ </HorizontalLayout>
+ \endcode
+
+ \image reflection_example.png
+
+ Reflection is only supported when Qt Declarative is compiled for OpenGL ES 2.0.
+ Otherwise the Reflection filter has no effect.
+
+ \todo describe (and fix) reflection and bounding box interaction
+
+*/
+
+/*!
+ \internal
+ \class QFxReflectionFilter
+ \ingroup effects
+ \brief The QFxReflectionFilter class allows you to add a reflection to an item.
+*/
+QFxReflectionFilter::QFxReflectionFilter(QObject *parent)
+: QSimpleCanvasFilter(parent), d(new QFxReflectionFilterPrivate)
+{
+}
+
+QFxReflectionFilter::~QFxReflectionFilter()
+{
+ delete d; d = 0;
+}
+
+/*!
+ \property QFxReflectionFilter::alpha
+ \brief the starting opacity of the reflection.
+
+ The starting opacity is the opacity closest to the item. The opacity will fade
+ from this value to zero over the height of the reflection.
+*/
+qreal QFxReflectionFilter::alpha() const
+{
+ return d->alpha;
+}
+
+void QFxReflectionFilter::setAlpha(qreal a)
+{
+ if(d->alpha == a) return;
+ d->alpha = a;
+ emit alphaChanged(a);
+ update();
+}
+
+/*!
+ \qmlproperty int Reflection::height
+
+ The height property controls how much of the item, in pixels, to reflect.
+ If it is set to the default value of -1, the whole item is reflected. If
+ it is set to 50, the bottom 50 pixels of the item are reflected. Data
+ binding could be used to reflect a percentage of the item.
+
+ \code
+ <Image id="myImage" src="album.png">
+ <filter>
+ <Reflection height="{myImage.height * 0.5}" />
+ </filter>
+ </Image>
+ \endcode
+ */
+/*!
+ \qmlproperty int Reflection::offset
+
+ The offset controls how far from the base of the item, in pixels, the
+ start of the reflection is placed. This can be used to create a nice
+ sliver of space between the item and its reflection or for more advanced
+ effects.
+
+ The default offset is 0 pixels.
+*/
+
+/*!
+ \qmlproperty real Reflection::alpha
+
+ The alpha value controls the starting opacity of the reflected item. If
+ set to the default value of 1, the reflected item starts completely opaque
+ and gradually fades to completely transparent. If set to less than one, the
+ reflection starts out partially transparent as though the item was sitting
+ on a visually less reflective surface.
+
+ Valid values are from 0 (which would be silly, but is allowed) to 1.
+*/
+/*!
+ \qmlproperty real Reflection::scale
+
+ When set to the default value of 1, the reflection is a 1:1 reflection of
+ the item. That is, each horizontal pixel in the item corresponds to one
+ horizontal pixel in the reflection.
+
+ When set a value other than 1, the reflection is scaled acordingly - less
+ than 1 scales it down and greater than 1 scales it up. The scale is applied
+ after the height parameter and does not effect the reflection offset.
+*/
+
+/*!
+ \property QFxReflectionFilter::height
+ \brief the height of the reflection, in pixels.
+*/
+int QFxReflectionFilter::height() const
+{
+ return d->height;
+}
+
+void QFxReflectionFilter::setHeight(int h)
+{
+ if(d->height == h) return;
+ d->height = h;
+ emit heightChanged(h);
+ update();
+}
+
+/*!
+ \property QFxReflectionFilter::offset
+ \brief the distance of the reflection from the item, in pixels.
+*/
+int QFxReflectionFilter::offset()
+{
+ return d->offset;
+}
+
+void QFxReflectionFilter::setOffset(int o)
+{
+ if(d->offset == o) return;
+ d->offset = o;
+ emit offsetChanged(o);
+ update();
+}
+
+/*!
+ \property QFxReflectionFilter::scale
+ \brief the scale of the reflection relative to the item.
+*/
+qreal QFxReflectionFilter::scale() const
+{
+ return d->scale;
+}
+
+void QFxReflectionFilter::setScale(qreal s)
+{
+ if(d->scale == s) return;
+ d->scale = s;
+ emit scaleChanged(s);
+ update();
+}
+
+static inline float min(float a, float b)
+{
+ return (a < b)?a:b;
+}
+
+void QFxReflectionFilter::filterGL(QSimpleCanvasItem::GLPainter &p)
+{
+#if defined(QFX_RENDER_OPENGL2)
+ QSimpleCanvasItem *item = this->item();
+
+ QRect r = item->itemBoundingRect();
+ if (r.isEmpty())
+ return;
+ float width = r.width();
+ float height = r.height();
+
+ float refHeight = height;
+ if(d->height > 0)
+ refHeight = min(height, d->height);
+
+ QSimpleCanvas::Matrix simpMat;
+ QSimpleCanvasItem *simpItem = 0;
+ if(isSimpleItem(&simpItem, &simpMat) &&
+ simpItem->glSimpleItemData(0, 0, 0, 0)) {
+
+ GLfloat vertices[8];
+ GLfloat texVertices[8];
+ GLTexture *texture = 0;
+
+ simpItem->glSimpleItemData(vertices, texVertices, &texture, 8);
+
+ GLfloat opacity[4];
+
+ float invRefHeight = 1. / refHeight;
+ for(int ii = 0; ii < 4; ++ii) {
+ float vertex = vertices[ii * 2 + 1];
+ float o = (1. - (height - vertex) * invRefHeight);
+ opacity[ii] = o * d->alpha * p.activeOpacity;
+ }
+
+ QSimpleCanvas::Matrix trans = p.activeTransform;
+ trans.rotate(180, 1, 0, 0);
+ trans.translate(0, -r.height() - d->offset);
+ if(d->scale != 1)
+ trans.scale(1, d->scale, 1);
+ trans.translate(0, -r.height());
+ trans *= simpMat;
+
+ glBindTexture(GL_TEXTURE_2D, texture->texture());
+
+ SingleTextureVertexOpacityShader *shader =
+ item->basicShaders()->singleTextureVertexOpacity();
+ shader->enable();
+ shader->setTransform(trans);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::TextureCoords, texVertices, 2);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::OpacityCoords, opacity, 1);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::Vertices);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::TextureCoords);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::OpacityCoords);
+
+ } else {
+ QGLFramebufferObject *fbo = renderToFBO();
+
+ float texWidth = width / float(fbo->width());
+ float texHeight = refHeight / float(fbo->height());
+
+ GLfloat invVertices[] = { width, height + d->scale * refHeight + d->offset,
+ 0, height + d->scale * refHeight + d->offset,
+ width, height + d->offset,
+ 0, height + d->offset };
+ GLfloat invTexVertices[] = { texWidth, texHeight,
+ 0, texHeight,
+ texWidth, 0,
+ 0, 0 };
+ GLfloat invOpacity[] = { 0, 0, d->alpha * p.activeOpacity, d->alpha * p.activeOpacity};
+
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+
+ SingleTextureVertexOpacityShader *shader =
+ item->basicShaders()->singleTextureVertexOpacity();
+ shader->enable();
+ shader->setTransform(p.activeTransform);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::Vertices, invVertices, 2);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::TextureCoords, invTexVertices, 2);
+ shader->setAttributeArray(SingleTextureVertexOpacityShader::OpacityCoords, invOpacity, 1);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::Vertices);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::TextureCoords);
+ shader->disableAttributeArray(SingleTextureVertexOpacityShader::OpacityCoords);
+
+ releaseFBO(fbo);
+ }
+
+ renderToScreen();
+
+#else
+ Q_UNUSED(p);
+#endif
+}
+
+QRectF QFxReflectionFilter::itemBoundingRect(const QRectF &r) const
+{
+ QRectF rv = r;
+ rv |= r.translated(0, r.height() + d->offset);
+ return rv;
+}
+
+QML_DEFINE_TYPE(QFxReflectionFilter,Reflection);
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxreflectionfilter.h b/src/declarative/fx/qfxreflectionfilter.h
new file mode 100644
index 0000000..b0cc7b2
--- /dev/null
+++ b/src/declarative/fx/qfxreflectionfilter.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXREFLECTIONFILTER_H
+#define QFXREFLECTIONFILTER_H
+
+#include <qsimplecanvasfilter.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxReflectionFilterPrivate;
+class Q_DECLARATIVE_EXPORT QFxReflectionFilter : public QSimpleCanvasFilter
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
+ Q_PROPERTY(int offset READ offset WRITE setOffset NOTIFY offsetChanged)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged)
+public:
+ QFxReflectionFilter(QObject *parent=0);
+ virtual ~QFxReflectionFilter();
+
+ qreal alpha() const;
+ void setAlpha(qreal);
+ int height() const;
+ void setHeight(int);
+ int offset();
+ void setOffset(int);
+ qreal scale() const;
+ void setScale(qreal);
+
+Q_SIGNALS:
+ void alphaChanged(qreal);
+ void heightChanged(int);
+ void offsetChanged(int);
+ void scaleChanged(qreal);
+
+protected:
+ virtual void filterGL(QSimpleCanvasItem::GLPainter &p);
+ virtual QRectF itemBoundingRect(const QRectF &r) const;
+
+private:
+ Q_DISABLE_COPY(QFxReflectionFilter)
+ QFxReflectionFilterPrivate *d;
+};
+QML_DECLARE_TYPE(QFxReflectionFilter);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXREFLECTIONFILTER_H
diff --git a/src/declarative/fx/qfxrepeater.cpp b/src/declarative/fx/qfxrepeater.cpp
new file mode 100644
index 0000000..823932c
--- /dev/null
+++ b/src/declarative/fx/qfxrepeater.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxrepeater.h"
+#include "qfxrepeater_p.h"
+#include "qmllistaccessor.h"
+#include <qlistmodelinterface.h>
+
+
+QT_BEGIN_NAMESPACE
+QFxRepeaterPrivate::QFxRepeaterPrivate()
+: component(0)
+{
+}
+
+QFxRepeaterPrivate::~QFxRepeaterPrivate()
+{
+}
+
+QFxItem *QFxRepeaterPrivate::addItem(QmlContext *ctxt, QFxItem *lastItem)
+{
+ Q_Q(QFxRepeater);
+ QObject *nobj = component->create(ctxt);
+ QFxItem *item = qobject_cast<QFxItem *>(nobj);
+ if (item) {
+ item->setParent(q->itemParent());
+ item->stackUnder(lastItem);
+ deletables << nobj;
+ } else {
+ delete nobj;
+ }
+
+ return item;
+}
+
+QML_DEFINE_TYPE(QFxRepeater,Repeater);
+
+/*!
+ \qmlclass Repeater
+ \inherits Item
+
+ \brief The Repeater element allows you to repeat a component based on a data source.
+
+ The Repeater element is used when you want to create a large number of
+ similar items. For each entry in the data source, an item is instantiated
+ in a context seeded with data from the data source. If the repeater will
+ be instantiating a large number of instances, it may be more efficient to
+ use one of Qt Declarative's \l {xmlViews}{view elements}.
+
+ The data source may be either an object list, a string list or a Qt model.
+ In each case, the data element and the index is exposed to each instantiated
+ component. The index is always exposed as an accessible \c index property.
+ In the case of an object or string list, the data element (of type string
+ or object) is available as the \c modelData property. In the case of a Qt model,
+ all roles are available as named properties just like in the view classes.
+
+ Items instantiated by the Repeater elemented are inserted, in order, as
+ children of the Repeater's parent. The insertion starts immediately after
+ the repeater's position in its parent stacking list. This is to allow
+ you to use a Repeater inside a layout. The following QML example shows how
+ the instantiated items would visually appear stacked between the red and
+ blue rectangles.
+
+ \code
+ <Item>
+ <Rect width="100" height="100" color="red" />
+ <Repeater ...repeater arguments... />
+ <!-- Instantiated items would appear here -->
+ <Rect width="100" height="100" color="blue" />
+ </Item>
+ \endcode
+
+ The repeater instance continues to own all items it instantiates, even
+ if they are otherwise manipulated. It is illegal to manually remove an item
+ created by the Repeater.
+
+ \todo Repeater is very conservative in how it instatiates/deletes items.
+ Also new model entries will not be created and old ones will not be removed.
+
+ \todo Need an example
+
+ */
+
+/*!
+ \internal
+ \class QFxRepeater
+ \ingroup utility
+ \qmlclass Repeater
+
+ \brief The QFxRepeater class allows you to repeat a component based on a
+ data source.
+
+ The QFxRepeater class is used when you want to create a large number of
+ similar items. For each entry in the data source, an item is instantiated
+ in a context seeded with data from the data source.
+
+ The data source may be either an object list, a string list or a Qt model.
+ In each case, the data element and the index is exposed to each instantiated
+ component. The index is always exposed as an accessible \c index property.
+ In the case of an object or string list, the data element (of type string
+ or object) is available as the \c modelData property. In the case of a Qt model,
+ all roles are available as named properties just like in the view classes.
+
+ As a special case the data source can also be merely a number. In this case it will
+ create that many instances of the component. They will also be assigned an index
+ based on the order they are created.
+
+ Items instantiated by the QFxRepeater class are inserted, in order, as
+ children of the repeater's parent. The insertion starts immediately after
+ the repeater's position in its parent stacking list. This is to allow
+ you to use a repeater inside a layout. The following QML example shows how
+ the instantiated items would visually appear stacked between the red and
+ blue rectangles.
+
+ \code
+ <Item>
+ <Rect width="100" height="100" color="red" />
+ <Repeater ...repeater arguments... />
+ <!-- Instantiated items would appear here -->
+ <Rect width="100" height="100" color="blue" />
+ </Item>
+ \endcode
+
+ The QFxRepeater instance continues to own all items it instantiates, even
+ if they are otherwise manipulated. It is illegal to manually delete an item
+ created by the repeater. On destruction, the repeater will clean up any
+ items it has instantiated.
+
+
+ XXX Repeater is very conservative in how it instatiates/deletes items. Also
+ new model entries will not be created and old ones will not be removed.
+ */
+
+/*!
+ Create a new QFxRepeater instance.
+ */
+QFxRepeater::QFxRepeater(QFxItem *parent)
+ : QFxItem(*(new QFxRepeaterPrivate), parent)
+{
+}
+
+/*!
+ \internal
+ */
+QFxRepeater::QFxRepeater(QFxRepeaterPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+}
+
+/*!
+ Destroy the repeater instance. All items it instantiated are also
+ destroyed.
+ */
+QFxRepeater::~QFxRepeater()
+{
+}
+
+/*!
+ \qmlproperty any Repeater::dataSource
+
+ The Repeater's data source.
+*/
+
+/*!
+ \property QFxRepeater::dataSource
+ \brief The source of data for the repeater.
+ */
+QVariant QFxRepeater::dataSource() const
+{
+ return QVariant();
+}
+
+void QFxRepeater::setDataSource(const QVariant &v)
+{
+ Q_D(QFxRepeater);
+ d->dataSource = v;
+ regenerate();
+}
+
+/*!
+ \qmlproperty Component Repeater::component
+ \default
+
+ The component to repeat.
+ */
+/*!
+ \property QFxRepeater::component
+ \brief The component to repeat.
+ */
+QmlComponent *QFxRepeater::component() const
+{
+ Q_D(const QFxRepeater);
+ return d->component;
+}
+
+void QFxRepeater::setComponent(QmlComponent *_c)
+{
+ Q_D(QFxRepeater);
+ d->component = _c;
+ regenerate();
+}
+
+/*!
+ \internal
+ */
+void QFxRepeater::parentChanged(QSimpleCanvasItem *o, QSimpleCanvasItem *n)
+{
+ QFxItem::parentChanged(o, n);
+ regenerate();
+}
+
+/*!
+ \internal
+ */
+void QFxRepeater::regenerate()
+{
+ Q_D(QFxRepeater);
+
+ qDeleteAll(d->deletables);
+ d->deletables.clear();
+ if(!d->component || !itemParent())
+ return;
+
+ QFxItem *lastItem = this;
+
+ if(d->dataSource.type() == QVariant::StringList) {
+ QStringList sl = qvariant_cast<QStringList>(d->dataSource);
+
+ for(int ii = 0; ii < sl.size(); ++ii) {
+ QmlContext *ctxt = new QmlContext(itemContext(), this);
+ d->deletables << ctxt;
+
+ ctxt->setContextProperty(QLatin1String("index"), ii);
+ ctxt->setContextProperty(QLatin1String("modelData"), sl.at(ii));
+
+ if (QFxItem *item = d->addItem(ctxt, lastItem))
+ lastItem = item;
+ }
+ } else if(QmlMetaType::isList(d->dataSource)) {
+ int cnt = QmlMetaType::listCount(d->dataSource);
+ if(cnt <= 0)
+ return;
+
+ for(int ii = 0; ii < cnt; ++ii) {
+ QVariant v = QmlMetaType::listAt(d->dataSource, ii);
+ QObject *o = QmlMetaType::toQObject(v);
+
+ QmlContext *ctxt = new QmlContext(itemContext(), this);
+ d->deletables << ctxt;
+
+ ctxt->setContextProperty(QLatin1String("index"), ii);
+ ctxt->setContextProperty(QLatin1String("modelData"), o);
+
+ if (QFxItem *item = d->addItem(ctxt, lastItem))
+ lastItem = item;
+ }
+ } else if (QListModelInterface *model = qobject_cast<QListModelInterface*>(d->dataSource.value<QObject*>())) {
+ int cnt = model->count();
+ if(cnt <= 0)
+ return;
+
+ for(int ii = 0; ii < cnt; ++ii) {
+ QmlContext *ctxt = new QmlContext(itemContext(), this);
+ d->deletables << ctxt;
+
+ ctxt->setContextProperty(QLatin1String("index"), ii);
+
+ QList<int> roles = model->roles();
+ QHash<int,QVariant> data = model->data(ii,roles);
+ for (int j = 0; j < roles.size(); ++j) {
+ ctxt->setContextProperty(model->toString(roles.at(j)), data.value(roles.at(j)));
+ }
+
+ //for compatability with other lists, assign data if there is only a single role
+ if (roles.size() == 1)
+ ctxt->setContextProperty(QLatin1String("modelData"), data.value(roles.at(0)));
+
+ if (QFxItem *item = d->addItem(ctxt, lastItem))
+ lastItem = item;
+ }
+ } else if (QObject *object = d->dataSource.value<QObject*>()) {
+ // A single object (i.e. list of size 1).
+ // Properties are the roles (excluding objectName).
+ QmlContext *ctxt = new QmlContext(itemContext(), this);
+ d->deletables << ctxt;
+
+ ctxt->setContextProperty(QLatin1String("index"), QVariant(0));
+ for (int ii = 1; ii < object->metaObject()->propertyCount(); ++ii) {
+ const QMetaProperty &prop = object->metaObject()->property(ii);
+ ctxt->setContextProperty(QLatin1String(prop.name()), prop.read(object));
+ }
+
+ //for compatability with other lists, assign data if there is only a single role (excluding objectName)
+ if (object->metaObject()->propertyCount() == 2) {
+ const QMetaProperty &prop = object->metaObject()->property(1);
+ ctxt->setContextProperty(QLatin1String("modelData"), prop.read(object));
+ }
+
+ d->addItem(ctxt, lastItem);
+
+ } else if(d->dataSource.canConvert(QVariant::Int)){
+
+ int count = qvariant_cast<int>(d->dataSource);
+
+ for(int ii = 0; ii < count; ++ii) {
+ QmlContext *ctxt = new QmlContext(itemContext(), this);
+ d->deletables << ctxt;
+
+ ctxt->setContextProperty(QLatin1String("index"), ii);
+
+ if (QFxItem *item = d->addItem(ctxt, lastItem))
+ lastItem = item;
+ }
+ }
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxrepeater.h b/src/declarative/fx/qfxrepeater.h
new file mode 100644
index 0000000..f6c4584
--- /dev/null
+++ b/src/declarative/fx/qfxrepeater.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXREPEATER_H
+#define QFXREPEATER_H
+
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxRepeaterPrivate;
+class Q_DECLARATIVE_EXPORT QFxRepeater : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QVariant dataSource READ dataSource WRITE setDataSource)
+ Q_PROPERTY(QmlComponent *component READ component WRITE setComponent)
+ Q_CLASSINFO("DefaultProperty", "component")
+public:
+ QFxRepeater(QFxItem *parent=0);
+ virtual ~QFxRepeater();
+
+ QVariant dataSource() const;
+ void setDataSource(const QVariant &);
+
+ QmlComponent *component() const;
+ void setComponent(QmlComponent *);
+
+private:
+ void regenerate();
+
+protected:
+ virtual void parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *);
+ QFxRepeater(QFxRepeaterPrivate &dd, QFxItem *parent);
+
+private:
+ Q_DISABLE_COPY(QFxRepeater)
+ Q_DECLARE_PRIVATE(QFxRepeater)
+};
+QML_DECLARE_TYPE(QFxRepeater);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // _QFXREPEATER_H_
diff --git a/src/declarative/fx/qfxrepeater_p.h b/src/declarative/fx/qfxrepeater_p.h
new file mode 100644
index 0000000..ba69658
--- /dev/null
+++ b/src/declarative/fx/qfxrepeater_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXREPEATER_P_H
+#define QFXREPEATER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem_p.h"
+#include "qfxrepeater.h"
+#include <QPointer>
+
+
+QT_BEGIN_NAMESPACE
+
+class QmlContext;
+class QFxRepeaterPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxRepeater)
+
+public:
+ QFxRepeaterPrivate();
+ ~QFxRepeaterPrivate();
+
+ QFxItem *addItem(QmlContext *ctxt, QFxItem *lastItem);
+
+ QVariant dataSource;
+ QmlComponent *component;
+
+ QList<QPointer<QObject> > deletables;
+};
+
+QT_END_NAMESPACE
+#endif // QFXREPEATER_P_H
diff --git a/src/declarative/fx/qfxscalegrid.cpp b/src/declarative/fx/qfxscalegrid.cpp
new file mode 100644
index 0000000..d84f5e8
--- /dev/null
+++ b/src/declarative/fx/qfxscalegrid.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QBuffer>
+#include <qml.h>
+#include "qfxscalegrid.h"
+
+
+QT_BEGIN_NAMESPACE
+/*!
+ \internal
+ \class QFxScaleGrid
+ \brief The QFxScaleGrid class allows you to specify a 3x3 grid to use in scaling an image.
+
+ A scale grid uses 4 grid lines (2 horizontal and 2 vertical) to break an image into 9 sections, as shown below:
+ \image scalegrid.png
+
+ When the image is scaled:
+ \list
+ \i the corners (sections 1, 3, 7, and 9) are not scaled at all
+ \i the middle (section 5) is scaled both horizontally and vertically
+ \i sections 2 and 8 are scaled horizontally
+ \i sections 4 and 6 are scaled vertically
+ \endlist
+
+ A common way of specifying a scale grid is to create an sci file. An sci file uses a simple
+ text-based format that specifies each grid line, as well as the associated image file. An example of an sci file's contents:
+ \code
+ gridLeft: 10
+ gridTop: 10
+ gridBottom: 10
+ gridRight: 10
+ imageFile: picture.png
+ \endcode
+*/
+QML_DEFINE_NOCREATE_TYPE(QFxScaleGrid);
+
+QFxScaleGrid::QFxScaleGrid() : QObject(), _left(0), _top(0), _right(0), _bottom(0)
+{
+}
+
+QFxScaleGrid::~QFxScaleGrid()
+{
+}
+
+bool QFxScaleGrid::isNull() const
+{
+ return !_left && !_top && !_right && !_bottom;
+}
+
+/*!
+ \property QFxScaleGrid::left
+ \brief the position of the left grid line as an offset from the left side of the image.
+*/
+void QFxScaleGrid::setLeft(int pos)
+{
+ _left = pos;
+}
+
+/*!
+ \property QFxScaleGrid::top
+ \brief the position of the top grid line as an offset from the top of the image.
+*/
+void QFxScaleGrid::setTop(int pos)
+{
+ _top = pos;
+}
+
+/*!
+ \property QFxScaleGrid::right
+ \brief the position of the right grid line as an offset from the right side of the image.
+*/
+void QFxScaleGrid::setRight(int pos)
+{
+ _right = pos;
+}
+
+/*!
+ \property QFxScaleGrid::bottom
+ \brief the position of the bottom grid line as an offset from the bottom of the image.
+*/
+void QFxScaleGrid::setBottom(int pos)
+{
+ _bottom = pos;
+}
+
+QFxGridScaledImage::QFxGridScaledImage()
+: _l(-1), _r(-1), _t(-1), _b(-1)
+{
+}
+
+QFxGridScaledImage::QFxGridScaledImage(const QFxGridScaledImage &o)
+: _l(o._l), _r(o._r), _t(o._t), _b(o._b), _pix(o._pix)
+{
+}
+
+QFxGridScaledImage &QFxGridScaledImage::operator=(const QFxGridScaledImage &o)
+{
+ _l = o._l;
+ _r = o._r;
+ _t = o._t;
+ _b = o._b;
+ _pix = o._pix;
+ return *this;
+}
+
+QFxGridScaledImage::QFxGridScaledImage(QIODevice *data)
+: _l(-1), _r(-1), _t(-1), _b(-1)
+{
+ int l = -1;
+ int r = -1;
+ int t = -1;
+ int b = -1;
+ QString imgFile;
+
+ while(!data->atEnd()) {
+ QString line = QString::fromUtf8(data->readLine().trimmed());
+ if(line.isEmpty() || line.startsWith(QLatin1String("#")))
+ continue;
+
+ QStringList list = line.split(QLatin1Char(':'));
+ if(list.count() != 2)
+ return;
+
+ list[0] = list[0].trimmed();
+ list[1] = list[1].trimmed();
+
+ if(list[0] == QLatin1String("gridLeft"))
+ l = list[1].toInt();
+ else if(list[0] == QLatin1String("gridRight"))
+ r = list[1].toInt();
+ else if(list[0] == QLatin1String("gridTop"))
+ t = list[1].toInt();
+ else if(list[0] == QLatin1String("gridBottom"))
+ b = list[1].toInt();
+ else if(list[0] == QLatin1String("imageFile"))
+ imgFile = list[1];
+ }
+
+ if(l < 0 || r < 0 || t < 0 || b < 0 || imgFile.isEmpty())
+ return;
+
+ _l = l; _r = r; _t = t; _b = b;
+
+ _pix = imgFile;
+}
+
+bool QFxGridScaledImage::isValid() const
+{
+ return _l >= 0;
+}
+
+int QFxGridScaledImage::gridLeft() const
+{
+ return _l;
+}
+
+int QFxGridScaledImage::gridRight() const
+{
+ return _r;
+}
+
+int QFxGridScaledImage::gridTop() const
+{
+ return _t;
+}
+
+int QFxGridScaledImage::gridBottom() const
+{
+ return _b;
+}
+
+QString QFxGridScaledImage::pixmapUrl() const
+{
+ return _pix;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxscalegrid.h b/src/declarative/fx/qfxscalegrid.h
new file mode 100644
index 0000000..9010ce7
--- /dev/null
+++ b/src/declarative/fx/qfxscalegrid.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXSCALEGRID_H
+#define QFXSCALEGRID_H
+
+#include <qfxglobal.h>
+#include <QImage>
+#include <QString>
+#include <QObject>
+#include <qsimplecanvas.h>
+#include <qfxpixmap.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxScaleGrid : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int left READ left WRITE setLeft)
+ Q_PROPERTY(int top READ top WRITE setTop)
+ Q_PROPERTY(int right READ right WRITE setRight)
+ Q_PROPERTY(int bottom READ bottom WRITE setBottom)
+public:
+ QFxScaleGrid();
+ ~QFxScaleGrid();
+
+ bool isNull() const;
+
+ int left() const { return _left; }
+ void setLeft(int);
+
+ int top() const { return _top; }
+ void setTop(int);
+
+ int right() const { return _right; }
+ void setRight(int);
+
+ int bottom() const { return _bottom; }
+ void setBottom(int);
+
+private:
+ int _left;
+ int _top;
+ int _right;
+ int _bottom;
+};
+
+class Q_DECLARATIVE_EXPORT QFxGridScaledImage
+{
+public:
+ QFxGridScaledImage();
+ QFxGridScaledImage(const QFxGridScaledImage &);
+ QFxGridScaledImage(QIODevice*);
+ QFxGridScaledImage &operator=(const QFxGridScaledImage &);
+ bool isValid() const;
+ int gridLeft() const;
+ int gridRight() const;
+ int gridTop() const;
+ int gridBottom() const;
+
+ QString pixmapUrl() const;
+
+private:
+ int _l;
+ int _r;
+ int _t;
+ int _b;
+ QString _pix;
+};
+QML_DECLARE_TYPE(QFxScaleGrid);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // QFXSCALEGRID_H
diff --git a/src/declarative/fx/qfxshadowfilter.cpp b/src/declarative/fx/qfxshadowfilter.cpp
new file mode 100644
index 0000000..d10899f
--- /dev/null
+++ b/src/declarative/fx/qfxshadowfilter.cpp
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxshadowfilter.h"
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <glsave.h>
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glbasicshaders.h>
+#endif
+
+class QFxShadowFilterPrivate
+
+QT_BEGIN_NAMESPACE
+{
+public:
+ QFxShadowFilterPrivate()
+ : x(0), y(0)
+ {
+ }
+
+ int x;
+ int y;
+};
+
+/*!
+ \qmlclass Shadow
+ \brief The Shadow filter casts a drop shadow.
+ \inherits Filter
+
+ Shadows work on all visual elements - including transparent and masked
+ images.
+
+ \table
+ \row
+ \o \image shadow_example.png
+ \o
+ \code
+ <Rect radius="5" color="lightsteelblue" width="100" height="100">
+ <filter><Shadow yOffset="8" xOffset="8" /></filter>
+ </Rect>
+ <Image src="pics/qtlogo.png">
+ <filter><Shadow yOffset="8" xOffset="8" /></filter>
+ </Image>
+ \endcode
+ \endtable
+
+ Shadows are only supported when Qt Qt Declarative is compiled for OpenGL ES 2.0.
+ Otherwise the Shadow filter has no effect.
+*/
+
+/*!
+ \internal
+ \class QFxShadowFilter
+ \ingroup effects
+ \brief The QFxShadowFilter class allows you to add a shadow to an item.
+*/
+
+QFxShadowFilter::QFxShadowFilter(QObject *parent)
+: QSimpleCanvasFilter(parent), d(new QFxShadowFilterPrivate)
+{
+}
+
+QFxShadowFilter::~QFxShadowFilter()
+{
+ delete d; d = 0;
+}
+
+/*!
+ \qmlproperty int Shadow::xOffset
+ \qmlproperty int Shadow::yOffset
+
+ Specify the x and y offset of the shadow relative to the item.
+*/
+
+int QFxShadowFilter::xOffset() const
+{
+ return d->x;
+}
+
+/*!
+ \property QFxShadowFilter::xOffset
+ \brief the x offset of the shadow relative to the item.
+*/
+void QFxShadowFilter::setXOffset(int offset)
+{
+ if(d->x == offset) return;
+ d->x = offset;
+ emit offsetChanged(d->x, d->y);
+}
+
+/*!
+ \property QFxShadowFilter::xOffset
+ \brief the y offset of the shadow relative to the item.
+*/
+int QFxShadowFilter::yOffset() const
+{
+ return d->y;
+}
+
+void QFxShadowFilter::setYOffset(int offset)
+{
+ if(d->y == offset) return;
+ d->y = offset;
+ emit offsetChanged(d->x, d->y);
+}
+
+QRectF QFxShadowFilter::itemBoundingRect(const QRectF &r) const
+{
+ QRectF rv = r;
+ rv |= r.translated(xOffset(), yOffset());
+ return rv;
+}
+
+void QFxShadowFilter::filterGL(QSimpleCanvasItem::GLPainter &p)
+{
+#if defined(QFX_RENDER_OPENGL2)
+
+ QSimpleCanvasItem *item = this->item();
+
+ QRect r = item->itemBoundingRect();
+
+ QGLFramebufferObject *fbo = renderToFBO();
+
+ float width = r.width();
+ float height = r.height();
+
+ float texWidth = width / float(fbo->width());
+ float texHeight = height / float(fbo->height());
+
+ GLfloat vertices[] = { d->x, height + d->y,
+ width + d->x, height + d->y,
+ d->x, d->y,
+ d->x + width, d->y };
+ GLfloat texVertices[] = { 0, 0,
+ texWidth, 0,
+ 0, texHeight,
+ texWidth, texHeight };
+
+ SingleTextureShadowShader *shader = item->basicShaders()->singleTextureShadow();
+ shader->enable();
+ shader->setOpacity(0.8 * p.activeOpacity);
+ shader->setTransform(p.activeTransform);
+
+ shader->setAttributeArray(SingleTextureShadowShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureShadowShader::TextureCoords, texVertices, 2);
+
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(SingleTextureShadowShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShadowShader::TextureCoords);
+
+ releaseFBO(fbo);
+
+ renderToScreen();
+#else
+ Q_UNUSED(p);
+#endif
+}
+
+QML_DEFINE_TYPE(QFxShadowFilter,Shadow);
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxshadowfilter.h b/src/declarative/fx/qfxshadowfilter.h
new file mode 100644
index 0000000..9ba3b7b
--- /dev/null
+++ b/src/declarative/fx/qfxshadowfilter.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXSHADOWFILTER_H
+#define QFXSHADOWFILTER_H
+
+#include <qsimplecanvasfilter.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxShadowFilterPrivate;
+class Q_DECLARATIVE_EXPORT QFxShadowFilter : public QSimpleCanvasFilter
+{
+ Q_OBJECT
+ Q_PROPERTY(int xOffset READ xOffset WRITE setXOffset NOTIFY offsetChanged)
+ Q_PROPERTY(int yOffset READ yOffset WRITE setYOffset NOTIFY offsetChanged)
+public:
+ QFxShadowFilter(QObject *parent=0);
+ virtual ~QFxShadowFilter();
+
+ int xOffset() const;
+ void setXOffset(int offset);
+
+ int yOffset() const;
+ void setYOffset(int offset);
+
+Q_SIGNALS:
+ void offsetChanged(int, int);
+
+protected:
+ virtual QRectF itemBoundingRect(const QRectF &) const;
+ virtual void filterGL(QSimpleCanvasItem::GLPainter &p);
+
+private:
+ QFxShadowFilterPrivate *d;
+};
+QML_DECLARE_TYPE(QFxShadowFilter);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // _QFXSHADOWFILTER_H_
diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp
new file mode 100644
index 0000000..9cf1bb0
--- /dev/null
+++ b/src/declarative/fx/qfxtext.cpp
@@ -0,0 +1,958 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxtext.h"
+#include "qfxtext_p.h"
+
+#include <private/qtextcontrol_p.h>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include "glbasicshaders.h"
+#endif
+
+#include <qfxperf.h>
+#include <QTextLayout>
+#include <QTextLine>
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QGraphicsSceneMouseEvent>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxText,Text);
+
+/*!
+ \qmlclass Text QFxText
+ \brief The Text element allows you to add formatted text to a scene.
+ \inherits Item
+
+ It can display both plain and rich text. For example:
+
+ \code
+ <Text text="Hello World!" font.family="Helvetica" font.size="24" color="red"/>
+ <Text>
+ <![CDATA[<b>Hello</b> <i>World!</i>]]]]><![CDATA[>
+ </Text>
+ \endcode
+
+ \image declarative-text.png
+
+ Additional examples can be found in examples/poc/text.xml
+
+ If height and width are not explicitly set, Text will attempt to determine how
+ much room is needed and set it accordingly. Unless \c wrap is set, it will always
+ prefer width to height (all text will be placed on a single line).
+
+ The \c elide property can alternatively be used to fit a single line of
+ plain text to a set width.
+
+ Text provides read-only text. For editable text, see \l TextEdit.
+
+ \todo explain details of auto-sizing
+*/
+
+/*!
+ \internal
+ \class QFxText
+ \qmlclass Text
+ \ingroup coreitems
+
+ \brief The QFxText class provides a formatted text item that you can add to a QFxView.
+
+ Text was designed for read-only text; it does not allow for any text editing.
+ It can display both plain and rich text. For example:
+
+ \code
+ <Text text="Hello World!" font.family="Helvetica" font.size="24" color="red"/>
+ <Text>
+ <![CDATA[<b>Hello</b> <i>World!</i>]]>
+ </Text>
+ \endcode
+
+ \image text.png
+
+ Note that the 'styling' properties such as color and outline are ignored for rich text, styling
+ of rich text should be done within the text itself.
+
+ Additional examples can be found in examples/poc/text.xml
+
+ If height and width are not explicitly set, Text will attempt to determine how
+ much room is needed and set it accordingly. Unless \c wrap is set, it will always
+ prefer width to height (all text will be placed on a single line).
+
+ The \c elideMode can alternatively be used to fit a line of plain text to a set width.
+
+ A QFxText object can be instantiated in Qml using the tag \c &lt;Text&gt;.
+*/
+QFxText::QFxText(QFxItem *parent)
+ : QFxItem(*(new QFxTextPrivate), parent)
+{
+ Q_D(QFxText);
+ d->init();
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setOptions(SimpleItem | HasContents | QFxText::MouseEvents);
+}
+
+QFxText::QFxText(QFxTextPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ Q_D(QFxText);
+ d->init();
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setOptions(SimpleItem | HasContents | QFxText::MouseEvents);
+}
+
+QFxText::~QFxText()
+{
+}
+
+/*!
+ \qmlproperty font Text::font
+
+ Set the Text's font attributes. \c font.size sets the font's point size.
+*/
+
+/*!
+ \property QFxText::font
+ \brief the font used to display the text.
+*/
+
+QmlFont *QFxText::font()
+{
+ Q_D(QFxText);
+ return d->font();
+}
+
+void QFxText::setText(const QString &n)
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::QFxText_setText> st;
+#endif
+ Q_D(QFxText);
+ if(d->text == n)
+ return;
+
+ d->richText = Qt::mightBeRichText(n); // ### what's the cost?
+ if (d->richText) {
+ if (!d->doc)
+ {
+ d->control = new QTextControl(this);
+ d->control->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ d->doc = d->control->document();
+ d->doc->setDocumentMargin(0);
+ }
+ d->doc->setHtml(n);
+ }
+
+ d->text = n;
+ d->imgDirty = true;
+ d->updateSize();
+ emit textChanged(d->text);
+ update();
+}
+
+/*!
+ \qmlproperty string Text::text
+ \default
+
+ The text to display. Text supports both plain and rich text strings.
+
+ The item will try to automatically determine whether the text should
+ be treated as rich text. This determination is made using Qt::mightBeRichText().
+*/
+QString QFxText::text() const
+{
+ Q_D(const QFxText);
+ return d->text;
+}
+
+void QFxText::setColor(const QColor &color)
+{
+ Q_D(QFxText);
+ if(d->color == color)
+ return;
+
+ d->imgDirty = true;
+ d->color = color;
+ update();
+}
+
+/*!
+ \qmlproperty color Text::color
+
+ The text color.
+
+ \code
+ <!-- green text using hexadecimal notation -->
+ <Text color="#00FF00" .../>
+
+ <!-- steelblue text using SVG color name-->
+ <Text color="steelblue" .../>
+ \endcode
+*/
+
+QColor QFxText::color() const
+{
+ Q_D(const QFxText);
+ return d->color;
+}
+
+/*!
+ \qmlproperty enumeration Text::style
+
+ Set an additional text style.
+
+ Supported text styles are \c Normal, \c Outline, \c Raised and \c Sunken.
+
+ \code
+ <HorizontalLayout>
+ <Text font.size="24" text="Normal" />
+ <Text font.size="24" text="Raised" style="Raised" styleColor="#AAAAAA"/>
+ <Text font.size="24" text="Outline" style="Outline" styleColor="red"/>
+ <Text font.size="24" text="Sunken" style="Sunken" styleColor="#AAAAAA"/>
+ </HorizontalLayout>
+ \endcode
+
+ \image declarative-textstyle.png
+*/
+
+/*!
+ \property QFxText::style
+ \brief an additional style of the text to display.
+
+ By default, the text style is Normal.
+
+ \note This property is used to support text styles not natively
+ handled by QFont or QPainter::drawText().
+*/
+QFxText::TextStyle QFxText::style() const
+{
+ Q_D(const QFxText);
+ return d->style;
+}
+
+void QFxText::setStyle(QFxText::TextStyle style)
+{
+ Q_D(QFxText);
+ if(d->style == style)
+ return;
+
+ d->imgDirty = true;
+ d->style = style;
+ update();
+}
+
+void QFxText::setStyleColor(const QColor &color)
+{
+ Q_D(QFxText);
+ if(d->styleColor == color)
+ return;
+
+ d->imgDirty = true;
+ d->styleColor = color;
+ update();
+}
+
+/*!
+ \qmlproperty color Text::styleColor
+
+ Defines the secondary color used by text styles.
+
+ \c styleColor is used as the outline color for outlined text, and as the
+ shadow color for raised or sunken text. If no style has been set, it is not
+ used at all.
+ */
+QColor QFxText::styleColor() const
+{
+ Q_D(const QFxText);
+ return d->styleColor;
+}
+
+/*!
+ \qmlproperty enumeration Text::hAlign
+ \qmlproperty enumeration Text::vAlign
+
+ Sets the horizontal and vertical alignment of the text within the Text elements
+ width and height. By default, the text is top-left aligned.
+
+ The valid values for \c hAlign are \c AlignLeft, \c AlignRight and
+ \c AlignHCenter. The valid values for \c vAlign are \c AlignTop, \c AlignBottom
+ and \c AlignVCenter.
+*/
+
+/*!
+ \property QFxText::hAlign
+ \brief the horizontal alignment of the text.
+
+ Valid values are \c AlignLeft, \c AlignRight, and \c AlignHCenter. The default value is \c AlignLeft.
+*/
+QFxText::HAlignment QFxText::hAlign() const
+{
+ Q_D(const QFxText);
+ return d->hAlign;
+}
+
+void QFxText::setHAlign(HAlignment align)
+{
+ Q_D(QFxText);
+ d->hAlign = align;
+}
+
+/*!
+ \property QFxText::vAlign
+ \brief the vertical alignment of the text.
+
+ Valid values are \c AlignTop, \c AlignBottom, and \c AlignVCenter. The default value is \c AlignTop.
+*/
+QFxText::VAlignment QFxText::vAlign() const
+{
+ Q_D(const QFxText);
+ return d->vAlign;
+}
+
+void QFxText::setVAlign(VAlignment align)
+{
+ Q_D(QFxText);
+ d->vAlign = align;
+}
+
+/*!
+ \qmlproperty bool Text::wrap
+
+ Set this property to wrap the text to the Text element's width. The text will only
+ wrap if an explicit width has been set.
+
+ Wrapping is done on word boundaries (i.e. it is a "word-wrap"). If the text cannot be
+ word-wrapped to the specified width it will be partially drawn outside of the item's bounds.
+ If this is undesirable then enable clipping on the item (Item::clip).
+
+ Wrapping is off by default.
+*/
+//### Future may provide choice of wrap modes, such as QTextOption::WrapAtWordBoundaryOrAnywhere
+bool QFxText::wrap() const
+{
+ Q_D(const QFxText);
+ return d->wrap;
+}
+
+void QFxText::setWrap(bool w)
+{
+ Q_D(QFxText);
+ if (w == d->wrap)
+ return;
+
+ d->wrap = w;
+
+ d->imgDirty = true;
+ d->updateSize();
+}
+
+/*!
+ \qmlproperty Qt::TextElideMode Text::elideMode
+
+ Set this property to elide parts of the text fit to the Text element's width.
+ The text will only elide if an explicit width has been set.
+
+ This property cannot be used with wrap enabled or with rich text.
+
+ Eliding can be ElideNone, ElideLeft, ElideMiddle, or ElideRight.
+
+ ElideNone is the default.
+*/
+Qt::TextElideMode QFxText::elideMode() const
+{
+ Q_D(const QFxText);
+ return d->elideMode;
+}
+
+void QFxText::setElideMode(Qt::TextElideMode mode)
+{
+ Q_D(QFxText);
+ if (mode == d->elideMode)
+ return;
+
+ d->elideMode = mode;
+
+ d->imgDirty = true;
+ d->updateSize();
+}
+
+
+QString QFxText::activeLink() const
+{
+ Q_D(const QFxText);
+ return d->activeLink;
+}
+
+void QFxText::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QFxText);
+ if(newGeometry.width() != oldGeometry.width()) {
+ if (d->wrap || d->elideMode != Qt::ElideNone) {
+ d->imgDirty = true;
+ d->updateSize();
+ }
+ }
+ QFxItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+
+void QFxText::fontChanged()
+{
+ Q_D(QFxText);
+ d->imgDirty = true;
+ d->updateSize();
+ emit update();
+}
+
+void QFxTextPrivate::updateSize()
+{
+ Q_Q(QFxText);
+ if (q->isComponentComplete()) {
+ if(text.isEmpty()) {
+ return;
+ }
+ QFont f; if(_font) f = _font->font();
+ QFontMetrics fm(f);
+ int dy = q->height();
+
+ QString tmp;
+ QSize size(0, 0);
+
+ //setup instance of QTextLayout for all cases other than richtext
+ if (!richText)
+ {
+ tmp = text;
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ singleline = !tmp.contains(QChar::LineSeparator);
+ if (singleline && elideMode != Qt::ElideNone && q->widthValid())
+ tmp = fm.elidedText(tmp,elideMode,q->width()); // XXX still worth layout...?
+ QTextLayout layout;
+ layout.setFont(f);
+ layout.setText(tmp);
+ size = setupTextLayout(&layout);
+ }
+ if (richText) {
+ singleline = false; // richtext can't elide or be optimized for single-line case
+ doc->setDefaultFont(f);
+ QTextOption option((Qt::Alignment)int(hAlign | vAlign));
+ if (wrap)
+ option.setWrapMode(QTextOption::WordWrap);
+ else
+ option.setWrapMode(QTextOption::NoWrap);
+ doc->setDefaultTextOption(option);
+ if (wrap && !q->heightValid() && q->widthValid())
+ doc->setTextWidth(q->width());
+ else
+ doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
+ dy -= (int)doc->size().height();
+ } else {
+ dy -= size.height();
+ }
+ int yoff = 0;
+
+ if (q->heightValid()) {
+ if (vAlign == QFxText::AlignBottom)
+ yoff = dy;
+ else if (vAlign == QFxText::AlignVCenter)
+ yoff = dy/2;
+ }
+ q->setBaselineOffset(fm.ascent() + yoff);
+
+ if (!q->widthValid()) {
+ int newWidth = (richText ? (int)doc->idealWidth() : size.width());
+ q->setImplicitWidth(newWidth);
+ }
+ if (!q->heightValid()) {
+ if (richText) {
+ q->setImplicitHeight((int)doc->size().height());
+ } else {
+ q->setImplicitHeight(size.height());
+ }
+ }
+ } else {
+ dirty = true;
+ }
+}
+
+// ### text layout handling should be profiled and optimized as needed
+// what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
+
+void QFxText::dump(int depth)
+{
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << propertyInfo();
+ QFxItem::dump(depth);
+}
+
+QString QFxText::propertyInfo() const
+{
+ Q_D(const QFxText);
+ return QChar(QLatin1Char('\"')) + d->text + QChar(QLatin1Char('\"'));
+}
+
+void QFxTextPrivate::drawOutline()
+{
+ QImage img = QImage(imgCache.size(), QImage::Format_ARGB32_Premultiplied);
+ QPainter ppm(&img);
+ img.fill(qRgba(0, 0, 0, 0));
+
+ QPoint pos(imgCache.rect().topLeft());
+ pos += QPoint(-1, 0);
+ ppm.drawImage(pos, imgStyleCache);
+ pos += QPoint(2, 0);
+ ppm.drawImage(pos, imgStyleCache);
+ pos += QPoint(-1, -1);
+ ppm.drawImage(pos, imgStyleCache);
+ pos += QPoint(0, 2);
+ ppm.drawImage(pos, imgStyleCache);
+
+ pos += QPoint(0, -1);
+ QPainter &p = ppm;
+ p.drawImage(pos, imgCache);
+
+ imgCache = QSimpleCanvasConfig::toImage(img);
+}
+
+void QFxTextPrivate::drawOutline(int yOffset)
+{
+ QImage img = QImage(imgCache.size(), QImage::Format_ARGB32_Premultiplied);
+ QPainter ppm(&img);
+ img.fill(qRgba(0, 0, 0, 0));
+
+ QPoint pos(imgCache.rect().topLeft());
+ pos += QPoint(0, yOffset);
+ ppm.drawImage(pos, imgStyleCache);
+
+ pos += QPoint(0, -yOffset);
+ QPainter &p = ppm;
+ p.drawImage(pos, imgCache);
+
+ imgCache = QSimpleCanvasConfig::toImage(img);
+}
+
+QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout)
+{
+ Q_Q(QFxText);
+ layout->setCacheEnabled(true);
+
+ QFont f; if(_font) f = _font->font();
+ QFontMetrics fm = QFontMetrics(f);
+
+ int leading = fm.leading();
+ int height = 0;
+ qreal widthUsed = 0;
+ qreal lineWidth = 0;
+
+ //set manual width
+ if ((wrap || elideMode != Qt::ElideNone) && q->widthValid())
+ lineWidth = q->width();
+
+ layout->beginLayout();
+
+ while (1) {
+ QTextLine line = layout->createLine();
+ if (!line.isValid())
+ break;
+
+ if ((wrap || elideMode != Qt::ElideNone) && q->widthValid())
+ line.setLineWidth(lineWidth);
+ }
+ layout->endLayout();
+
+ if (layout->lineCount() == 1)
+ height -= leading;
+
+ for (int i = 0; i < layout->lineCount(); ++i) {
+ QTextLine line = layout->lineAt(i);
+ widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ line.setPosition(QPointF(0, height));
+ height += int(line.height());
+ }
+ return QSize((int)widthUsed, height);
+}
+
+QImage QFxTextPrivate::wrappedTextImage(bool drawStyle)
+{
+ //do layout
+ Q_Q(const QFxText);
+ QFont f; if(_font) f = _font->font();
+ QString tmp = text;
+ if (singleline && elideMode != Qt::ElideNone && q->widthValid()) {
+ QFontMetrics fm(f);
+ tmp = fm.elidedText(tmp,elideMode,q->width()); // XXX still worth layout...?
+ }
+ tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QTextLayout textLayout(tmp, f);
+ QSize size = setupTextLayout(&textLayout);
+
+ int x = 0;
+ for (int i = 0; i < textLayout.lineCount(); ++i) {
+ QTextLine line = textLayout.lineAt(i);
+ if(hAlign == QFxText::AlignLeft) {
+ x = 0;
+ } else if(hAlign == QFxText::AlignRight) {
+ x = size.width() - (int)line.naturalTextWidth();
+ } else if(hAlign == QFxText::AlignHCenter) {
+ x = (size.width() - (int)line.naturalTextWidth()) / 2;
+ }
+ line.setPosition(QPoint(x, (int)line.y()));
+ }
+
+ //paint text
+ QImage img(size, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ QPainter p(&img);
+ if (drawStyle) {
+ p.setPen(styleColor);
+ }
+ else
+ p.setPen(color);
+ p.setFont(f);
+ textLayout.draw(&p, QPointF(0, 0));
+ return img;
+}
+
+QImage QFxTextPrivate::richTextImage(bool drawStyle)
+{
+ QSize size = doc->size().toSize();
+
+ //paint text
+ QImage img(size, QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ QPainter p(&img);
+
+ if (drawStyle) {
+ QPalette pal = control->palette();
+ pal.setColor(QPalette::Text, styleColor);
+ control->setPalette(pal);
+ QTextOption colorOption;
+ colorOption.setFlags(QTextOption::SuppressColors);
+ doc->setDefaultTextOption(colorOption);
+ } else {
+ QPalette pal = control->palette();
+ pal.setColor(QPalette::Text, color);
+ control->setPalette(pal);
+ }
+ control->drawContents(&p, QRectF(QPointF(0, 0), QSizeF(size)));
+ if (drawStyle)
+ doc->setDefaultTextOption(QTextOption());
+ return img;
+}
+
+void QFxTextPrivate::checkImgCache()
+{
+ if(!imgDirty)
+ return;
+
+ bool empty = text.isEmpty();
+ if (empty) {
+ imgCache = QSimpleCanvasConfig::Image();
+ imgStyleCache = QImage();
+ } else if (richText) {
+ imgCache = QSimpleCanvasConfig::toImage(richTextImage(false));
+ if (style != QFxText::Normal)
+ imgStyleCache = richTextImage(true); //### should use styleColor
+ } else {
+ imgCache = QSimpleCanvasConfig::toImage(wrappedTextImage(false));
+ if (style != QFxText::Normal)
+ imgStyleCache = wrappedTextImage(true); //### should use styleColor
+ }
+ if (!empty)
+ switch (style) {
+ case QFxText::Outline:
+ drawOutline();
+ break;
+ case QFxText::Sunken:
+ drawOutline(-1);
+ break;
+ case QFxText::Raised:
+ drawOutline(1);
+ break;
+ default:
+ break;
+ }
+
+#if defined(QFX_RENDER_OPENGL)
+ tex.setImage(imgCache);
+#endif
+
+ imgDirty = false;
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxText::paintContents(QPainter &p)
+{
+ Q_D(QFxText);
+ d->checkImgCache();
+ if(d->imgCache.isNull())
+ return;
+
+ int w = width();
+ int h = height();
+
+ int x = 0;
+ int y = 0;
+
+ switch (d->hAlign) {
+ case AlignLeft:
+ x = 0;
+ break;
+ case AlignRight:
+ x = w - d->imgCache.width();
+ break;
+ case AlignHCenter:
+ x = (w - d->imgCache.width()) / 2;
+ break;
+ }
+
+ switch (d->vAlign) {
+ case AlignTop:
+ y = 0;
+ break;
+ case AlignBottom:
+ y = h - d->imgCache.height();
+ break;
+ case AlignVCenter:
+ y = (h - d->imgCache.height()) / 2;
+ break;
+ }
+
+ p.drawImage(x, y, d->imgCache);
+}
+
+#elif defined(QFX_RENDER_OPENGL2)
+void QFxText::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxText);
+ d->checkImgCache();
+ if(d->imgCache.isNull())
+ return;
+
+ int w = width();
+ int h = height();
+
+ float x = 0;
+ float y = 0;
+
+ switch (d->hAlign) {
+ case AlignLeft:
+ x = 0;
+ break;
+ case AlignRight:
+ x = w - d->imgCache.width();
+ break;
+ case AlignHCenter:
+ x = (w - d->imgCache.width()) / 2;
+ break;
+ }
+
+ switch (d->vAlign) {
+ case AlignTop:
+ y = 0;
+ break;
+ case AlignBottom:
+ y = h - d->imgCache.height();
+ break;
+ case AlignVCenter:
+ y = (h - d->imgCache.height()) / 2;
+ break;
+ }
+
+ float widthV = d->imgCache.width();
+ float heightV = d->imgCache.height();
+
+ QGLShaderProgram *shader = p.useTextureShader();
+
+ GLfloat vertices[] = { x, y + heightV,
+ x + widthV, y + heightV,
+ x, y,
+ x + widthV, y };
+
+ GLfloat texVertices[] = { 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1 };
+
+ shader->setAttributeArray(SingleTextureShader::Vertices, vertices, 2);
+ shader->setAttributeArray(SingleTextureShader::TextureCoords, texVertices, 2);
+
+ glBindTexture(GL_TEXTURE_2D, d->tex.texture());
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ shader->disableAttributeArray(SingleTextureShader::Vertices);
+ shader->disableAttributeArray(SingleTextureShader::TextureCoords);
+}
+
+#elif defined(QFX_RENDER_OPENGL)
+void QFxText::paintGLContents(GLPainter &p)
+{
+ Q_D(QFxText);
+ d->checkImgCache();
+ if(d->imgCache.isNull())
+ return;
+
+ int w = width();
+ int h = height();
+
+ float x = 0;
+ float y = 0;
+
+ switch (d->hAlign) {
+ case AlignLeft:
+ x = 0;
+ break;
+ case AlignRight:
+ x = w - d->imgCache.width();
+ break;
+ case AlignHCenter:
+ x = (w - d->imgCache.width()) / 2;
+ break;
+ }
+
+ switch (d->vAlign) {
+ case AlignTop:
+ y = 0;
+ break;
+ case AlignBottom:
+ y = h - d->imgCache.height();
+ break;
+ case AlignVCenter:
+ y = (h - d->imgCache.height()) / 2;
+ break;
+ }
+
+ float widthV = d->imgCache.width();
+ float heightV = d->imgCache.height();
+
+ GLfloat vertices[] = { x, y + heightV,
+ x + widthV, y + heightV,
+ x, y,
+ x + widthV, y };
+
+ GLfloat texVertices[] = { 0, 0,
+ 1, 0,
+ 0, 1,
+ 1, 1 };
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(p.activeTransform.data());
+ glEnable(GL_TEXTURE_2D);
+ if(p.activeOpacity == 1.) {
+ GLint i = GL_REPLACE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ } else {
+ GLint i = GL_MODULATE;
+ glTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &i);
+ glColor4f(1, 1, 1, p.activeOpacity);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, d->tex.texture());
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FLOAT, 0, texVertices);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisable(GL_TEXTURE_2D);
+}
+
+#endif
+
+void QFxText::componentComplete()
+{
+ Q_D(QFxText);
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::TextComponentComplete> cc;
+#endif
+ QFxItem::componentComplete();
+ if (d->dirty) {
+ d->updateSize();
+ d->dirty = false;
+ }
+}
+
+/*!
+ \overload
+ Handles the given mouse \a event.
+ */
+void QFxText::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxText);
+
+ if (!d->richText || !d->doc || d->control->anchorAt(event->pos()).isEmpty()) {
+ event->setAccepted(false);
+ d->activeLink = QString();
+ } else {
+ d->activeLink = d->control->anchorAt(event->pos());
+ }
+
+ // ### may malfunction if two of the same links are clicked & dragged onto each other)
+
+ if (!event->isAccepted())
+ QFxItem::mousePressEvent(event);
+
+}
+
+/*!
+ \overload
+ Handles the given mouse \a event.
+ */
+void QFxText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxText);
+
+ // ### confirm the link, and send a signal out
+ if (d->richText && d->doc && d->activeLink == d->control->anchorAt(event->pos()))
+ emit linkActivated(d->activeLink);
+ else
+ event->setAccepted(false);
+
+ if (!event->isAccepted())
+ QFxItem::mouseReleaseEvent(event);
+}
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxtext.h b/src/declarative/fx/qfxtext.h
new file mode 100644
index 0000000..0de884b
--- /dev/null
+++ b/src/declarative/fx/qfxtext.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTEXT_H
+#define QFXTEXT_H
+
+#include <qfxitem.h>
+#include <qmlfont.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QFxTextPrivate;
+class Q_DECLARATIVE_EXPORT QFxText : public QFxItem
+{
+ Q_OBJECT
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(TextStyle)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QmlFont *font READ font)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+ Q_PROPERTY(TextStyle style READ style WRITE setStyle)
+ Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor)
+ Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign)
+ Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap)
+ Q_PROPERTY(Qt::TextElideMode elide READ elideMode WRITE setElideMode)
+ Q_PROPERTY(QString activeLink READ activeLink);
+ Q_CLASSINFO("DefaultProperty", "text")
+
+public:
+ QFxText(QFxItem *parent=0);
+ ~QFxText();
+
+ enum HAlignment { AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter };
+ enum VAlignment { AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter };
+ enum TextStyle { Normal,
+ Outline,
+ Raised,
+ Sunken };
+
+ QString text() const;
+ void setText(const QString &);
+
+ QmlFont *font();
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ TextStyle style() const;
+ void setStyle(TextStyle style);
+
+ QColor styleColor() const;
+ void setStyleColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ bool wrap() const;
+ void setWrap(bool w);
+
+ Qt::TextElideMode elideMode() const;
+ void setElideMode(Qt::TextElideMode);
+
+ QString activeLink() const;
+
+ virtual void dump(int depth);
+ virtual QString propertyInfo() const;
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &p);
+#elif defined(QFX_RENDER_OPENGL)
+ void paintGLContents(GLPainter &);
+#endif
+
+ virtual void componentComplete();
+
+Q_SIGNALS:
+ void textChanged(const QString &text);
+ void linkActivated(const QString &link);
+
+private Q_SLOTS:
+ //### should be in QFxTextPrivate?
+ void fontChanged();
+
+protected:
+ QFxText(QFxTextPrivate &dd, QFxItem *parent);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+private:
+ Q_DISABLE_COPY(QFxText)
+ Q_DECLARE_PRIVATE(QFxText)
+};
+QML_DECLARE_TYPE(QFxText);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxtext_p.h b/src/declarative/fx/qfxtext_p.h
new file mode 100644
index 0000000..7be4309
--- /dev/null
+++ b/src/declarative/fx/qfxtext_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTEXT_P_H
+#define QFXTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem.h"
+#include "qfxitem_p.h"
+#include "qml.h"
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+
+class QFxTextPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxText)
+public:
+ QFxTextPrivate()
+ : _font(0), color((QRgb)0), style(QFxText::Normal), imgDirty(true), hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), dirty(false), wrap(false), richText(false), singleline(false), control(0), doc(0)
+ {
+ }
+
+ ~QFxTextPrivate()
+ {
+ delete _font;
+ }
+
+ void init()
+ {
+ }
+
+ void updateSize();
+ void checkImgCache();
+
+ void drawOutline();
+ void drawOutline(int yOffset);
+
+ QImage wrappedTextImage(bool drawStyle);
+ QImage richTextImage(bool drawStyle);
+ QSize setupTextLayout(QTextLayout *layout);
+
+ QString text;
+ QmlFont *font()
+ {
+ if(!_font) {
+ Q_Q(QFxText);
+ _font = new QmlFont;
+ QObject::connect(_font, SIGNAL(updated()), q, SLOT(fontChanged()));
+ }
+ return _font;
+ }
+
+ QmlFont *_font;
+ QColor color;
+ QFxText::TextStyle style;
+ QColor styleColor;
+ QString activeLink;
+ bool imgDirty;
+#if defined(QFX_RENDER_OPENGL)
+ GLTexture tex;
+#endif
+ QSimpleCanvasConfig::Image imgCache;
+ QImage imgStyleCache;
+ QFxText::HAlignment hAlign;
+ QFxText::VAlignment vAlign;
+ Qt::TextElideMode elideMode;
+ bool dirty;
+ bool wrap;
+ bool richText;
+ bool singleline;
+ QTextControl *control;
+ QTextDocument *doc;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp
new file mode 100644
index 0000000..ebfe799
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit.cpp
@@ -0,0 +1,804 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qfxtextedit.h>
+#include "qfxtextedit_p.h"
+
+#include <private/qtextcontrol_p.h>
+
+#if defined(QFX_RENDER_OPENGL2)
+#include "glbasicshaders.h"
+#endif
+
+#include <qfxperf.h>
+#include <QTextLayout>
+#include <QTextLine>
+#include <QTextDocument>
+#include <QGraphicsSceneMouseEvent>
+
+#include <QDebug>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxTextEdit, TextEdit);
+
+/*!
+ \qmlclass TextEdit
+ \brief The TextEdit element allows you to add editable formatted text to a scene.
+ \inherits ImageItem
+
+ It can display both plain and rich text. For example:
+
+ \code
+ <TextEdit id="edit" focus="true" focusable="true"
+ font.family="Helvetica" font.size="20" color="blue" width="240">
+ <![CDATA[<b>Hello</b> <i>World!</i>]]/>
+ </TextEdit>
+ \endcode
+
+ \image declarative-textedit.gif
+
+ \sa Text
+*/
+
+/*!
+ \internal
+ \class QFxTextEdit
+ \qmlclass TextEdit
+ \ingroup coreitems
+
+ \brief The QFxTextEdit class provides an editable formatted text item that you can add to a QFxView.
+
+ It can display both plain and rich text.
+
+ \image declarative-textedit.png
+
+ A QFxTextEdit object can be instantiated in Qml using the tag \c &lt;TextEdit&gt;.
+*/
+
+/*!
+ Constructs a new QFxTextEdit.
+*/
+QFxTextEdit::QFxTextEdit(QFxItem *parent)
+: QFxImageItem(*(new QFxTextEditPrivate), parent)
+{
+ Q_D(QFxTextEdit);
+ d->init();
+}
+
+/*!
+\internal
+*/
+QFxTextEdit::QFxTextEdit(QFxTextEditPrivate &dd, QFxItem *parent)
+ : QFxImageItem(dd, parent)
+{
+ Q_D(QFxTextEdit);
+ d->init();
+}
+
+QString QFxTextEdit::text() const
+{
+ Q_D(const QFxTextEdit);
+
+ if (d->richText)
+ return d->document->toHtml();
+ else
+ return d->document->toPlainText();
+}
+
+/*!
+ \qmlproperty font TextEdit::font
+
+ Set the TextEdit's font attributes. \c font.size sets the font's point size.
+*/
+
+/*!
+ \qmlproperty string TextEdit::text
+ \default
+
+ The text to display. If the text format is AutoText the text edit will
+ automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+*/
+
+/*!
+ \property QFxTextEdit::text
+ \brief the text edit's text
+
+ If the text format is set to AutoText the text edit will try to
+ automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+
+ \sa textFormat
+*/
+
+void QFxTextEdit::setText(const QString &text)
+{
+ Q_D(QFxTextEdit);
+ d->text = text;
+ d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text));
+ if (d->richText) {
+ d->control->setHtml(text);
+ } else {
+ d->control->setPlainText(text);
+ }
+ q_textChanged();
+ updateSize();
+}
+
+/*!
+ \qmlproperty enumeration TextEdit::textFormat
+
+ The way the text property should be displayed.
+
+ Supported text formats are \c AutoText, \c PlainText and \c RichText.
+
+ The default is AutoText. If the text format is AutoText the text edit
+ edit will automatically determine whether the text should be treated as
+ rich text. This determination is made using Qt::mightBeRichText().
+
+ \table
+ \row
+ \o
+ \code
+ <VerticalLayout>
+ <TextEdit font.size="24">
+ <![CDATA[<b>Hello</b> <i>World!</i>]]]]><![CDATA[>
+ </TextEdit>
+ <TextEdit font.size="24" textFormat="RichText">
+ <![CDATA[<b>Hello</b> <i>World!</i>]]]]><![CDATA[>
+ </TextEdit>
+ <TextEdit font.size="24" textFormat="PlainText">
+ <![CDATA[<b>Hello</b> <i>World!</i>]]]]><![CDATA[>
+ </TextEdit>
+ </VerticalLayout>
+ \endcode
+ \o \image declarative-textformat.png
+ \endtable
+*/
+
+/*!
+ \property QFxTextEdit::textFormat
+ \brief this property describes how the text set on the text edit
+ should be interpreted.
+
+ Valid values are \c AutoText, \c PlainText and \c RichText. The
+ default value is \c AutoText, meaning the text edit will attempt
+ to guess how the text should be interpreted using the
+ Qt::mightBeRichText() function.
+
+ \sa text
+*/
+
+QFxTextEdit::TextFormat QFxTextEdit::textFormat() const
+{
+ Q_D(const QFxTextEdit);
+ return d->format;
+}
+
+void QFxTextEdit::setTextFormat(TextFormat format)
+{
+ Q_D(QFxTextEdit);
+ if (format == d->format)
+ return;
+ bool wasRich = d->richText;
+ d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text));
+
+ if (wasRich && !d->richText) {
+ d->control->setPlainText(d->text);
+ updateSize();
+ } else if (!wasRich && d->richText) {
+ d->control->setHtml(d->text);
+ updateSize();
+ }
+ d->format = format;
+}
+
+/*!
+ \property QFxTextEdit::font
+ \brief the text edit's default font
+*/
+
+QmlFont *QFxTextEdit::font()
+{
+ Q_D(QFxTextEdit);
+ return &(d->font);
+}
+
+/*!
+ \qmlproperty color TextEdit::color
+
+ The text color.
+
+ \code
+ <!-- green text using hexadecimal notation -->
+ <TextEdit color="#00FF00" .../>
+
+ <!-- steelblue text using SVG color name-->
+ <TextEdit color="steelblue" .../>
+ \endcode
+*/
+
+/*!
+ \property QFxTextEdit::color
+ \brief the text edit's default text color
+*/
+QColor QFxTextEdit::color() const
+{
+ Q_D(const QFxTextEdit);
+ return d->color;
+}
+
+void QFxTextEdit::setColor(const QColor &color)
+{
+ Q_D(QFxTextEdit);
+ if(d->color == color)
+ return;
+
+ clearCache();
+ d->color = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Text, color);
+ d->control->setPalette(pal);
+ update();
+}
+
+/*!
+ \qmlproperty enumeration TextEdit::hAlign
+ \qmlproperty enumeration TextEdit::vAlign
+
+ Sets the horizontal and vertical alignment of the text within the TextEdit elements
+ width and height. By default, the text is top-left aligned.
+
+ The valid values for \c hAlign are \c AlignLeft, \c AlignRight and
+ \c AlignHCenter. The valid values for \c vAlign are \c AlignTop, \c AlignBottom
+ and \c AlignVCenter.
+*/
+
+/*!
+ \property QFxText::hAlign
+ \brief the horizontal alignment of the text.
+
+ Valid values are \c AlignLeft, \c AlignRight, and \c AlignHCenter. The default value is \c AlignLeft.
+*/
+QFxTextEdit::HAlignment QFxTextEdit::hAlign() const
+{
+ Q_D(const QFxTextEdit);
+ return d->hAlign;
+}
+
+void QFxTextEdit::setHAlign(QFxTextEdit::HAlignment alignment)
+{
+ Q_D(QFxTextEdit);
+ if (alignment == d->hAlign)
+ return;
+ d->hAlign = alignment;
+ d->updateDefaultTextOption();
+ updateSize();
+}
+
+/*!
+ \property QFxText::vAlign
+ \brief the vertical alignment of the text.
+
+ Valid values are \c AlignTop, \c AlignBottom, and \c AlignVCenter. The default value is \c AlignTop.
+*/
+QFxTextEdit::VAlignment QFxTextEdit::vAlign() const
+{
+ Q_D(const QFxTextEdit);
+ return d->vAlign;
+}
+
+void QFxTextEdit::setVAlign(QFxTextEdit::VAlignment alignment)
+{
+ Q_D(QFxTextEdit);
+ if (alignment == d->vAlign)
+ return;
+ d->vAlign = alignment;
+ d->updateDefaultTextOption();
+ updateSize();
+}
+
+bool QFxTextEdit::wrap() const
+{
+ Q_D(const QFxTextEdit);
+ return d->wrap;
+}
+
+/*!
+ \qmlproperty bool TextEdit::wrap
+
+ Set this property to wrap the text to the TextEdit element's width. The text will only wrap if an explicit width has been set.
+
+ Wrapping is done on word boundaries (i.e. it is a "word-wrap"). Wrapping is off by default.
+*/
+
+/*!
+ \property QFxTextEdit::wrap
+ \brief If true the text edit wraps text based on the width of the
+ text edit.
+*/
+void QFxTextEdit::setWrap(bool w)
+{
+ Q_D(QFxTextEdit);
+ if (w == d->wrap)
+ return;
+ d->wrap = w;
+ d->updateDefaultTextOption();
+ updateSize();
+}
+
+
+void QFxTextEdit::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if(newGeometry.width() != oldGeometry.width())
+ updateSize();
+ QFxImageItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+/*!
+ \internal
+*/
+void QFxTextEdit::dump(int depth)
+{
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << propertyInfo();
+ QFxImageItem::dump(depth);
+}
+
+/*!
+ \internal
+*/
+QString QFxTextEdit::propertyInfo() const
+{
+ Q_D(const QFxTextEdit);
+ return QChar(QLatin1Char('\"')) + d->text + QChar(QLatin1Char('\"'));
+}
+
+/*!
+ Ensures any delayed caching or data loading the class
+ needs to performed is complete.
+*/
+void QFxTextEdit::componentComplete()
+{
+ Q_D(QFxTextEdit);
+ QFxImageItem::componentComplete();
+ if (d->dirty) {
+ updateSize();
+ d->dirty = false;
+ }
+}
+
+/*!
+ \qmlproperty bool TextEdit::readOnly
+
+ Whether the user an interact with the TextEdit element. If this
+ property is set to true the text cannot be edited by user interaction.
+
+ By default this property is false.
+*/
+
+/*!
+ \property QFxTextEdit::readOnly
+ \brief If this property is true the text can not be edited by
+ user interaction.
+
+ Changing this property will modify the text interaction flags. If
+ you require more specific control about how user interaction
+ with the text edit is handled, use setTextInteractionFlags() instead.
+
+ \sa setTextInteractionFlags()
+*/
+void QFxTextEdit::setReadOnly(bool r)
+{
+ Q_D(QFxTextEdit);
+
+ Qt::TextInteractionFlags flags = Qt::NoTextInteraction;
+ if (r) {
+ flags = Qt::TextSelectableByMouse;
+ } else {
+ flags = Qt::TextEditorInteraction;
+ }
+ d->control->setTextInteractionFlags(flags);
+ if (!r)
+ d->control->moveCursor(QTextCursor::End);
+}
+
+bool QFxTextEdit::isReadOnly() const
+{
+ Q_D(const QFxTextEdit);
+ return !(d->control->textInteractionFlags() & Qt::TextEditable);
+}
+
+/*!
+ Sets how the text edit should interact with user input to the given
+ \a flags.
+*/
+void QFxTextEdit::setTextInteractionFlags(Qt::TextInteractionFlags flags)
+{
+ Q_D(QFxTextEdit);
+ d->control->setTextInteractionFlags(flags);
+}
+
+/*!
+ Returns the flags specifying how the text edit should interact
+ with user input.
+*/
+Qt::TextInteractionFlags QFxTextEdit::textInteractionFlags() const
+{
+ Q_D(const QFxTextEdit);
+ return d->control->textInteractionFlags();
+}
+
+/*!
+ Returns the cursor for the point at the given \a pos on the
+ text edit.
+*/
+QTextCursor QFxTextEdit::cursorForPosition(const QPoint &pos) const
+{
+ Q_D(const QFxTextEdit);
+ return d->control->cursorForPosition(pos);
+}
+
+/*!
+ Returns the rectangle where the given text \a cursor is rendered
+ within the text edit.
+*/
+QRect QFxTextEdit::cursorRect(const QTextCursor &cursor) const
+{
+ Q_D(const QFxTextEdit);
+ if (cursor.isNull())
+ return QRect();
+
+ return d->control->cursorRect(cursor).toRect();
+}
+
+/*!
+ Returns the rectangle where the text cursor is rendered
+ within the text edit.
+*/
+QRect QFxTextEdit::cursorRect() const
+{
+ Q_D(const QFxTextEdit);
+ return d->control->cursorRect().toRect();
+}
+
+
+/*!
+ Sets the text cursor for the text edit to the given \a cursor.
+*/
+void QFxTextEdit::setTextCursor(const QTextCursor &cursor)
+{
+ Q_D(QFxTextEdit);
+ d->control->setTextCursor(cursor);
+}
+
+/*!
+ Returns the text cursor for the text edit.
+*/
+QTextCursor QFxTextEdit::textCursor() const
+{
+ Q_D(const QFxTextEdit);
+ return d->control->textCursor();
+}
+
+/*!
+Moves the cursor by performing the given \a operation.
+
+If \a mode is QTextCursor::KeepAnchor, the cursor selects the text it moves over. This is the same effect that the user achieves when they hold down the Shift key and move the cursor with the cursor keys.
+*/
+void QFxTextEdit::moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
+{
+ Q_D(QFxTextEdit);
+ d->control->moveCursor(operation, mode);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QFxTextEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QTextCursor c = textCursor();
+ QTextCursor::MoveOperation op = QTextCursor::NoMove;
+ if (event == QKeySequence::MoveToNextChar) {
+ op = QTextCursor::Right;
+ } else if (event == QKeySequence::MoveToPreviousChar) {
+ op = QTextCursor::Left;
+ } else if (event == QKeySequence::MoveToNextWord) {
+ op = QTextCursor::WordRight;
+ } else if (event == QKeySequence::MoveToPreviousWord) {
+ op = QTextCursor::WordLeft;
+ } else if (event == QKeySequence::MoveToNextLine) {
+ op = QTextCursor::Down;
+ } else if (event == QKeySequence::MoveToPreviousLine) {
+ op = QTextCursor::Up;
+ }
+
+ if (op != QTextCursor::NoMove && !c.movePosition(op))
+ event->ignore();
+ else
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QFxTextEdit::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QFxTextEdit);
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+/*!
+\overload
+Handles the given focus \a event.
+*/
+void QFxTextEdit::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QFxImageItem::focusInEvent(event);
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+/*!
+\overload
+Handles the given focus \a event.
+*/
+void QFxTextEdit::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QFxImageItem::focusOutEvent(event);
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+static QMouseEvent *sceneMouseEventToMouseEvent(QGraphicsSceneMouseEvent *e)
+{
+ QEvent::Type t;
+ switch(e->type()) {
+ default:
+ case QEvent::GraphicsSceneMousePress:
+ t = QEvent::MouseButtonPress;
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ t = QEvent::MouseButtonRelease;
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ t = QEvent::MouseMove;
+ break;
+ case QGraphicsSceneEvent::GraphicsSceneMouseDoubleClick:
+ t = QEvent::MouseButtonDblClick;
+ break;
+ }
+
+ QMouseEvent *me = new QMouseEvent(t, e->pos().toPoint(), e->button(), e->buttons(), 0);
+ return me;
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ d->control->processEvent(me, QPointF(0, 0));
+ event->setAccepted(me->isAccepted());
+ delete me;
+ if (!event->isAccepted())
+ QFxImageItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ d->control->processEvent(me, QPointF(0, 0));
+ event->setAccepted(me->isAccepted());
+ delete me;
+ if (!event->isAccepted())
+ QFxImageItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ d->control->processEvent(me, QPointF(0, 0));
+ event->setAccepted(me->isAccepted());
+ delete me;
+ if (!event->isAccepted())
+ QFxImageItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given input method \a event.
+*/
+void QFxTextEdit::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QFxTextEdit);
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+/*!
+\overload
+Returns the value of the given \a property.
+*/
+QVariant QFxTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const
+{
+ Q_D(const QFxTextEdit);
+ return d->control->inputMethodQuery(property);
+}
+
+/*!
+Draws the contents of the text edit using the given \a painter within
+the given \a bounds.
+*/
+void QFxTextEdit::drawContents(QPainter *painter, const QRect &bounds)
+{
+ Q_D(QFxTextEdit);
+
+ painter->setRenderHint(QPainter::TextAntialiasing, true);
+
+ d->control->drawContents(painter, bounds);
+}
+
+/*!
+This signal is emitted when the font of the item changes.
+*/
+void QFxTextEdit::fontChanged()
+{
+ Q_D(QFxTextEdit);
+ clearCache();
+ d->document->setDefaultFont(d->font.font());
+ updateSize();
+ emit update();
+}
+
+void QFxTextEdit::updateImgCache(const QRectF &r)
+{
+ dirtyCache(r.toRect());
+ emit update();
+}
+
+void QFxTextEditPrivate::init()
+{
+ Q_Q(QFxTextEdit);
+
+ q->setSmooth(true);
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+ q->setOptions(QFxTextEdit::AcceptsInputMethods | QFxTextEdit::SimpleItem
+ | QFxTextEdit::HasContents | QFxTextEdit::MouseEvents);
+
+ QObject::connect(&font, SIGNAL(updated()), q, SLOT(fontChanged()));
+
+ control = new QTextControl(q);
+
+ QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF)));
+
+ QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged()));
+ QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged()));
+
+ document = control->document();
+ document->setDefaultFont(font.font());
+ document->setDocumentMargin(0);
+ document->setUndoRedoEnabled(false); // flush undo buffer.
+ document->setUndoRedoEnabled(true);
+}
+
+void QFxTextEdit::q_textChanged()
+{
+ emit textChanged(text());
+}
+
+void QFxTextEdit::updateSize()
+{
+ Q_D(QFxTextEdit);
+ if (isComponentComplete()) {
+ QFontMetrics fm = QFontMetrics(d->font.font());
+ int dy = height();
+ // ### assumes that if the width is set, the text will fill to edges
+ // ### (unless wrap is false, then clipping will occur)
+ if (widthValid())
+ d->document->setTextWidth(width());
+ dy -= (int)d->document->size().height();
+
+ int yoff = 0;
+ if (heightValid()) {
+ if (d->vAlign == AlignBottom)
+ yoff = dy;
+ else if (d->vAlign == AlignVCenter)
+ yoff = dy/2;
+ }
+ setBaselineOffset(fm.ascent() + yoff);
+ if (!widthValid()) {
+ int newWidth = (int)d->document->idealWidth();
+ d->document->setTextWidth(newWidth); // ### QTextDoc> Alignment will not work unless textWidth is set
+ setImplicitWidth(newWidth);
+ }
+ if (!heightValid()) {
+ if (d->text.isEmpty()) {
+ setImplicitHeight(fm.height());
+ } else {
+ setImplicitHeight((int)d->document->size().height());
+ }
+ }
+ setContentsSize(QSize(width(), height()));
+ } else {
+ d->dirty = true;
+ }
+ emit update();
+}
+
+void QFxTextEditPrivate::updateDefaultTextOption()
+{
+ QTextDocument *doc = control->document();
+
+ QTextOption opt = doc->defaultTextOption();
+ int oldAlignment = opt.alignment();
+ opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign));
+
+ QTextOption::WrapMode oldWrapMode = opt.wrapMode();
+
+ if (wrap)
+ opt.setWrapMode(QTextOption::WordWrap);
+ else
+ opt.setWrapMode(QTextOption::NoWrap);
+
+ if (oldWrapMode == opt.wrapMode() && oldAlignment == opt.alignment())
+ return;
+ doc->setDefaultTextOption(opt);
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h
new file mode 100644
index 0000000..be84a3c
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTEXTEDIT_H
+#define QFXTEXTEDIT_H
+
+#include <qfxtext.h>
+#include <qfximageitem.h>
+
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qtextoption.h>
+#include <QtGui/qtextcursor.h>
+#include <QtGui/qtextformat.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+/*!
+WARNING: SHORT TERM CLASS. INTENDED TO MERGE INTO QFxTextItem
+*/
+class QFxTextEditPrivate;
+class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxImageItem
+{
+ Q_OBJECT
+ Q_ENUMS(VAlignment)
+ Q_ENUMS(HAlignment)
+ Q_ENUMS(TextFormat)
+
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+ Q_PROPERTY(QmlFont * font READ font)
+ Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign)
+ Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap)
+ Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_CLASSINFO("DefaultProperty", "text")
+public:
+ QFxTextEdit(QFxItem *parent=0);
+
+ enum HAlignment {
+ AlignLeft = Qt::AlignLeft,
+ AlignRight = Qt::AlignRight,
+ AlignHCenter = Qt::AlignHCenter
+ };
+
+ enum VAlignment {
+ AlignTop = Qt::AlignTop,
+ AlignBottom = Qt::AlignBottom,
+ AlignVCenter = Qt::AlignVCenter
+ };
+
+ enum TextFormat {
+ AutoText,
+ PlainText,
+ RichText,
+ };
+
+ QString text() const;
+ void setText(const QString &);
+
+ TextFormat textFormat() const;
+ void setTextFormat(TextFormat format);
+
+ // leave in, have affect the default text
+ QmlFont *font();
+
+ QColor color() const;
+ void setColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ bool wrap() const;
+ void setWrap(bool w);
+
+ virtual void dump(int depth);
+ virtual QString propertyInfo() const;
+
+ virtual void componentComplete();
+
+ /* FROM EDIT */
+ void setReadOnly(bool);
+ bool isReadOnly() const;
+
+ void setTextInteractionFlags(Qt::TextInteractionFlags flags);
+ Qt::TextInteractionFlags textInteractionFlags() const;
+
+ QTextCursor cursorForPosition(const QPoint &pos) const;
+ QRect cursorRect(const QTextCursor &cursor) const;
+ QRect cursorRect() const;
+
+ void setTextCursor(const QTextCursor &cursor);
+ QTextCursor textCursor() const;
+
+ void moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor);
+
+ QVariant inputMethodQuery(Qt::InputMethodQuery property) const;
+
+Q_SIGNALS:
+ void textChanged(const QString &);
+ void cursorPositionChanged();
+
+private Q_SLOTS:
+ void fontChanged();
+ void updateImgCache(const QRectF &rect);
+ void q_textChanged();
+
+private:
+ void updateSize();
+
+protected:
+ QFxTextEdit(QFxTextEditPrivate &dd, QFxItem *parent);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+ void keyPressEvent(QKeyEvent *);
+ void keyReleaseEvent(QKeyEvent *);
+
+ void focusInEvent(QFocusEvent *);
+ void focusOutEvent(QFocusEvent *);
+
+ // mouse filter?
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+
+ void inputMethodEvent(QInputMethodEvent *e);
+
+ void drawContents(QPainter *, const QRect &);
+private:
+
+ friend class QmlFont;
+ Q_DISABLE_COPY(QFxTextEdit)
+ Q_DECLARE_PRIVATE(QFxTextEdit)
+};
+QML_DECLARE_TYPE(QFxTextEdit);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h
new file mode 100644
index 0000000..aa07484
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTEXTEDIT_P_H
+#define QFXTEXTEDIT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfxitem.h"
+#include "qfximageitem_p.h"
+#include "qml.h"
+
+
+QT_BEGIN_NAMESPACE
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+class QFxTextEditPrivate : public QFxImageItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxTextEdit)
+
+public:
+ QFxTextEditPrivate()
+ : font(0), color("black"), imgDirty(true), hAlign(QFxTextEdit::AlignLeft), vAlign(QFxTextEdit::AlignTop), dirty(false), wrap(false), richText(false), format(QFxTextEdit::AutoText), document(0)
+ {
+ }
+
+ void init();
+
+ void updateDefaultTextOption();
+ void relayoutDocument();
+
+ QString text;
+ QmlFont font;
+ QColor color;
+ QString style;
+ QColor styleColor;
+ bool imgDirty;
+#if defined(QFX_RENDER_OPENGL)
+ GLTexture texture;
+#endif
+ QSimpleCanvasConfig::Image imgCache;
+ QImage imgStyleCache;
+ QFxTextEdit::HAlignment hAlign;
+ QFxTextEdit::VAlignment vAlign;
+ bool dirty;
+ bool wrap;
+ bool richText;
+ QFxTextEdit::TextFormat format;
+ QTextDocument *document;
+ QTextControl *control;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxtransform.cpp b/src/declarative/fx/qfxtransform.cpp
new file mode 100644
index 0000000..8d8e5b4
--- /dev/null
+++ b/src/declarative/fx/qfxtransform.cpp
@@ -0,0 +1,661 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include "private/qfxitem_p.h"
+#include "qfxtransform.h"
+#include <QtDeclarative/qmlinfo.h>
+
+#include <math.h>
+#ifndef M_PI
+
+QT_BEGIN_NAMESPACE
+#define M_PI 3.14159265358979323846
+#endif
+
+QML_DEFINE_TYPE(QFxTransform,Transform);
+
+/*!
+ \qmlclass Transform
+ \brief A transformation.
+
+ \todo Document Transform.
+*/
+QFxTransform::QFxTransform(QObject *parent) :
+ QObject(parent)
+{
+}
+
+bool QFxTransform::isIdentity() const
+{
+ return true;
+}
+
+QSimpleCanvas::Matrix QFxTransform::transform() const
+{
+ return QSimpleCanvas::Matrix();
+}
+
+void QFxTransform::update()
+{
+ QFxItem *item = qobject_cast<QFxItem *>(parent());
+ if(item)
+ item->updateTransform();
+}
+
+QML_DEFINE_TYPE(QFxAxis,Axis);
+
+QFxAxis::QFxAxis(QObject *parent)
+: QFxTransform(parent), _xStart(0), _yStart(0), _xEnd(0), _yEnd(0), _zEnd(0), _rotation(0),
+ _translation(0), _distanceToPlane(1024.), _dirty(true)
+{
+}
+
+qreal QFxAxis::xStart() const
+{
+ return _xStart;
+}
+
+void QFxAxis::setXStart(qreal x)
+{
+ _xStart = x;
+ update();
+}
+
+qreal QFxAxis::yStart() const
+{
+ return _yStart;
+}
+
+void QFxAxis::setYStart(qreal y)
+{
+ _yStart = y;
+ update();
+}
+
+qreal QFxAxis::xEnd() const
+{
+ return _xEnd;
+}
+
+void QFxAxis::setXEnd(qreal x)
+{
+ _xEnd = x;
+ update();
+}
+
+qreal QFxAxis::yEnd() const
+{
+ return _yEnd;
+}
+
+void QFxAxis::setYEnd(qreal y)
+{
+ _yEnd = y;
+ update();
+}
+
+qreal QFxAxis::zEnd() const
+{
+ return _zEnd;
+}
+
+void QFxAxis::setZEnd(qreal z)
+{
+#if !defined(QFX_RENDER_OPENGL)
+ if(z != 0. && translation() != 0.) {
+ qmlInfo(this) << "QTransform cannot translate along Z-axis";
+ return;
+ }
+#endif
+
+ _zEnd = z;
+ update();
+}
+
+qreal QFxAxis::rotation() const
+{
+ return _rotation;
+}
+
+void QFxAxis::setRotation(qreal r)
+{
+ _rotation = r;
+ update();
+}
+
+qreal QFxAxis::translation() const
+{
+ return _translation;
+}
+
+void QFxAxis::setTranslation(qreal t)
+{
+#if !defined(QFX_RENDER_OPENGL)
+ if(zEnd() != 0. && t != 0.) {
+ qmlInfo(this) << "QTransform cannot translate along Z-axis";
+ return;
+ }
+#endif
+
+ _translation = t;
+ update();
+}
+
+bool QFxAxis::isIdentity() const
+{
+ return (_rotation == 0. && _translation == 0.) ||
+ (zEnd() == 0. && yEnd() == yStart() && xEnd() == xStart());
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+const qreal inv_dist_to_plane = 1. / 1024.;
+QTransform QFxAxis::transform() const
+{
+ if(_dirty) {
+ _transform = QTransform();
+
+ if(!isIdentity()) {
+ if(rotation() != 0.) {
+ QTransform rotTrans;
+ rotTrans.translate(-xStart(), -yStart());
+ QTransform rotTrans2;
+ rotTrans2.translate(xStart(), yStart());
+
+ qreal rad = rotation() * 2. * M_PI / 360.;
+ qreal c = ::cos(rad);
+ qreal s = ::sin(rad);
+
+ qreal x = xEnd() - xStart();
+ qreal y = yEnd() - yStart();
+ qreal z = zEnd();
+
+ qreal idtp = inv_dist_to_plane;
+ if(distanceToPlane() != 1024.)
+ idtp = 1. / distanceToPlane();
+
+ qreal len = x * x + y * y + z * z;
+ if(len != 1.) {
+ len = ::sqrt(len);
+ x /= len;
+ y /= len;
+ z /= len;
+ }
+
+ QTransform rot(x*x*(1-c)+c, x*y*(1-c)-z*s, x*z*(1-c)+y*s*idtp,
+ y*x*(1-c)+z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*idtp,
+ 0, 0, 1);
+
+ _transform *= rotTrans;
+ _transform *= rot;
+ _transform *= rotTrans2;
+ }
+
+ if(translation() != 0.) {
+ QTransform trans;
+ trans.translate((xEnd() - xStart()) * translation(),
+ (yEnd() - yStart()) * translation());
+ _transform *= trans;
+ }
+ }
+
+ _dirty = false;
+ }
+
+ return _transform;
+}
+#elif defined(QFX_RENDER_OPENGL)
+QMatrix4x4 QFxAxis::transform() const
+{
+ if(_dirty) {
+ _dirty = false;
+ _transform = QMatrix4x4();
+
+ if(!isIdentity()) {
+ if(rotation() != 0.) {
+ qreal x = xEnd() - xStart();
+ qreal y = yEnd() - yStart();
+ qreal z = zEnd();
+
+ _transform.translate(xStart(), yStart(), 0);
+ _transform.rotate(rotation(), x, y, z);
+ _transform.translate(-xStart(), -yStart(), 0);
+ }
+
+ if(translation() != 0.)
+ _transform.translate((xEnd() - xStart()) * translation(),
+ (yEnd() - yStart()) * translation(),
+ (zEnd()) * translation());
+ }
+ }
+
+ return _transform;
+}
+#endif
+
+qreal QFxAxis::distanceToPlane() const
+{
+ return _distanceToPlane;
+}
+
+void QFxAxis::setDistanceToPlane(qreal d)
+{
+ _distanceToPlane = d;
+ update();
+}
+
+void QFxAxis::update()
+{
+ _dirty = true;
+ QFxItem *item = qobject_cast<QFxItem *>(parent());
+ if(item)
+ item->updateTransform();
+}
+
+QML_DEFINE_TYPE(QFxFlipable,Flipable);
+
+class QFxFlipablePrivate : public QFxItemPrivate
+{
+public:
+ QFxFlipablePrivate() : current(QFxFlipable::Front), front(0), back(0) {}
+
+ QFxFlipable::Side current;
+ QFxItem *front;
+ QFxItem *back;
+};
+
+/*!
+ \qmlclass Flipable QFxFlipable
+ \brief The Flipable element provides a surface that can be flipped.
+ \inherits Item
+
+ Flipable allows you to specify a front and a back and then flip between those sides.
+
+ \code
+ <Flipable id="flipable" width="40" height="40">
+ <transform>
+ <Axis id="axis" xStart="20" xEnd="20" yStart="20" yEnd="0" />
+ </transform>
+ <front>
+ <Image file="front.png"/>
+ </front>
+ <back>
+ <Image file="back.png"/>
+ </back>
+ <states>
+ <State name="back">
+ <SetProperty target="{axis}" property="rotation" value="180" />
+ </State>
+ </states>
+ <transitions>
+ <Transition>
+ <NumericAnimation easing="easeInOutQuad" properties="rotation"/>
+ </Transition>
+ </transitions>
+ </Flipable>
+ \endcode
+
+ \image flipable.gif
+
+ \todo A lot needs to be done to get a fully-functioning Flipable. Should we simplify?
+
+*/
+
+/*!
+ \internal
+ \class QFxFlipable
+ \brief The QFxFlipable class provides a flipable surface.
+
+ \ingroup widgets
+
+ QFxFlipable allows you to specify a front and a back, as well as an
+ axis for the flip.
+*/
+
+QFxFlipable::QFxFlipable(QFxItem *parent)
+: QFxItem(*(new QFxFlipablePrivate), parent)
+{
+}
+
+QFxFlipable::~QFxFlipable()
+{
+}
+
+/*!
+ \qmlproperty Item Flipable::front
+ \qmlproperty Item Flipable::back
+
+ The front and back sides of the flipable.
+*/
+
+QFxItem *QFxFlipable::front()
+{
+ Q_D(const QFxFlipable);
+ return d->front;
+}
+
+void QFxFlipable::setFront(QFxItem *front)
+{
+ Q_D(QFxFlipable);
+ if(d->front) {
+ qmlInfo(this) << "front is a write-once property";
+ return;
+ }
+ d->front = front;
+ children()->append(d->front);
+ if(Back == d->current)
+ d->front->setOpacity(0.);
+}
+
+QFxItem *QFxFlipable::back()
+{
+ Q_D(const QFxFlipable);
+ return d->back;
+}
+
+void QFxFlipable::setBack(QFxItem *back)
+{
+ Q_D(QFxFlipable);
+ if(d->back) {
+ qmlInfo(this) << "back is a write-once property";
+ return;
+ }
+ d->back = back;
+ children()->append(d->back);
+ if(Front == d->current)
+ d->back->setOpacity(0.);
+}
+
+/*!
+ \qmlproperty enumeration Flipable::side
+
+ The side of the Flippable currently visible. Possible values are \c
+ Front and \c Back.
+*/
+QFxFlipable::Side QFxFlipable::side() const
+{
+ Q_D(const QFxFlipable);
+ return d->current;
+}
+
+void QFxFlipable::transformChanged(const QSimpleCanvas::Matrix &trans)
+{
+ Q_D(QFxFlipable);
+ QPointF p1(0, 0);
+ QPointF p2(1, 0);
+ QPointF p3(1, 1);
+
+ p1 = trans.map(p1);
+ p2 = trans.map(p2);
+ p3 = trans.map(p3);
+
+ qreal cross = (p1.x() - p2.x()) * (p3.y() - p2.y()) -
+ (p1.y() - p2.y()) * (p3.x() - p2.x());
+
+ Side newSide;
+ if(cross > 0) {
+ newSide = Back;
+ } else {
+ newSide = Front;
+ }
+
+ if(newSide != d->current) {
+ d->current = newSide;
+ if (d->current==Back) {
+ QSimpleCanvas::Matrix mat;
+#ifdef QFX_RENDER_OPENGL
+ mat.translate(d->back->width()/2,d->back->height()/2, 0);
+ if(d->back->width() && p1.x() >= p2.x())
+ mat.rotate(180, 0, 1, 0);
+ if(d->back->height() && p2.y() >= p3.y())
+ mat.rotate(180, 1, 0, 0);
+ mat.translate(-d->back->width()/2,-d->back->height()/2, 0);
+#else
+ mat.translate(d->back->width()/2,d->back->height()/2);
+ if(d->back->width() && p1.x() >= p2.x())
+ mat.rotate(180, Qt::YAxis);
+ if(d->back->height() && p2.y() >= p3.y())
+ mat.rotate(180, Qt::XAxis);
+ mat.translate(-d->back->width()/2,-d->back->height()/2);
+#endif
+ d->back->setTransform(mat);
+ }
+ if(d->front)
+ d->front->setOpacity((d->current==Front)?1.:0.);
+ if(d->back)
+ d->back->setOpacity((d->current==Back)?1.:0.);
+ emit sideChanged();
+ }
+}
+
+QML_DEFINE_TYPE(QFxPerspective,Perspective);
+
+QFxPerspective::QFxPerspective(QObject *parent)
+ : QFxTransform(parent)
+{
+}
+
+#if defined(QFX_RENDER_OPENGL)
+bool QFxPerspective::isIdentity() const
+{
+ return false;
+}
+
+QMatrix4x4 QFxPerspective::transform() const
+{
+ QMatrix4x4 rv;
+ rv.translate(_x, _y);
+ rv.perspective(_angle, _aspect, 1, 1024 * 1024);
+ rv.translate(-_x, -_y, -1);
+ rv.scale(1, 1, 1. / _scale);
+
+ return rv;
+}
+#endif
+
+QML_DEFINE_TYPE(QFxSquish,Squish);
+
+QFxSquish::QFxSquish(QObject *parent)
+ : QFxTransform(parent)
+{
+}
+
+qreal QFxSquish::x() const
+{
+ return p.x();
+}
+
+void QFxSquish::setX(qreal v)
+{
+ p.setX(v);
+ update();
+}
+
+qreal QFxSquish::y() const
+{
+ return p.y();
+}
+
+void QFxSquish::setY(qreal v)
+{
+ p.setY(v);
+ update();
+}
+
+qreal QFxSquish::width() const
+{
+ return s.width();
+}
+
+void QFxSquish::setWidth(qreal v)
+{
+ s.setWidth(v);
+ update();
+}
+
+qreal QFxSquish::height() const
+{
+ return s.height();
+}
+
+void QFxSquish::setHeight(qreal v)
+{
+ s.setHeight(v);
+ update();
+}
+
+qreal QFxSquish::topLeft_x() const
+{
+ return p1.x();
+}
+
+void QFxSquish::settopLeft_x(qreal v)
+{
+ p1.setX(v);
+ update();
+}
+
+qreal QFxSquish::topLeft_y() const
+{
+ return p1.y();
+}
+
+void QFxSquish::settopLeft_y(qreal v)
+{
+ p1.setY(v);
+ update();
+}
+
+qreal QFxSquish::topRight_x() const
+{
+ return p2.x();
+}
+
+void QFxSquish::settopRight_x(qreal v)
+{
+ p2.setX(v);
+ update();
+}
+
+qreal QFxSquish::topRight_y() const
+{
+ return p2.y();
+}
+
+void QFxSquish::settopRight_y(qreal v)
+{
+ p2.setY(v);
+ update();
+}
+
+qreal QFxSquish::bottomLeft_x() const
+{
+ return p3.x();
+}
+
+void QFxSquish::setbottomLeft_x(qreal v)
+{
+ p3.setX(v);
+ update();
+}
+
+qreal QFxSquish::bottomLeft_y() const
+{
+ return p3.y();
+}
+
+void QFxSquish::setbottomLeft_y(qreal v)
+{
+ p3.setY(v);
+ update();
+}
+
+qreal QFxSquish::bottomRight_x() const
+{
+ return p4.x();
+}
+
+void QFxSquish::setbottomRight_x(qreal v)
+{
+ p4.setX(v);
+ update();
+}
+
+qreal QFxSquish::bottomRight_y() const
+{
+ return p4.y();
+}
+
+void QFxSquish::setbottomRight_y(qreal v)
+{
+ p4.setY(v);
+ update();
+}
+
+void QFxSquish::update()
+{
+ QFxItem *item = qobject_cast<QFxItem *>(parent());
+ if(item)
+ item->updateTransform();
+}
+
+#if defined(QFX_RENDER_OPENGL)
+bool QFxSquish::isIdentity() const
+{
+ return false;
+}
+
+QMatrix4x4 QFxSquish::transform() const
+{
+ QPolygonF poly;
+ poly << p << QPointF(p.x() + s.width(), p.y()) << QPointF(p.x() + s.width(), p.y() + s.height()) << QPointF(p.x(), p.y() + s.height());
+ QPolygonF poly2;
+ poly2 << p1 << p2 << p4 << p3;
+
+ QTransform t;
+ QMatrix4x4 rv;
+ if(QTransform::quadToQuad(poly, poly2, t))
+ rv = QMatrix4x4(t);
+
+ return rv;
+}
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxtransform.h b/src/declarative/fx/qfxtransform.h
new file mode 100644
index 0000000..129a4b4
--- /dev/null
+++ b/src/declarative/fx/qfxtransform.h
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXTRANSFORM_H
+#define QFXTRANSFORM_H
+
+#include <QObject>
+#include <QTransform>
+#if defined(QFX_RENDER_OPENGL)
+#include <QtGui/qmatrix4x4.h>
+#endif
+#include <qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class Q_DECLARATIVE_EXPORT QFxTransform : public QObject
+{
+ Q_OBJECT
+public:
+ QFxTransform(QObject *parent=0);
+
+ void update();
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+};
+QML_DECLARE_TYPE(QFxTransform);
+
+class Q_DECLARATIVE_EXPORT QFxAxis : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal xStart READ xStart WRITE setXStart)
+ Q_PROPERTY(qreal yStart READ yStart WRITE setYStart)
+ Q_PROPERTY(qreal xEnd READ xEnd WRITE setXEnd)
+ Q_PROPERTY(qreal yEnd READ yEnd WRITE setYEnd)
+ Q_PROPERTY(qreal zEnd READ zEnd WRITE setZEnd)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
+ Q_PROPERTY(qreal translation READ translation WRITE setTranslation)
+ Q_PROPERTY(qreal distanceToPlane READ distanceToPlane WRITE setDistanceToPlane)
+public:
+ QFxAxis(QObject *parent=0);
+
+ qreal xStart() const;
+ void setXStart(qreal);
+ qreal yStart() const;
+ void setYStart(qreal);
+
+ qreal xEnd() const;
+ void setXEnd(qreal);
+ qreal yEnd() const;
+ void setYEnd(qreal);
+ qreal zEnd() const;
+ void setZEnd(qreal);
+
+ qreal rotation() const;
+ void setRotation(qreal);
+ qreal translation() const;
+ void setTranslation(qreal);
+
+ qreal distanceToPlane() const;
+ void setDistanceToPlane(qreal);
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+
+private:
+ void update();
+
+ qreal _xStart;
+ qreal _yStart;
+ qreal _xEnd;
+ qreal _yEnd;
+ qreal _zEnd;
+ qreal _rotation;
+ qreal _translation;
+ qreal _distanceToPlane;
+
+ mutable bool _dirty;
+ mutable QSimpleCanvas::Matrix _transform;
+};
+QML_DECLARE_TYPE(QFxAxis);
+
+class Q_DECLARATIVE_EXPORT QFxPerspective : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle)
+ Q_PROPERTY(qreal aspect READ aspect WRITE setAspect)
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale)
+public:
+ QFxPerspective(QObject *parent=0);
+
+ qreal angle() const { return _angle; }
+ void setAngle(qreal v) { _angle = v; update(); }
+
+ qreal aspect() const { return _aspect; }
+ void setAspect(qreal v) { _aspect = v; update(); }
+
+ qreal x() const { return _x; }
+ void setX(qreal v) { _x = v; update(); }
+
+ qreal y() const { return _y; }
+ void setY(qreal v) { _y = v; update(); }
+
+ qreal scale() const { return _scale; }
+ void setScale(qreal v) { _scale = v; update(); }
+
+#if defined(QFX_RENDER_OPENGL)
+ virtual bool isIdentity() const;
+ virtual QMatrix4x4 transform() const;
+#endif
+private:
+ qreal _scale;
+ qreal _x;
+ qreal _y;
+ qreal _angle;
+ qreal _aspect;
+};
+QML_DECLARE_TYPE(QFxPerspective);
+
+class Q_DECLARATIVE_EXPORT QFxSquish : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal x READ x WRITE setX)
+ Q_PROPERTY(qreal y READ y WRITE setY)
+ Q_PROPERTY(qreal width READ width WRITE setWidth)
+ Q_PROPERTY(qreal height READ height WRITE setHeight)
+ Q_PROPERTY(qreal topLeft_x READ topLeft_x WRITE settopLeft_x)
+ Q_PROPERTY(qreal topLeft_y READ topLeft_y WRITE settopLeft_y)
+ Q_PROPERTY(qreal topRight_x READ topRight_x WRITE settopRight_x)
+ Q_PROPERTY(qreal topRight_y READ topRight_y WRITE settopRight_y)
+ Q_PROPERTY(qreal bottomLeft_x READ bottomLeft_x WRITE setbottomLeft_x)
+ Q_PROPERTY(qreal bottomLeft_y READ bottomLeft_y WRITE setbottomLeft_y)
+ Q_PROPERTY(qreal bottomRight_y READ bottomRight_y WRITE setbottomRight_y)
+ Q_PROPERTY(qreal bottomRight_x READ bottomRight_x WRITE setbottomRight_x)
+public:
+ QFxSquish(QObject *parent=0);
+
+ qreal x() const;
+ void setX(qreal);
+
+ qreal y() const;
+ void setY(qreal);
+
+ qreal width() const;
+ void setWidth(qreal);
+
+ qreal height() const;
+ void setHeight(qreal);
+
+ qreal topLeft_x() const;
+ void settopLeft_x(qreal);
+
+ qreal topLeft_y() const;
+ void settopLeft_y(qreal);
+
+ qreal topRight_x() const;
+ void settopRight_x(qreal);
+
+ qreal topRight_y() const;
+ void settopRight_y(qreal);
+
+ qreal bottomLeft_x() const;
+ void setbottomLeft_x(qreal);
+
+ qreal bottomLeft_y() const;
+ void setbottomLeft_y(qreal);
+
+ qreal bottomRight_y() const;
+ void setbottomRight_y(qreal);
+
+ qreal bottomRight_x() const;
+ void setbottomRight_x(qreal);
+
+#if defined(QFX_RENDER_OPENGL)
+ virtual bool isIdentity() const;
+ virtual QMatrix4x4 transform() const;
+#endif
+
+private:
+ void update();
+
+ QPointF p;
+ QSizeF s;
+ QPointF p1, p2, p3, p4;
+};
+
+QML_DECLARE_TYPE(QFxSquish);
+
+class QFxFlipablePrivate;
+class Q_DECLARATIVE_EXPORT QFxFlipable : public QFxItem
+{
+ Q_OBJECT
+
+ Q_ENUMS(Side);
+ Q_PROPERTY(QFxItem *front READ front WRITE setFront)
+ Q_PROPERTY(QFxItem *back READ back WRITE setBack)
+ Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+public:
+ QFxFlipable(QFxItem *parent=0);
+ ~QFxFlipable();
+
+ QFxItem *front();
+ void setFront(QFxItem *);
+
+ QFxItem *back();
+ void setBack(QFxItem *);
+
+ enum Side { Front, Back };
+ Side side() const;
+
+protected:
+ virtual void transformChanged(const QSimpleCanvas::Matrix &);
+
+Q_SIGNALS:
+ void sideChanged();
+
+private:
+ Q_DISABLE_COPY(QFxFlipable)
+ Q_DECLARE_PRIVATE(QFxFlipable)
+};
+QML_DECLARE_TYPE(QFxFlipable);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif // _TRANSFORM_H_
diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp
new file mode 100644
index 0000000..145e750
--- /dev/null
+++ b/src/declarative/fx/qfxvisualitemmodel.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qlistmodelinterface.h"
+#include "qfxitem.h"
+#include <qmlcontext.h>
+#include <qmlexpression.h>
+#include "qmlpackage.h"
+#include "qhash.h"
+#include "qlist.h"
+#include "private/qobject_p.h"
+#include "qmlopenmetaobject.h"
+#include "qmllistaccessor.h"
+#include "qfxvisualitemmodel.h"
+
+
+QT_BEGIN_NAMESPACE
+QML_DECLARE_TYPE(QListModelInterface);
+
+class QFxVisualItemModelParts;
+class QFxVisualItemModelData;
+class QFxVisualItemModelPrivate : public QObjectPrivate
+{
+public:
+ QFxVisualItemModelPrivate(QmlContext *);
+
+ QListModelInterface *m_listModelInterface;
+ QAbstractItemModel *m_abstractItemModel;
+ QFxVisualItemModel *m_visualItemModel;
+ QString m_part;
+
+ QmlComponent *m_delegate;
+ QmlContext *m_context;
+ QList<int> m_roles;
+ QHash<int,QString> m_roleNames;
+
+ QHash<int, QObject *> m_cache;
+ QHash<QObject *, QmlPackage*> m_packaged;
+ QHash<QmlPackage*, int> m_packageRef;
+
+ QFxVisualItemModelParts *m_parts;
+ friend class QFxVisualItemParts;
+
+ QFxVisualItemModelData *data(QObject *item);
+
+ QVariant m_modelVariant;
+ QmlListAccessor *m_modelList;
+
+ int modelCount() const {
+ if(m_visualItemModel)
+ return m_visualItemModel->count();
+ if(m_listModelInterface)
+ return m_listModelInterface->count();
+ if(m_abstractItemModel)
+ return m_abstractItemModel->rowCount();
+ if(m_modelList)
+ return m_modelList->count();
+ return 0;
+ }
+};
+
+class QFxVisualItemModelDataMetaObject : public QmlOpenMetaObject
+{
+public:
+ QFxVisualItemModelDataMetaObject(QObject *parent)
+ : QmlOpenMetaObject(parent) {}
+
+ virtual QVariant propertyCreated(int, QMetaPropertyBuilder &);
+ virtual int createProperty(const char *, const char *);
+
+private:
+ friend class QFxVisualItemModelData;
+ QList<int> roles;
+};
+
+class QFxVisualItemModelData : public QObject
+{
+Q_OBJECT
+public:
+ QFxVisualItemModelData(int index, QFxVisualItemModelPrivate *model);
+
+ Q_PROPERTY(int index READ index NOTIFY indexChanged);
+ int index() const;
+ void setIndex(int index);
+
+ int count() const;
+ int role(int) const;
+ void setValue(int, const QVariant &);
+
+Q_SIGNALS:
+ void indexChanged();
+
+private:
+ friend class QFxVisualItemModelDataMetaObject;
+ int m_index;
+ QFxVisualItemModelPrivate *m_model;
+ QFxVisualItemModelDataMetaObject *m_meta;
+};
+
+int QFxVisualItemModelData::count() const
+{
+ return m_meta->count();
+}
+
+int QFxVisualItemModelData::role(int id) const
+{
+ Q_ASSERT(id >= 0 && id < count());
+ return m_meta->roles.at(id);
+}
+
+void QFxVisualItemModelData::setValue(int id, const QVariant &val)
+{
+ m_meta->setValue(id, val);
+}
+
+int QFxVisualItemModelDataMetaObject::createProperty(const char *name, const char *type)
+{
+ QFxVisualItemModelData *data =
+ static_cast<QFxVisualItemModelData *>(object());
+
+ if ((!data->m_model->m_listModelInterface || !data->m_model->m_abstractItemModel)
+ && data->m_model->m_modelList) {
+ if (!qstrcmp(name, "modelData"))
+ return QmlOpenMetaObject::createProperty(name, type);
+ } else {
+ const QLatin1String sname(name);
+ for(QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
+ iter != data->m_model->m_roleNames.end(); ++iter) {
+
+ if(*iter == sname)
+ return QmlOpenMetaObject::createProperty(name, type);
+ }
+ }
+ return -1;
+}
+
+QVariant
+QFxVisualItemModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+
+ QFxVisualItemModelData *data =
+ static_cast<QFxVisualItemModelData *>(object());
+ QString name = QLatin1String(prop.name());
+ if ((!data->m_model->m_listModelInterface || !data->m_model->m_abstractItemModel)
+ && data->m_model->m_modelList) {
+ return data->m_model->m_modelList->at(data->m_index);
+ } else if (data->m_model->m_listModelInterface) {
+ for(QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
+ iter != data->m_model->m_roleNames.end(); ++iter) {
+
+ if(*iter == name) {
+ roles.append(iter.key());
+ QHash<int,QVariant> values = data->m_model->m_listModelInterface->data(data->m_index, QList<int>() << iter.key());
+ if (values.isEmpty())
+ return QVariant();
+ else
+ return *values.begin();
+ }
+ }
+ } else if (data->m_model->m_abstractItemModel) {
+ for(QHash<int, QString>::ConstIterator iter = data->m_model->m_roleNames.begin();
+ iter != data->m_model->m_roleNames.end(); ++iter) {
+
+ if(*iter == name) {
+ roles.append(iter.key());
+ QModelIndex index = data->m_model->m_abstractItemModel->index(data->m_index, 0);
+ return data->m_model->m_abstractItemModel->data(index, iter.key());
+ }
+ }
+ }
+ Q_ASSERT(!"Can never be reached");
+ return QVariant();
+}
+
+QFxVisualItemModelData::QFxVisualItemModelData(int index,
+ QFxVisualItemModelPrivate *model)
+: m_index(index), m_model(model),
+ m_meta(new QFxVisualItemModelDataMetaObject(this))
+{
+}
+
+int QFxVisualItemModelData::index() const
+{
+ return m_index;
+}
+
+// This is internal only - it should not be set from qml
+void QFxVisualItemModelData::setIndex(int index)
+{
+ m_index = index;
+ emit indexChanged();
+}
+
+class QFxVisualItemModelPartsMetaObject : public QmlOpenMetaObject
+{
+public:
+ QFxVisualItemModelPartsMetaObject(QObject *parent)
+ : QmlOpenMetaObject(parent) {}
+
+ virtual QVariant propertyCreated(int, QMetaPropertyBuilder &);
+};
+
+class QFxVisualItemModelParts : public QObject
+{
+Q_OBJECT
+public:
+ QFxVisualItemModelParts(QFxVisualItemModel *parent);
+
+private:
+ friend class QFxVisualItemModelPartsMetaObject;
+ QFxVisualItemModel *model;
+};
+
+QVariant
+QFxVisualItemModelPartsMetaObject::propertyCreated(int, QMetaPropertyBuilder &prop)
+{
+ prop.setWritable(false);
+
+ QFxVisualItemModel *m = new QFxVisualItemModel;
+ m->setParent(object());
+ m->setPart(QLatin1String(prop.name()));
+ m->setModel(QVariant::fromValue(static_cast<QFxVisualItemModelParts *>(object())->model));
+
+ QVariant var = QVariant::fromValue((QObject *)m);
+ return var;
+}
+
+QFxVisualItemModelParts::QFxVisualItemModelParts(QFxVisualItemModel *parent)
+: QObject(parent), model(parent)
+{
+ new QFxVisualItemModelPartsMetaObject(this);
+}
+
+QFxVisualItemModelPrivate::QFxVisualItemModelPrivate(QmlContext *ctxt)
+: m_listModelInterface(0), m_abstractItemModel(0), m_visualItemModel(0), m_delegate(0)
+, m_context(ctxt), m_parts(0), m_modelList(0)
+{
+}
+
+QFxVisualItemModelData *QFxVisualItemModelPrivate::data(QObject *item)
+{
+ QList<QFxVisualItemModelData *> dataList =
+ item->findChildren<QFxVisualItemModelData *>();
+ Q_ASSERT(dataList.count() == 1);
+ return dataList.first();
+}
+
+QFxVisualItemModel::QFxVisualItemModel()
+: QObject(*(new QFxVisualItemModelPrivate(QmlContext::activeContext())))
+{
+}
+
+QFxVisualItemModel::QFxVisualItemModel(QmlContext *ctxt)
+: QObject(*(new QFxVisualItemModelPrivate(ctxt)))
+{
+}
+
+QFxVisualItemModel::~QFxVisualItemModel()
+{
+ Q_D(QFxVisualItemModel);
+ if(d->m_modelList)
+ delete d->m_modelList;
+}
+
+QVariant QFxVisualItemModel::model() const
+{
+ Q_D(const QFxVisualItemModel);
+ return d->m_modelVariant;
+}
+
+void QFxVisualItemModel::setModel(const QVariant &model)
+{
+ Q_D(QFxVisualItemModel);
+ d->m_modelVariant = model;
+ if(d->m_listModelInterface) {
+ // Assume caller has released all items.
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::disconnect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+ d->m_listModelInterface = 0;
+ } else if (d->m_abstractItemModel) {
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsInserted(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsInserted(const QModelIndex &,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(rowsRemoved(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int)));
+ QObject::disconnect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)),
+ this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&)));
+ } else if(d->m_visualItemModel) {
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ d->m_visualItemModel = 0;
+ }
+
+ QObject *object = qvariant_cast<QObject *>(model);
+ if (object && (d->m_listModelInterface = qobject_cast<QListModelInterface *>(object))) {
+ d->m_roles.clear();
+ d->m_roleNames.clear();
+ if(d->m_listModelInterface) {
+ d->m_roles = d->m_listModelInterface->roles();
+ for(int ii = 0; ii < d->m_roles.count(); ++ii)
+ d->m_roleNames.insert(d->m_roles.at(ii),
+ d->m_listModelInterface->toString(d->m_roles.at(ii)));
+ }
+
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsChanged(int,int,QList<int>)),
+ this, SLOT(_q_itemsChanged(int,int,QList<int>)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsInserted(int,int)),
+ this, SLOT(_q_itemsInserted(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsRemoved(int,int)),
+ this, SLOT(_q_itemsRemoved(int,int)));
+ QObject::connect(d->m_listModelInterface, SIGNAL(itemsMoved(int,int,int)),
+ this, SLOT(_q_itemsMoved(int,int,int)));
+
+ if(d->m_delegate && d->m_listModelInterface->count())
+ emit itemsInserted(0, d->m_listModelInterface->count());
+ return;
+ } else if (object && (d->m_abstractItemModel = qobject_cast<QAbstractItemModel *>(object))) {
+ d->m_roles.clear();
+ d->m_roleNames.clear();
+ for (QHash<int,QByteArray>::const_iterator it = d->m_abstractItemModel->roleNames().begin();
+ it != d->m_abstractItemModel->roleNames().end(); ++it) {
+ d->m_roles.append(it.key());
+ d->m_roleNames.insert(it.key(), QLatin1String(*it));
+ }
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsInserted(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsInserted(const QModelIndex &,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(rowsRemoved(const QModelIndex &,int,int)),
+ this, SLOT(_q_rowsRemoved(const QModelIndex &,int,int)));
+ QObject::connect(d->m_abstractItemModel, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)),
+ this, SLOT(_q_dataChanged(const QModelIndex&,const QModelIndex&)));
+ return;
+ }
+ if ((d->m_visualItemModel = qvariant_cast<QFxVisualItemModel *>(model))) {
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsInserted(int,int)),
+ this, SIGNAL(itemsInserted(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsRemoved(int,int)),
+ this, SIGNAL(itemsRemoved(int,int)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(itemsMoved(int,int,int)),
+ this, SIGNAL(itemsMoved(int,int,int)));
+ return;
+ }
+ if (!d->m_modelList)
+ d->m_modelList = new QmlListAccessor;
+ d->m_modelList->setList(model);
+ if(d->m_delegate && d->modelCount())
+ emit itemsInserted(0, d->modelCount());
+}
+
+QmlComponent *QFxVisualItemModel::delegate() const
+{
+ Q_D(const QFxVisualItemModel);
+ return d->m_delegate;
+}
+
+void QFxVisualItemModel::setDelegate(QmlComponent *delegate)
+{
+ Q_D(QFxVisualItemModel);
+ d->m_delegate = delegate;
+
+ if(d->modelCount())
+ emit itemsInserted(0, d->modelCount());
+}
+
+QString QFxVisualItemModel::part() const
+{
+ Q_D(const QFxVisualItemModel);
+ return d->m_part;
+}
+
+void QFxVisualItemModel::setPart(const QString &part)
+{
+ Q_D(QFxVisualItemModel);
+ d->m_part = part;
+}
+
+int QFxVisualItemModel::count() const
+{
+ Q_D(const QFxVisualItemModel);
+ return d->modelCount();
+}
+
+QFxItem *QFxVisualItemModel::item(int index, bool complete)
+{
+ Q_D(QFxVisualItemModel);
+ if(d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, d->m_part.toLatin1(), complete);
+ return item(index, QByteArray(), complete);
+}
+
+void QFxVisualItemModel::release(QFxItem *item)
+{
+ Q_D(QFxVisualItemModel);
+ if (d->m_visualItemModel) {
+ d->m_visualItemModel->release(item);
+ return;
+ }
+ item->setItemParent(0);
+ QObject *obj = item;
+
+ if (QmlPackage *package = d->m_packaged.value(item)) {
+ static_cast<QObject*>(item)->setParent(package);
+ d->m_packaged.remove(item);
+ //XXX Inefficient
+ for (QHash<QObject *, QmlPackage *>::Iterator iter = d->m_packaged.begin();
+ iter != d->m_packaged.end(); ++iter) {
+ if (*iter == package)
+ return;
+ }
+ obj = package; // fall through and delete
+ }
+
+ //XXX Inefficient
+ for (QHash<int, QObject *>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ++iter) {
+ if (*iter == obj) {
+ delete obj;
+ d->m_cache.erase(iter);
+ return;
+ }
+ }
+}
+
+QObject *QFxVisualItemModel::parts()
+{
+ Q_D(QFxVisualItemModel);
+ if(!d->m_parts)
+ d->m_parts = new QFxVisualItemModelParts(this);
+ return d->m_parts;
+}
+
+QFxItem *QFxVisualItemModel::item(int index, const QByteArray &viewId, bool complete)
+{
+ Q_D(QFxVisualItemModel);
+ if(d->m_visualItemModel)
+ return d->m_visualItemModel->item(index, viewId, complete);
+
+ if(d->modelCount() <= 0 || !d->m_delegate)
+ return 0;
+
+ QObject *nobj = 0;
+ if(d->m_cache.contains(index)) {
+ nobj = d->m_cache[index];
+ } else {
+ QmlContext *ctxt = new QmlContext(d->m_context);
+ QFxVisualItemModelData *data = new QFxVisualItemModelData(index, d);
+ ctxt->setContextProperty(QLatin1String("model"), data);
+ ctxt->addDefaultObject(data);
+ nobj = d->m_delegate->beginCreate(ctxt);
+ if (complete)
+ d->m_delegate->completeCreate();
+ ctxt->setParent(nobj);
+ data->setParent(nobj);
+
+ d->m_cache.insert(index, nobj);
+ }
+
+ QFxItem *item = qobject_cast<QFxItem *>(nobj);
+ if (!item) {
+ QmlPackage *package = qobject_cast<QmlPackage *>(nobj);
+ if(package) {
+ QObject *o = package->part(QLatin1String(viewId));
+ item = qobject_cast<QFxItem *>(o);
+ d->m_packaged[o] = package;
+ }
+ }
+
+ return item;
+}
+
+void QFxVisualItemModel::completeItem()
+{
+ Q_D(QFxVisualItemModel);
+ if(d->m_visualItemModel) {
+ d->m_visualItemModel->completeItem();
+ return;
+ }
+
+ d->m_delegate->completeCreate();
+}
+
+QVariant QFxVisualItemModel::evaluate(int index, const QString &expression, QObject *objectContext)
+{
+ Q_D(QFxVisualItemModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->evaluate(index, expression, objectContext);
+
+ if((!d->m_listModelInterface && !d->m_abstractItemModel) || !d->m_delegate)
+ return QVariant();
+
+ QVariant value;
+ if(d->m_cache.contains(index)) {
+ QObject *nobj = d->m_cache[index];
+ QFxItem *item = qobject_cast<QFxItem *>(nobj);
+ if (item) {
+ QmlExpression e(item->itemContext(), expression, objectContext);
+ e.setTrackChange(false);
+ value = e.value();
+ }
+ } else {
+ QmlContext *ctxt = new QmlContext(d->m_context);
+ QFxVisualItemModelData *data = new QFxVisualItemModelData(index, d);
+ ctxt->addDefaultObject(data);
+ QmlExpression e(ctxt, expression, objectContext);
+ e.setTrackChange(false);
+ value = e.value();
+ delete data;
+ delete ctxt;
+ }
+
+ return value;
+}
+
+void QFxVisualItemModel::_q_itemsChanged(int index, int count,
+ const QList<int> &roles)
+{
+ Q_D(QFxVisualItemModel);
+ // XXX - highly inefficient
+ for(int ii = index; ii < index + count; ++ii) {
+
+ if(d->m_cache.contains(ii)) {
+
+ QObject *item = d->m_cache[ii];
+ QFxVisualItemModelData *data = d->data(item);
+
+ for(int prop = 0; prop < data->count(); ++prop) {
+
+ int role = data->role(prop);
+ if(roles.contains(role)) {
+ if (d->m_listModelInterface) {
+ data->setValue(prop, *d->m_listModelInterface->data(ii, QList<int>() << role).begin());
+ } else if (d->m_abstractItemModel) {
+ QModelIndex index = d->m_abstractItemModel->index(ii, 0);
+ data->setValue(prop, d->m_abstractItemModel->data(index, role));
+ }
+ }
+ }
+ }
+
+ }
+}
+
+void QFxVisualItemModel::_q_itemsInserted(int index, int count)
+{
+ Q_D(QFxVisualItemModel);
+ // XXX - highly inefficient
+ QHash<int, QObject *> items;
+ for(QHash<int, QObject *>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if(iter.key() >= index) {
+ QObject *item = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, item);
+
+ QFxVisualItemModelData *data = d->data(item);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsInserted(index, count);
+}
+
+void QFxVisualItemModel::_q_itemsRemoved(int index, int count)
+{
+ Q_D(QFxVisualItemModel);
+ // XXX - highly inefficient
+ QHash<int, QObject *> items;
+ for(QHash<int, QObject *>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if(iter.key() >= index && iter.key() < index + count) {
+ QObject *item = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, item); //XXX perhaps better to maintain separately
+ QFxVisualItemModelData *data = d->data(item);
+ data->setIndex(-1);
+ } else if(iter.key() >= index + count) {
+ QObject *item = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, item);
+ QFxVisualItemModelData *data = d->data(item);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+
+ d->m_cache.unite(items);
+ emit itemsRemoved(index, count);
+}
+
+void QFxVisualItemModel::_q_itemsMoved(int from, int to, int count)
+{
+ Q_D(QFxVisualItemModel);
+ // XXX - highly inefficient
+ QHash<int, QObject *> items;
+ for(QHash<int, QObject *>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if(iter.key() >= from && iter.key() < from + count) {
+ QObject *item = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, item);
+
+ QFxVisualItemModelData *data = d->data(item);
+ data->setIndex(index);
+ } else {
+ ++iter;
+ }
+ }
+ d->m_cache.unite(items);
+
+ emit itemsMoved(from, to, count);
+}
+
+void QFxVisualItemModel::_q_rowsInserted(const QModelIndex &, int begin, int end)
+{
+ _q_itemsInserted(begin, end - begin + 1);
+}
+
+void QFxVisualItemModel::_q_rowsRemoved(const QModelIndex &, int begin, int end)
+{
+ _q_itemsRemoved(begin, end - begin + 1);
+}
+
+void QFxVisualItemModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end)
+{
+ Q_D(QFxVisualItemModel);
+ _q_itemsChanged(begin.row(), end.row() - begin.row() + 1, d->m_roles);
+}
+
+QML_DEFINE_TYPE(QFxVisualItemModel,VisualModel);
+
+QT_END_NAMESPACE
+#include "qfxvisualitemmodel.moc"
diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h
new file mode 100644
index 0000000..5ec42e9
--- /dev/null
+++ b/src/declarative/fx/qfxvisualitemmodel.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXVISUALITEMMODEL_H
+#define QFXVISUALITEMMODEL_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+/*****************************************************************************
+ *****************************************************************************
+ XXX Experimental
+ *****************************************************************************
+*****************************************************************************/
+
+class QFxItem;
+class QmlComponent;
+class QFxVisualItemModelPrivate;
+class QFxVisualItemModel : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QFxVisualItemModel)
+
+ Q_PROPERTY(QVariant model READ model WRITE setModel)
+ Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate)
+ Q_PROPERTY(QString part READ part WRITE setPart)
+ Q_PROPERTY(QObject *parts READ parts)
+ Q_CLASSINFO("DefaultProperty", "delegate")
+public:
+ QFxVisualItemModel();
+ QFxVisualItemModel(QmlContext *);
+ virtual ~QFxVisualItemModel();
+
+ QVariant model() const;
+ void setModel(const QVariant &);
+
+ QmlComponent *delegate() const;
+ void setDelegate(QmlComponent *);
+
+ QString part() const;
+ void setPart(const QString &);
+
+ int count() const;
+ QFxItem *item(int index, bool complete=true);
+ QFxItem *item(int index, const QByteArray &, bool complete=true);
+ void release(QFxItem *item);
+ void completeItem();
+ QVariant evaluate(int index, const QString &expression, QObject *objectContext);
+
+ QObject *parts();
+
+Q_SIGNALS:
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+
+private Q_SLOTS:
+ void _q_itemsChanged(int, int, const QList<int> &);
+ void _q_itemsInserted(int index, int count);
+ void _q_itemsRemoved(int index, int count);
+ void _q_itemsMoved(int from, int to, int count);
+ void _q_rowsInserted(const QModelIndex &,int,int);
+ void _q_rowsRemoved(const QModelIndex &,int,int);
+ void _q_dataChanged(const QModelIndex&,const QModelIndex&);
+
+private:
+ Q_DISABLE_COPY(QFxVisualItemModel)
+};
+QML_DECLARE_TYPE(QFxVisualItemModel);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXVISUALITEMMODEL_H
diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp
new file mode 100644
index 0000000..c4a2750
--- /dev/null
+++ b/src/declarative/fx/qfxwebview.cpp
@@ -0,0 +1,1079 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDebug>
+#include <QPen>
+#include <QFile>
+#include <QEvent>
+#include <QBasicTimer>
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtWebKit/QWebPage>
+#include <QtWebKit/QWebFrame>
+
+#include "qml.h"
+#include "qmlbindablevalue.h"
+#include "qmlengine.h"
+#include "qmlstate.h"
+#include "qfxtransform.h"
+#include "qfxscalegrid.h"
+#include "qsimplecanvas.h"
+#include "qlistmodelinterface.h"
+
+#if defined(QFX_RENDER_OPENGL2)
+#include <QtOpenGL/qglframebufferobject.h>
+#include <glsave.h>
+#endif
+#if defined(QFX_RENDER_OPENGL)
+#include <gltexture.h>
+#endif
+
+#include "qfxwebview.h"
+#include <qsimplecanvasfilter.h>
+#include <private/qfxitem_p.h>
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxWebView,WebView);
+
+static const int MAX_DOUBLECLICK_TIME=500; // XXX need better gesture system
+
+class QFxWebViewPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxWebView)
+
+public:
+ QFxWebViewPrivate()
+ : page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0),
+ smooth(true), max_imagecache_size(100000), progress(1.0), pending(PendingNone)
+ {
+ }
+
+ QWebPage *page;
+
+ struct ImageCacheItem {
+ ImageCacheItem() : age(0) {}
+ ~ImageCacheItem() { }
+ int age;
+ QRect area;
+#if defined(QFX_RENDER_QPAINTER)
+ QSimpleCanvasConfig::Image image;
+#else
+ GLTexture image;
+#endif
+ };
+ QList<ImageCacheItem*> imagecache;
+ void dirtyCache(const QRect& dirt)
+ {
+ for (int i=0; i<imagecache.count(); ) {
+ if (imagecache[i]->area.intersects(dirt)) {
+ imagecache.removeAt(i);
+ } else {
+ ++i;
+ }
+ }
+ }
+ void clearCache()
+ {
+ foreach (ImageCacheItem* i, imagecache)
+ delete i;
+ imagecache.clear();
+ }
+
+ int idealwidth;
+ int idealheight;
+ bool interactive;
+ QMouseEvent *lastPress, *lastRelease;
+ int mouseX, mouseY;
+ bool smooth;
+ int max_imagecache_size;
+ qreal progress;
+ QBasicTimer dcTimer;
+ QString statusBarMessage;
+ enum { PendingNone, PendingUrl, PendingHtml, PendingContent } pending;
+ QUrl pending_url;
+ QString pending_string;
+ QByteArray pending_data;
+};
+
+
+/*!
+ \qmlclass WebView
+ \brief The WebView element allows you to add web content to a canvas.
+ \inherits Item
+
+ A WebView renders web content based on a URL.
+
+ If the width and height of the element is not set, they will
+ dynamically adjust to a size appropriate for the content.
+ This width may be large (eg. 980) for typical online web pages.
+
+ If the idealWidth is set, the width will be this amount or larger,
+ usually laying out the web content to fit the idealWidth.
+
+ If the idealHeight is set, the height will be this amount or larger.
+ Due to WebKit limitations, the height may be more than necessary
+ if the idealHeight is changed after the content is loaded.
+
+ \code
+ <WebView url="http://www.nokia.com" smooth="true" scale="0.5" width="490" height="400"/>
+ \endcode
+
+ \image webview.png
+
+ The element includes no scrolling, scaling,
+ toolbars, etc., those must be implemented around WebView. See the WebBrowser example
+ for a demonstration of this.
+*/
+
+/*!
+ \internal
+ \class QFxWebView
+ \brief The QFxWebView class allows you to add web content to a QFxView.
+
+ A WebView renders web content base on a URL.
+
+ \image webview.png
+
+ The element includes no scrolling, scaling,
+ toolbars, etc., those must be implemented around WebView. See the WebBrowser example
+ for a demonstration of this.
+
+ A QFxWebView object can be instantiated in Qml using the tag \l WebView.
+*/
+
+QFxWebView::QFxWebView(QFxItem *parent)
+ : QFxItem(*(new QFxWebViewPrivate), parent)
+{
+ init();
+}
+
+QFxWebView::QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ init();
+}
+
+QFxWebView::~QFxWebView()
+{
+ Q_D(QFxWebView);
+ delete d->page;
+}
+
+void QFxWebView::init()
+{
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setOptions(HasContents | MouseEvents);
+ setFocusable(true);
+
+ QWebPage *wp = new QFxWebPage(this);
+
+ // QML elements don't default to having a background,
+ // even though most we pages will set one anyway.
+ QPalette pal = QApplication::palette();
+ pal.setBrush(QPalette::Base, QColor::fromRgbF(0, 0, 0, 0));
+ wp->setPalette(pal);
+
+ wp->setNetworkAccessManager(itemContext()->engine()->networkAccessManager());
+ setPage(wp);
+
+ // XXX settable from QML?
+ settings()->setAttribute(QWebSettings::PluginsEnabled, true);
+}
+
+void QFxWebView::componentComplete()
+{
+ QFxItem::componentComplete();
+ Q_D(QFxWebView);
+ switch (d->pending) {
+ case QFxWebViewPrivate::PendingUrl:
+ setUrl(d->pending_url.toString());
+ break;
+ case QFxWebViewPrivate::PendingHtml:
+ setHtml(d->pending_string, d->pending_url);
+ break;
+ case QFxWebViewPrivate::PendingContent:
+ setContent(d->pending_data, d->pending_string, d->pending_url);
+ break;
+ default:
+ break;
+ }
+ d->pending = QFxWebViewPrivate::PendingNone;
+}
+
+/*!
+ \qmlproperty real WebView::progress
+ This property holds the progress of loading the current URL, from 0 to 1.
+*/
+/*!
+ \property qreal QFxWebView::progress
+ \brief the progress of loading the current URL, from 0 to 1.
+*/
+qreal QFxWebView::progress() const
+{
+ Q_D(const QFxWebView);
+ return d->progress;
+}
+
+void QFxWebView::doLoadProgress(int p)
+{
+ Q_D(QFxWebView);
+ if (d->progress == p/100.0)
+ return;
+ d->progress = p/100.0;
+ expandToWebPage();
+ emit progressChanged();
+}
+
+void QFxWebView::doLoadFinished(bool ok)
+{
+ // XXX bug 232556 - pages with no title never get this signal
+ if (title().isEmpty())
+ emit urlChanged();
+
+ if (ok) {
+ emit loadFinished();
+ } else {
+ emit loadFailed();
+ }
+}
+
+/*!
+ \qmlproperty string WebView::url
+ This property holds the URL to the page displayed in this item.
+
+ Note that after this property is set, it may take some time
+ before the change is notified, as this only happens when
+ loading of the URL successfully starts.
+*/
+/*!
+ \property QString QFxWebView::url
+ \brief the URL to the page displayed in this item.
+
+ \sa urlChanged()
+*/
+/*!
+ \fn void QFxWebView::urlChanged()
+
+ Emitted when loading of the URL successfully starts after
+ setUrl() is called.
+*/
+QString QFxWebView::url() const
+{
+ Q_D(const QFxWebView);
+ return d->page->mainFrame()->url().toString();
+}
+
+void QFxWebView::setUrl(const QString &n)
+{
+ Q_D(QFxWebView);
+ if(n == d->page->mainFrame()->url().toString())
+ return;
+
+ d->page->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+
+ QUrl url(n);
+ if (url.isRelative())
+ url = itemContext()->resolvedUrl(n);
+
+ if (isComponentComplete())
+ d->page->mainFrame()->load(url);
+ else {
+ d->pending = d->PendingUrl;
+ d->pending_url = url;
+ }
+
+ // emit urlChanged() - not until actually loaded
+}
+
+/*!
+ \qmlproperty int WebView::idealWidth
+ This property holds the ideal width for displaying the current URL.
+*/
+/*!
+ \property int QFxWebView::idealWidth
+ \brief the ideal width for displaying the current URL.
+*/
+int QFxWebView::idealWidth() const
+{
+ Q_D(const QFxWebView);
+ return d->idealwidth;
+}
+
+void QFxWebView::setIdealWidth(int iw)
+{
+ Q_D(QFxWebView);
+ if(d->idealwidth == iw) return;
+ d->idealwidth = iw;
+ expandToWebPage();
+ emit idealWidthChanged();
+}
+
+/*!
+ \qmlproperty int WebView::idealHeight
+ This property holds the ideal height for displaying the current URL.
+*/
+/*!
+ \property int QFxWebView::idealHeight
+ \brief the ideal height for displaying the current URL.
+*/
+int QFxWebView::idealHeight() const
+{
+ Q_D(const QFxWebView);
+ return d->idealheight;
+}
+
+void QFxWebView::setIdealHeight(int ih)
+{
+ Q_D(QFxWebView);
+ if(d->idealheight == ih) return;
+ d->idealheight = ih;
+ expandToWebPage();
+ emit idealHeightChanged();
+}
+
+/*!
+ \qmlproperty bool WebView::interactive
+ This property holds controls whether the item responds to mouse and key events.
+*/
+/*!
+ \property bool QFxWebView::interactive
+ \brief controls whether the item responds to mouse and key events.
+*/
+bool QFxWebView::interactive() const
+{
+ Q_D(const QFxWebView);
+ return d->interactive;
+}
+
+void QFxWebView::setInteractive(bool i)
+{
+ Q_D(QFxWebView);
+ if(d->interactive == i) return;
+ d->interactive = i;
+ emit interactiveChanged();
+}
+
+/*!
+ \qmlproperty bool WebView::smooth
+ This property holds hints as to whether the item should be drawn anti-aliased.
+*/
+/*!
+ \property bool QFxWebView::smooth
+ \brief hints as to whether the item should be drawn anti-aliased.
+*/
+bool QFxWebView::smooth() const
+{
+ Q_D(const QFxWebView);
+ return d->smooth;
+}
+
+void QFxWebView::setSmooth(bool i)
+{
+ Q_D(QFxWebView);
+ if(d->smooth == i) return;
+ d->smooth = i;
+ update();
+}
+
+void QFxWebView::updateCacheForVisibility()
+{
+ Q_D(QFxWebView);
+ if (!isVisible())
+ d->clearCache();
+}
+
+void QFxWebView::expandToWebPage()
+{
+ Q_D(QFxWebView);
+ QSize cs = d->page->mainFrame()->contentsSize();
+ if (cs.width() < d->idealwidth)
+ cs.setWidth(d->idealwidth);
+ if (cs.height() < d->idealheight)
+ cs.setHeight(d->idealheight);
+ if (widthValid() && cs.width() < width())
+ cs.setWidth(width());
+ if (heightValid() && cs.height() < height())
+ cs.setHeight(height());
+ if (cs != d->page->viewportSize()) {
+ d->page->setViewportSize(cs);
+ d->clearCache();
+ setImplicitWidth(cs.width());
+ setImplicitHeight(cs.height());
+ }
+}
+
+void QFxWebView::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if(newGeometry.size() != oldGeometry.size())
+ expandToWebPage();
+ QFxItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QFxWebView::paintPage(const QRect& r)
+{
+ Q_D(QFxWebView);
+ d->dirtyCache(r);
+ update();
+}
+
+/*!
+ \qmlproperty int WebView::cacheSize
+ This property holds the maximum number of pixels of image cache to allow
+
+ The default is 0.1 megapixels.
+
+ The cache will not be larger than the (unscaled) size of the WebView.
+*/
+/*!
+ \property int QFxWebView::cacheSize
+ \brief the maximum number of pixels of image cache to allow
+ The default is 0.1 megapixels.
+
+ The cache will not be larger than the (unscaled) size of the QFxWebView.
+*/
+int QFxWebView::cacheSize() const
+{
+ Q_D(const QFxWebView);
+ return d->max_imagecache_size;
+}
+
+void QFxWebView::setCacheSize(int pixels)
+{
+ Q_D(QFxWebView);
+ if (pixels < d->max_imagecache_size) {
+ int cachesize=0;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ QRect area = d->imagecache[i]->area;
+ cachesize += area.width()*area.height();
+ }
+ while (d->imagecache.count() && cachesize > pixels) {
+ int oldest=-1;
+ int age=-1;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ int a = d->imagecache[i]->age;
+ if (a > age) {
+ oldest = i;
+ age = a;
+ }
+ }
+ cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height();
+ d->imagecache.removeAt(oldest);
+ }
+ }
+ d->max_imagecache_size = pixels;
+}
+
+void QFxWebView::dump(int depth)
+{
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << "url:" << url();
+ QFxItem::dump(depth);
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxWebView::paintContents(QPainter &p)
+#elif defined(QFX_RENDER_OPENGL)
+void QFxWebView::paintGLContents(GLPainter &p)
+#else
+#error "What render?"
+#endif
+{
+ Q_D(QFxWebView);
+ QWebFrame *frame = d->page->mainFrame();
+ const QRect content(QPoint(0,0),frame->contentsSize());
+
+ if (content.width() <= 0 || content.height() <= 0)
+ return;
+
+#if defined(QFX_RENDER_QPAINTER)
+ bool wasAA = p.testRenderHint(QPainter::Antialiasing);
+ p.setRenderHints(QPainter::Antialiasing, d->smooth);
+ QRectF clipf = p.clipRegion().boundingRect();
+ const QRect clip = p.clipRegion().isEmpty() ? content : clipf.toRect();
+#elif defined(QFX_RENDER_OPENGL)
+ const QRectF clipf = p.sceneClipRect;
+ const QRect clip = mapFromScene(clipf).toRect();
+#endif
+
+ QRegion topaint(clip);
+ topaint &= content;
+ QRegion uncached(content);
+
+ int cachesize=0;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ QRect area = d->imagecache[i]->area;
+ if (topaint.contains(area)) {
+ p.drawImage(area, d->imagecache[i]->image);
+ topaint -= area;
+ d->imagecache[i]->age=0;
+ } else {
+ d->imagecache[i]->age++;
+ }
+ cachesize += area.width()*area.height();
+ uncached -= area;
+ }
+
+ if (!topaint.isEmpty()) {
+ // Find a sensible larger area, otherwise will paint lots of tiny images.
+ QRect biggerrect = topaint.boundingRect().adjusted(-64,-64,128,128);
+ cachesize += biggerrect.width() * biggerrect.height();
+ while (d->imagecache.count() && cachesize > d->max_imagecache_size) {
+ int oldest=-1;
+ int age=-1;
+ for (int i=0; i<d->imagecache.count(); ++i) {
+ int a = d->imagecache[i]->age;
+ if (a > age) {
+ oldest = i;
+ age = a;
+ }
+ }
+ cachesize -= d->imagecache[oldest]->area.width()*d->imagecache[oldest]->area.height();
+ uncached += d->imagecache[oldest]->area;
+ d->imagecache.removeAt(oldest);
+ }
+ const QRegion bigger = QRegion(biggerrect) & uncached;
+ const QVector<QRect> rects = bigger.rects();
+ foreach (QRect r, rects) {
+ QImage img(r.size(),QImage::Format_ARGB32_Premultiplied);
+ img.fill(0);
+ {
+ QPainter qp(&img);
+ qp.translate(-r.x(),-r.y());
+ frame->render(&qp,r);
+ }
+ QFxWebViewPrivate::ImageCacheItem *newitem = new QFxWebViewPrivate::ImageCacheItem;
+ newitem->area = r;
+#if defined(QFX_RENDER_QPAINTER)
+ newitem->image = QSimpleCanvasConfig::Image(QSimpleCanvasConfig::toImage(img));
+#else
+ newitem->image.setImage(img);
+#endif
+ d->imagecache.append(newitem);
+ p.drawImage(r, newitem->image);
+ }
+ }
+#if defined(QFX_RENDER_QPAINTER)
+ p.setRenderHints(QPainter::Antialiasing, wasAA);
+#endif
+}
+
+QString QFxWebView::propertyInfo() const
+{
+ Q_D(const QFxWebView);
+ return d->page->mainFrame()->url().toString();
+}
+
+static QMouseEvent *sceneMouseEventToMouseEvent(QGraphicsSceneMouseEvent *e)
+{
+ QEvent::Type t;
+ switch(e->type()) {
+ default:
+ case QEvent::GraphicsSceneMousePress:
+ t = QEvent::MouseButtonPress;
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ t = QEvent::MouseButtonRelease;
+ break;
+ case QEvent::GraphicsSceneMouseMove:
+ t = QEvent::MouseMove;
+ break;
+ case QGraphicsSceneEvent::GraphicsSceneMouseDoubleClick:
+ t = QEvent::MouseButtonDblClick;
+ break;
+ }
+
+ QMouseEvent *me = new QMouseEvent(t, e->pos().toPoint(), e->button(), e->buttons(), 0);
+ return me;
+}
+
+
+void QFxWebView::timerEvent(QTimerEvent *event)
+{
+ Q_D(QFxWebView);
+ if (event->timerId() ==d->dcTimer.timerId()) {
+ d->dcTimer.stop();
+ if (d->lastPress) {
+ d->page->event(d->lastPress);
+ delete d->lastPress;
+ d->lastPress = 0;
+ }
+ if (d->lastRelease) {
+ d->page->event(d->lastRelease);
+ delete d->lastRelease;
+ d->lastRelease = 0;
+ }
+ }
+}
+
+int QFxWebView::mouseX() const
+{
+ Q_D(const QFxWebView);
+ if (d->lastPress)
+ return d->lastPress->x();
+ if (d->lastRelease)
+ return d->lastRelease->x();
+ return d->mouseX;
+}
+
+int QFxWebView::mouseY() const
+{
+ Q_D(const QFxWebView);
+ if (d->lastPress)
+ return d->lastPress->y();
+ if (d->lastRelease)
+ return d->lastRelease->y();
+ return d->mouseY;
+}
+
+void QFxWebView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ Q_D(QFxWebView);
+ d->dcTimer.stop();
+ delete d->lastPress;
+ delete d->lastRelease;
+ d->lastPress = 0;
+ d->lastRelease = 0;
+ d->mouseX = me->x();
+ d->mouseY = me->y();
+ emit doubleClick();
+ d->mouseX = 0;
+ d->mouseY = 0;
+ delete me;
+}
+
+void QFxWebView::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxWebView);
+ if (d->interactive) {
+ d->lastPress = sceneMouseEventToMouseEvent(event);
+ event->setAccepted(true);
+ } else {
+ event->setAccepted(false);
+ }
+ if (!event->isAccepted())
+ QFxItem::mousePressEvent(event);
+}
+
+void QFxWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxWebView);
+ if (d->interactive) {
+ d->lastRelease = sceneMouseEventToMouseEvent(event);
+ d->dcTimer.start(MAX_DOUBLECLICK_TIME,this);
+ event->setAccepted(true);
+ } else {
+ event->setAccepted(false);
+ }
+ if (!event->isAccepted())
+ QFxItem::mouseReleaseEvent(event);
+}
+
+void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive && !d->dcTimer.isActive()) {
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ d->page->event(me);
+ event->setAccepted(
+#if QT_VERSION <= 0x040500 // XXX see bug 230835
+ true
+#else
+ me->isAccepted()
+#endif
+ );
+ delete me;
+ } else {
+ event->setAccepted(false);
+ }
+ if (!event->isAccepted())
+ QFxItem::mouseMoveEvent(event);
+}
+
+void QFxWebView::keyPressEvent(QKeyEvent* event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive)
+ d->page->event(event);
+ if (!event->isAccepted())
+ QFxItem::keyPressEvent(event);
+}
+
+void QFxWebView::keyReleaseEvent(QKeyEvent* event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive)
+ d->page->event(event);
+ if (!event->isAccepted())
+ QFxItem::keyReleaseEvent(event);
+}
+
+/*!
+ \qmlproperty action WebView::back
+ This property holds the action for causing the previous URL in the history to be displayed.
+*/
+QAction *QFxWebView::backAction() const
+{
+ Q_D(const QFxWebView);
+ return d->page->action(QWebPage::Back);
+}
+
+/*!
+ \qmlproperty action WebView::forward
+ This property holds the action for causing the next URL in the history to be displayed.
+*/
+QAction *QFxWebView::forwardAction() const
+{
+ Q_D(const QFxWebView);
+ return d->page->action(QWebPage::Forward);
+}
+
+/*!
+ \qmlproperty action WebView::reload
+ This property holds the action for reloading with the current URL
+*/
+QAction *QFxWebView::reloadAction() const
+{
+ Q_D(const QFxWebView);
+ return d->page->action(QWebPage::Reload);
+}
+
+/*!
+ \qmlproperty action WebView::stop
+ This property holds the action for stopping loading with the current URL
+*/
+QAction *QFxWebView::stopAction() const
+{
+ Q_D(const QFxWebView);
+ return d->page->action(QWebPage::Stop);
+}
+
+/*!
+ \qmlproperty real WebView::title
+ This property holds the title of the web page currently viewed
+
+ By default, this property contains an empty string.
+*/
+/*!
+ \property QFxWebView::title
+ This property holds the title of the web page currently viewed
+
+ By default, this property contains an empty string.
+
+ \sa titleChanged()
+*/
+QString QFxWebView::title() const
+{
+ Q_D(const QFxWebView);
+ if (d->page)
+ return d->page->mainFrame()->title();
+ return QString();
+}
+
+
+
+/*!
+ \qmlproperty pixmap WebView::icon
+ This property holds the icon associated with the web page currently viewed
+*/
+/*!
+ \property QFxWebView::icon
+ \brief the icon associated with the web page currently viewed
+
+ By default, this property contains a null icon.
+
+ \sa iconChanged(), QWebSettings::iconForUrl()
+*/
+QPixmap QFxWebView::icon() const
+{
+ Q_D(const QFxWebView);
+ if (d->page)
+ return d->page->mainFrame()->icon().pixmap(QSize(256,256));
+ return QPixmap();
+}
+
+
+/*!
+ \qmlproperty real WebView::textSizeMultiplier
+ This property holds multiplier used to scale the text in a Web page
+*/
+/*!
+ Sets the value of the multiplier used to scale the text in a Web page to
+ the \a factor specified.
+*/
+void QFxWebView::setTextSizeMultiplier(qreal factor)
+{
+ Q_D(QFxWebView);
+ d->page->mainFrame()->setTextSizeMultiplier(factor);
+}
+
+/*!
+ Returns the value of the multiplier used to scale the text in a Web page.
+*/
+qreal QFxWebView::textSizeMultiplier() const
+{
+ Q_D(const QFxWebView);
+ return d->page->mainFrame()->textSizeMultiplier();
+}
+
+void QFxWebView::setStatusBarMessage(const QString& s)
+{
+ Q_D(QFxWebView);
+ d->statusBarMessage = s;
+ emit statusChanged();
+}
+
+QString QFxWebView::status() const
+{
+ Q_D(const QFxWebView);
+ return d->statusBarMessage;
+}
+
+QWebPage *QFxWebView::page() const
+{
+ Q_D(const QFxWebView);
+ return d->page;
+}
+
+void QFxWebView::setPage(QWebPage *page)
+{
+ Q_D(QFxWebView);
+ if (d->page == page)
+ return;
+ if (d->page) {
+ if (d->page->parent() == this) {
+ delete d->page;
+ } else {
+ d->page->disconnect(this);
+ }
+ }
+ d->page = page;
+ d->page->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : -1,
+ d->idealheight>0 ? d->idealheight : -1));
+ d->page->mainFrame()->setScrollBarPolicy(Qt::Horizontal,Qt::ScrollBarAlwaysOff);
+ d->page->mainFrame()->setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff);
+ connect(this,SIGNAL(visibleChanged()),this,SLOT(updateCacheForVisibility()));
+ connect(d->page,SIGNAL(repaintRequested(QRect)),this,SLOT(paintPage(QRect)));
+ connect(d->page->mainFrame(),SIGNAL(urlChanged(QUrl)),this,SIGNAL(urlChanged()));
+ connect(d->page->mainFrame(), SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
+ connect(d->page->mainFrame(), SIGNAL(iconChanged()), this, SIGNAL(iconChanged()));
+
+ connect(d->page,SIGNAL(loadStarted()),this,SIGNAL(loadStarted()));
+ connect(d->page,SIGNAL(loadProgress(int)),this,SLOT(doLoadProgress(int)));
+ connect(d->page,SIGNAL(loadFinished(bool)),this,SLOT(doLoadFinished(bool)));
+ connect(d->page,SIGNAL(statusBarMessage(QString)),this,SLOT(setStatusBarMessage(QString)));
+}
+
+void QFxWebView::load(const QNetworkRequest &request,
+ QNetworkAccessManager::Operation operation,
+ const QByteArray &body)
+{
+ page()->mainFrame()->load(request, operation, body);
+}
+
+QString QFxWebView::html() const
+{
+ return page()->mainFrame()->toHtml();
+}
+
+/*!
+ \qmlproperty string WebView::html
+ This property holds HTML text set directly
+
+ The html property can be set as a string (using CDATA for large blocks),
+ or as xhtml inline using the XML namespace http://www.w3.org/1999/xhtml:
+
+ \code
+ <WebView>
+ <html xmlns="http://www.w3.org/1999/xhtml">
+ <p>This is valid xHTML.</p>
+ </html>
+ </WebView>
+ \endcode
+
+ \code
+ <WebView>
+ <html>&lt;CDATA[
+ <p>This is just HTML.
+ ]]&gt;html>
+ </WebView>
+ \endcode
+*/
+void QFxWebView::setHtml(const QString &html, const QUrl &baseUrl)
+{
+ Q_D(QFxWebView);
+ d->page->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+ if (isComponentComplete())
+ d->page->mainFrame()->setHtml(html, baseUrl);
+ else {
+ d->pending = d->PendingHtml;
+ d->pending_url = baseUrl;
+ d->pending_string = html;
+ }
+}
+
+void QFxWebView::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
+{
+ Q_D(QFxWebView);
+ d->page->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+
+ if (isComponentComplete())
+ d->page->mainFrame()->setContent(data,mimeType,baseUrl);
+ else {
+ d->pending = d->PendingContent;
+ d->pending_url = baseUrl;
+ d->pending_string = mimeType;
+ d->pending_data = data;
+ }
+}
+
+QWebHistory *QFxWebView::history() const
+{
+ return page()->history();
+}
+
+QWebSettings *QFxWebView::settings() const
+{
+ return page()->settings();
+}
+
+/*!
+ \internal
+ \class QFxWebPage
+ \brief The QFxWebPage class is a QWebPage that can create QML plugins.
+
+ \sa QFxWebView
+*/
+QFxWebPage::QFxWebPage(QFxWebView *parent) :
+ QWebPage(parent)
+{
+}
+
+QFxWebPage::~QFxWebPage()
+{
+}
+
+/*
+ Qt WebKit does not understand non-QWidget plugins, so dummy widgets
+ are created, parented to a single dummy tool window.
+
+ The requirements for QML object plugins are input to the Qt WebKit
+ non-QWidget plugin support, which will obsolete this kludge.
+*/
+class QWidget_Dummy_Plugin : public QWidget
+{
+ Q_OBJECT
+public:
+ static QWidget *dummy_shared_parent()
+ {
+ static QWidget *dsp = 0;
+ if (!dsp) {
+ dsp = new QWidget(0,Qt::Tool);
+ dsp->setGeometry(-10000,-10000,0,0);
+ dsp->show();
+ }
+ return dsp;
+ }
+ QWidget_Dummy_Plugin(const QUrl& url, QFxWebView *view, const QStringList &paramNames, const QStringList &paramValues) :
+ QWidget(dummy_shared_parent()),
+ propertyNames(paramNames),
+ propertyValues(paramValues),
+ webview(view)
+ {
+ QmlEngine *engine = webview->itemContext()->engine();
+ component = new QmlComponent(engine, url, this);
+ item = 0;
+ connect(engine, SIGNAL(readyChanged()), this, SLOT(qmlLoaded()));
+ }
+
+public Q_SLOTS:
+ void qmlLoaded()
+ {
+ item = qobject_cast<QFxItem*>(component->create(webview->itemContext()));
+ item->setParent(webview);
+ for (int i=0; i<propertyNames.count(); ++i) {
+ if (propertyNames[i] != QLatin1String("type") && propertyNames[i] != QLatin1String("data")) {
+ item->setProperty(propertyNames[i].toLatin1(),propertyValues[i]);
+ }
+ }
+ resizeEvent(0);
+ delete component;
+ component = 0;
+ }
+ void resizeEvent(QResizeEvent*)
+ {
+ if (item) {
+ item->setX(x());
+ item->setY(y());
+ item->setWidth(width());
+ item->setHeight(height());
+ }
+ }
+
+private:
+ QmlComponent *component;
+ QFxItem *item;
+ QStringList propertyNames, propertyValues;
+ QFxWebView *webview;
+};
+
+QFxWebView *QFxWebPage::view()
+{
+ return static_cast<QFxWebView*>(parent());
+}
+
+QObject *QFxWebPage::createPlugin(const QString &, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues)
+{
+ QUrl comp = view()->itemContext()->resolvedUri(url.toString());
+ return new QWidget_Dummy_Plugin(comp,view(),paramNames,paramValues);
+}
+
+#include "qfxwebview.moc"
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h
new file mode 100644
index 0000000..463d0c4
--- /dev/null
+++ b/src/declarative/fx/qfxwebview.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXWEBVIEW_H
+#define QFXWEBVIEW_H
+
+#include <QAction>
+#include <QUrl>
+#include <qfxglobal.h>
+#include <qfxitem.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QWebPage>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QWebHistory;
+class QWebSettings;
+class QFxWebViewPrivate;
+class QNetworkRequest;
+class QFxWebView;
+
+class Q_DECLARATIVE_EXPORT QFxWebPage : public QWebPage
+{
+ Q_OBJECT
+public:
+ explicit QFxWebPage(QFxWebView *parent);
+ ~QFxWebPage();
+protected:
+ QObject *createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues);
+private:
+ QFxWebView *view();
+};
+
+
+class Q_DECLARATIVE_EXPORT QFxWebView : public QFxItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QString title READ title NOTIFY titleChanged)
+ Q_PROPERTY(QPixmap icon READ icon NOTIFY iconChanged)
+ Q_PROPERTY(qreal textSizeMultiplier READ textSizeMultiplier WRITE setTextSizeMultiplier DESIGNABLE false)
+ Q_PROPERTY(QString status READ status NOTIFY statusChanged)
+
+ Q_PROPERTY(int mouseX READ mouseX)
+ Q_PROPERTY(int mouseY READ mouseY)
+
+ Q_PROPERTY(QString html READ html WRITE setHtml)
+
+ Q_PROPERTY(int idealWidth READ idealWidth WRITE setIdealWidth NOTIFY idealWidthChanged)
+ Q_PROPERTY(int idealHeight READ idealHeight WRITE setIdealHeight NOTIFY idealHeightChanged)
+ Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
+ Q_PROPERTY(bool smooth READ smooth WRITE setSmooth)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged())
+ Q_PROPERTY(bool interactive READ interactive WRITE setInteractive NOTIFY interactiveChanged)
+ Q_PROPERTY(int cacheSize READ cacheSize WRITE setCacheSize)
+
+ Q_PROPERTY(QObject* reload READ reloadAction)
+ Q_PROPERTY(QObject* back READ backAction)
+ Q_PROPERTY(QObject* forward READ forwardAction)
+ Q_PROPERTY(QObject* stop READ stopAction)
+
+public:
+ QFxWebView(QFxItem *parent=0);
+ ~QFxWebView();
+
+ QString url() const;
+ void setUrl(const QString &);
+
+ QString title() const;
+
+ QPixmap icon() const;
+
+ qreal textSizeMultiplier() const;
+ void setTextSizeMultiplier(qreal);
+
+ bool interactive() const;
+ void setInteractive(bool);
+
+ int cacheSize() const;
+ void setCacheSize(int pixels);
+
+ int mouseX() const;
+ int mouseY() const;
+
+ bool smooth() const;
+ void setSmooth(bool);
+
+ int idealWidth() const;
+ void setIdealWidth(int);
+ int idealHeight() const;
+ void setIdealHeight(int);
+
+
+ qreal progress() const;
+
+ QAction *reloadAction() const;
+ QAction *backAction() const;
+ QAction *forwardAction() const;
+ QAction *stopAction() const;
+
+ virtual void dump(int depth);
+ virtual QString propertyInfo() const;
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &painter);
+#elif defined(QFX_RENDER_OPENGL)
+ void paintGLContents(GLPainter &);
+#endif
+
+ QWebPage *page() const;
+ void setPage(QWebPage *page);
+
+ void load(const QNetworkRequest &request,
+ QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
+ const QByteArray &body = QByteArray());
+
+ QString html() const;
+
+ void setHtml(const QString &html, const QUrl &baseUrl = QUrl());
+ void setContent(const QByteArray &data, const QString &mimeType = QString(), const QUrl &baseUrl = QUrl());
+
+ QWebHistory *history() const;
+ QWebSettings *settings() const;
+
+ QString status() const;
+
+Q_SIGNALS:
+ void idealWidthChanged();
+ void idealHeightChanged();
+ void urlChanged();
+ void interactiveChanged();
+ void progressChanged();
+ void titleChanged(const QString&);
+ void iconChanged();
+ void statusChanged();
+
+ void loadStarted();
+ void loadFinished();
+ void loadFailed();
+
+ void singleClick();
+ void doubleClick();
+
+private Q_SLOTS:
+ void updateCacheForVisibility();
+ void expandToWebPage();
+ void paintPage(const QRect&);
+ void doLoadProgress(int p);
+ void doLoadFinished(bool ok);
+ void setStatusBarMessage(const QString&);
+
+protected:
+ QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent* event);
+ void keyReleaseEvent(QKeyEvent* event);
+ void timerEvent(QTimerEvent *event);
+ virtual void geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry);
+
+private:
+ void init();
+ virtual void componentComplete();
+ Q_DISABLE_COPY(QFxWebView)
+ Q_DECLARE_PRIVATE(QFxWebView)
+};
+QML_DECLARE_TYPE(QFxWebView);
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxwidgetcontainer.cpp b/src/declarative/fx/qfxwidgetcontainer.cpp
new file mode 100644
index 0000000..44ccf0f
--- /dev/null
+++ b/src/declarative/fx/qfxwidgetcontainer.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfxwidgetcontainer.h"
+#include <qsimplecanvas.h>
+#include <qgraphicswidget.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlclass WidgetContainer QFxWidgetContainer
+ \brief The WidgetContainer element allows you to add QGraphicsWidgets into Fluid UI elements.
+*/
+
+/*!
+ \internal
+ \class QFxWidgetContainer
+ \brief The QFxWidgetContainer class allows you to add QGraphicsWidgets into Fluid UI applications.
+*/
+
+QML_DEFINE_TYPE(QFxWidgetContainer, WidgetContainer);
+
+QFxWidgetContainer::QFxWidgetContainer(QFxItem *parent)
+: QFxItem(parent), _graphicsWidget(0)
+{
+}
+
+QFxWidgetContainer::~QFxWidgetContainer()
+{
+}
+
+QGraphicsWidget *QFxWidgetContainer::graphicsWidget() const
+{
+ return _graphicsWidget;
+}
+
+/*!
+ \property QGraphicsWidget QFxWidgetContainer::graphicsWidget
+ The QGraphicsWidget associated with this element.
+*/
+void QFxWidgetContainer::setGraphicsWidget(QGraphicsWidget *widget)
+{
+ if(widget == _graphicsWidget)
+ return;
+
+ _graphicsWidget = widget;
+
+ QSimpleCanvas *c = canvas();
+ if(!c)
+ return;
+
+ if(c->canvasMode() != QSimpleCanvas::GraphicsView) {
+ qWarning("QFxWidgetContainer: Cannot add a widget to a non-graphicsview canvas. You might need to set QFX_USE_GRAPHICSVIEW=1");
+ return;
+ }
+
+ QGraphicsItem *item = (QGraphicsItem *)(*this);
+ _graphicsWidget->setParentItem(item);
+}
+
+void QFxWidgetContainer::canvasChanged()
+{
+ if(_graphicsWidget) {
+ QGraphicsWidget *w = _graphicsWidget;
+ _graphicsWidget = 0;
+ setGraphicsWidget(w);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxwidgetcontainer.h b/src/declarative/fx/qfxwidgetcontainer.h
new file mode 100644
index 0000000..65e4352
--- /dev/null
+++ b/src/declarative/fx/qfxwidgetcontainer.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFXWIDGETCONTAINER_H
+#define QFXWIDGETCONTAINER_H
+
+#include <QtDeclarative/qfxitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsWidget;
+
+class Q_DECLARATIVE_EXPORT QFxWidgetContainer : public QFxItem
+{
+ Q_OBJECT
+
+ Q_CLASSINFO("DefaultProperty", "graphicsWidget")
+ Q_PROPERTY(QGraphicsWidget *graphicsWidget READ graphicsWidget WRITE setGraphicsWidget)
+
+public:
+ QFxWidgetContainer(QFxItem *parent = 0);
+ ~QFxWidgetContainer();
+
+ QGraphicsWidget *graphicsWidget() const;
+ void setGraphicsWidget(QGraphicsWidget *);
+
+protected:
+ virtual void canvasChanged();
+
+private:
+ QGraphicsWidget *_graphicsWidget;
+};
+QML_DECLARE_TYPE(QFxWidgetContainer);
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXGRAPHICSWIDGET_H