summaryrefslogtreecommitdiffstats
path: root/src/declarative/fx
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/fx')
-rw-r--r--src/declarative/fx/fx.pri95
-rw-r--r--src/declarative/fx/qfxanchors.cpp889
-rw-r--r--src/declarative/fx/qfxanchors.h197
-rw-r--r--src/declarative/fx/qfxanchors_p.h132
-rw-r--r--src/declarative/fx/qfxanimatedimageitem.cpp213
-rw-r--r--src/declarative/fx/qfxanimatedimageitem.h100
-rw-r--r--src/declarative/fx/qfxanimatedimageitem_p.h77
-rw-r--r--src/declarative/fx/qfxblendedimage.cpp297
-rw-r--r--src/declarative/fx/qfxblendedimage.h111
-rw-r--r--src/declarative/fx/qfxblurfilter.cpp467
-rw-r--r--src/declarative/fx/qfxblurfilter.h82
-rw-r--r--src/declarative/fx/qfxcomponentinstance.cpp152
-rw-r--r--src/declarative/fx/qfxcomponentinstance.h89
-rw-r--r--src/declarative/fx/qfxcomponentinstance_p.h76
-rw-r--r--src/declarative/fx/qfxcontentwrapper.cpp144
-rw-r--r--src/declarative/fx/qfxcontentwrapper.h90
-rw-r--r--src/declarative/fx/qfxcontentwrapper_p.h71
-rw-r--r--src/declarative/fx/qfxevents.cpp182
-rw-r--r--src/declarative/fx/qfxevents_p.h127
-rw-r--r--src/declarative/fx/qfxflickable.cpp1153
-rw-r--r--src/declarative/fx/qfxflickable.h195
-rw-r--r--src/declarative/fx/qfxflickable_p.h170
-rw-r--r--src/declarative/fx/qfxflipable.cpp348
-rw-r--r--src/declarative/fx/qfxflipable.h106
-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.cpp1428
-rw-r--r--src/declarative/fx/qfxgridview.h148
-rw-r--r--src/declarative/fx/qfxhighlightfilter.cpp319
-rw-r--r--src/declarative/fx/qfxhighlightfilter.h98
-rw-r--r--src/declarative/fx/qfximage.cpp1015
-rw-r--r--src/declarative/fx/qfximage.h129
-rw-r--r--src/declarative/fx/qfximage_p.h119
-rw-r--r--src/declarative/fx/qfxitem.cpp2100
-rw-r--r--src/declarative/fx/qfxitem.h277
-rw-r--r--src/declarative/fx/qfxitem_p.h179
-rw-r--r--src/declarative/fx/qfxkeyactions.cpp920
-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.cpp1082
-rw-r--r--src/declarative/fx/qfxlayouts.h171
-rw-r--r--src/declarative/fx/qfxlayouts_p.h100
-rw-r--r--src/declarative/fx/qfxlistview.cpp1649
-rw-r--r--src/declarative/fx/qfxlistview.h154
-rw-r--r--src/declarative/fx/qfxmouseregion.cpp580
-rw-r--r--src/declarative/fx/qfxmouseregion.h163
-rw-r--r--src/declarative/fx/qfxmouseregion_p.h110
-rw-r--r--src/declarative/fx/qfxpainteditem.cpp340
-rw-r--r--src/declarative/fx/qfxpainteditem.h97
-rw-r--r--src/declarative/fx/qfxpainteditem_p.h95
-rw-r--r--src/declarative/fx/qfxparticles.cpp1200
-rw-r--r--src/declarative/fx/qfxparticles.h240
-rw-r--r--src/declarative/fx/qfxpath.cpp868
-rw-r--r--src/declarative/fx/qfxpath.h257
-rw-r--r--src/declarative/fx/qfxpath_p.h79
-rw-r--r--src/declarative/fx/qfxpathview.cpp890
-rw-r--r--src/declarative/fx/qfxpathview.h136
-rw-r--r--src/declarative/fx/qfxpathview_p.h151
-rw-r--r--src/declarative/fx/qfxpixmap.cpp233
-rw-r--r--src/declarative/fx/qfxpixmap.h87
-rw-r--r--src/declarative/fx/qfxrect.cpp1005
-rw-r--r--src/declarative/fx/qfxrect.h193
-rw-r--r--src/declarative/fx/qfxrect_p.h109
-rw-r--r--src/declarative/fx/qfxreflectionfilter.cpp352
-rw-r--r--src/declarative/fx/qfxreflectionfilter.h96
-rw-r--r--src/declarative/fx/qfxrepeater.cpp356
-rw-r--r--src/declarative/fx/qfxrepeater.h89
-rw-r--r--src/declarative/fx/qfxrepeater_p.h81
-rw-r--r--src/declarative/fx/qfxscalegrid.cpp216
-rw-r--r--src/declarative/fx/qfxscalegrid.h119
-rw-r--r--src/declarative/fx/qfxshadowfilter.cpp214
-rw-r--r--src/declarative/fx/qfxshadowfilter.h86
-rw-r--r--src/declarative/fx/qfxtext.cpp950
-rw-r--r--src/declarative/fx/qfxtext.h153
-rw-r--r--src/declarative/fx/qfxtext_p.h137
-rw-r--r--src/declarative/fx/qfxtextedit.cpp938
-rw-r--r--src/declarative/fx/qfxtextedit.h211
-rw-r--r--src/declarative/fx/qfxtextedit_p.h109
-rw-r--r--src/declarative/fx/qfxtransform.cpp895
-rw-r--r--src/declarative/fx/qfxtransform.h319
-rw-r--r--src/declarative/fx/qfxvisualitemmodel.cpp771
-rw-r--r--src/declarative/fx/qfxvisualitemmodel.h132
-rw-r--r--src/declarative/fx/qfxwebview.cpp1076
-rw-r--r--src/declarative/fx/qfxwebview.h216
-rw-r--r--src/declarative/fx/qfxwidgetcontainer.cpp108
-rw-r--r--src/declarative/fx/qfxwidgetcontainer.h81
89 files changed, 30826 insertions, 0 deletions
diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri
new file mode 100644
index 0000000..90820fa
--- /dev/null
+++ b/src/declarative/fx/fx.pri
@@ -0,0 +1,95 @@
+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/qfxevents_p.h \
+ fx/qfxflickable.h \
+ fx/qfxflickable_p.h \
+ fx/qfxflipable.h \
+ fx/qfxfocuspanel.h \
+ fx/qfxfocusrealm.h \
+ fx/qfxgridview.h \
+ fx/qfxhighlightfilter.h \
+ fx/qfximage.h \
+ fx/qfxpainteditem.h \
+ fx/qfxpainteditem_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/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/qfxevents.cpp \
+ fx/qfxflickable.cpp \
+ fx/qfxflipable.cpp \
+ fx/qfxfocuspanel.cpp \
+ fx/qfxfocusrealm.cpp \
+ fx/qfxgridview.cpp \
+ fx/qfxhighlightfilter.cpp \
+ fx/qfximage.cpp \
+ fx/qfxpainteditem.cpp \
+ fx/qfxitem.cpp \
+ fx/qfxkeyactions.cpp \
+ fx/qfxkeyproxy.cpp \
+ fx/qfxlayouts.cpp \
+ fx/qfxmouseregion.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..bd5520a
--- /dev/null
+++ b/src/declarative/fx/qfxanchors.cpp
@@ -0,0 +1,889 @@
+/****************************************************************************
+**
+** 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 "qfxitem_p.h"
+#include <QDebug>
+#include <QtDeclarative/qmlinfo.h>
+#include <QtDeclarative/qmlbindablevalue.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 group_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)
+{
+}
+
+QFxAnchors::~QFxAnchors()
+{
+ Q_D(QFxAnchors);
+ d->remDepend(d->fill);
+ d->remDepend(d->centeredIn);
+ d->remDepend(d->left.item);
+ d->remDepend(d->right.item);
+ d->remDepend(d->top.item);
+ d->remDepend(d->bottom.item);
+ d->remDepend(d->vCenter.item);
+ d->remDepend(d->hCenter.item);
+ d->remDepend(d->baseline.item);
+}
+
+void QFxAnchorsPrivate::fillChanged()
+{
+ if (!fill || !isItemComplete())
+ return;
+
+ if (fill == item->itemParent()) { //child-parent
+ setItemPos(QPointF(leftMargin, topMargin));
+ } else if (fill->itemParent() == item->itemParent()) { //siblings
+ setItemPos(QPointF(fill->x()+leftMargin, fill->y()+topMargin));
+ }
+ setItemWidth(fill->width()-leftMargin-rightMargin);
+ setItemHeight(fill->height()-topMargin-bottomMargin);
+}
+
+void QFxAnchorsPrivate::centeredInChanged()
+{
+ if (!centeredIn || fill || !isItemComplete())
+ return;
+
+ if (centeredIn == item->itemParent()) {
+ QPointF p((item->itemParent()->width() - item->width()) / 2.,
+ (item->itemParent()->height() - item->height()) / 2.);
+ setItemPos(p);
+
+ } else if (centeredIn->itemParent() == item->itemParent()) {
+
+ QPointF p(centeredIn->x() + (centeredIn->width() - item->width()) / 2.,
+ centeredIn->y() + (centeredIn->height() - item->height()) / 2.);
+ setItemPos(p);
+ }
+}
+
+void QFxAnchorsPrivate::clearItem(QFxItem *item)
+{
+ if (fill == item)
+ fill = 0;
+ if (centeredIn == item)
+ centeredIn = 0;
+ if (left.item == item) {
+ left.item = 0;
+ usedAnchors &= ~QFxAnchors::HasLeftAnchor;
+ }
+ if (right.item == item) {
+ right.item = 0;
+ usedAnchors &= ~QFxAnchors::HasRightAnchor;
+ }
+ if (top.item == item) {
+ top.item = 0;
+ usedAnchors &= ~QFxAnchors::HasTopAnchor;
+ }
+ if (bottom.item == item) {
+ bottom.item = 0;
+ usedAnchors &= ~QFxAnchors::HasBottomAnchor;
+ }
+ if (vCenter.item == item) {
+ vCenter.item = 0;
+ usedAnchors &= ~QFxAnchors::HasVCenterAnchor;
+ }
+ if (hCenter.item == item) {
+ hCenter.item = 0;
+ usedAnchors &= ~QFxAnchors::HasHCenterAnchor;
+ }
+ if (baseline.item == item) {
+ baseline.item = 0;
+ usedAnchors &= ~QFxAnchors::HasBaselineAnchor;
+ }
+}
+
+void QFxAnchorsPrivate::addDepend(QFxItem *item)
+{
+ Q_Q(QFxAnchors);
+ if (!item)
+ return;
+ QFxItemPrivate *p =
+ static_cast<QFxItemPrivate *>(QObjectPrivate::get(item));
+ p->dependantAnchors.append(q);
+}
+
+void QFxAnchorsPrivate::remDepend(QFxItem *item)
+{
+ Q_Q(QFxAnchors);
+ if (!item)
+ return;
+ QFxItemPrivate *p =
+ static_cast<QFxItemPrivate *>(QObjectPrivate::get(item));
+ p->dependantAnchors.removeAll(q);
+}
+
+bool QFxAnchorsPrivate::isItemComplete() const
+{
+ return item->isComponentComplete();
+}
+
+void QFxAnchorsPrivate::setItemHeight(qreal v)
+{
+ updatingMe = true;
+ item->setHeight(v);
+ updatingMe = false;
+}
+
+void QFxAnchorsPrivate::setItemWidth(qreal v)
+{
+ updatingMe = true;
+ item->setWidth(v);
+ updatingMe = false;
+}
+
+void QFxAnchorsPrivate::setItemX(qreal v)
+{
+ updatingMe = true;
+ item->setX(v);
+ updatingMe = false;
+}
+
+void QFxAnchorsPrivate::setItemY(qreal v)
+{
+ updatingMe = true;
+ item->setY(v);
+ updatingMe = false;
+}
+
+void QFxAnchorsPrivate::setItemPos(const QPointF &v)
+{
+ updatingMe = true;
+ item->setPos(v);
+ updatingMe = false;
+}
+
+void QFxAnchorsPrivate::updateMe()
+{
+ if (updatingMe) {
+ updatingMe = false;
+ return;
+ }
+
+ fillChanged();
+ centeredInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QFxAnchorsPrivate::updateOnComplete()
+{
+ fillChanged();
+ centeredInChanged();
+ updateHorizontalAnchors();
+ updateVerticalAnchors();
+}
+
+void QFxAnchorsPrivate::update(QFxItem *, const QRectF &newG, const QRectF &oldG)
+{
+ fillChanged();
+ centeredInChanged();
+
+ if (newG.x() != oldG.x() || newG.width() != oldG.width())
+ updateHorizontalAnchors();
+ if (newG.y() != oldG.y() || newG.height() != oldG.height())
+ updateVerticalAnchors();
+}
+
+/*!
+ \property QFxAnchors::fill
+ \brief which 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);
+ d->remDepend(d->fill);
+ d->fill = f;
+ d->addDepend(d->fill);
+
+ d->fillChanged();
+}
+
+/*!
+ \property QFxAnchors::centeredIn
+ \brief which item the item should stay centered in.
+
+ 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->remDepend(d->centeredIn);
+ d->centeredIn = c;
+ d->addDepend(d->centeredIn);
+
+ d->centeredInChanged();
+}
+
+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 QFxAnchorsPrivate::updateVerticalAnchors()
+{
+ if (fill || centeredIn || !isItemComplete())
+ return;
+
+ if (!updatingVerticalAnchor) {
+ updatingVerticalAnchor = true;
+ if (usedAnchors & QFxAnchors::HasTopAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ int height = 0;
+ if (usedAnchors & QFxAnchors::HasBottomAnchor) {
+ invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QFxAnchorLine::Top, height);
+ } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) {
+ invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QFxAnchorLine::Top, height);
+ height *= 2;
+ }
+ if (!invalid)
+ setItemHeight(height);
+
+ //Handle top
+ if (top.item == item->itemParent()) {
+ setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin);
+ } else if (top.item->itemParent() == item->itemParent()) {
+ setItemY(position(top.item, top.anchorLine) + topMargin);
+ }
+ } else if (usedAnchors & QFxAnchors::HasBottomAnchor) {
+ //Handle stretching (top + bottom case is handled above)
+ if (usedAnchors & QFxAnchors::HasVCenterAnchor) {
+ int height = 0;
+ bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
+ QFxAnchorLine::Top, height);
+ if (!invalid)
+ setItemHeight(height*2);
+ }
+
+ //Handle bottom
+ if (bottom.item == item->itemParent()) {
+ setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ } else if (bottom.item->itemParent() == item->itemParent()) {
+ setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
+ }
+ } else if (usedAnchors & QFxAnchors::HasVCenterAnchor) {
+ //(stetching handled above)
+
+ //Handle vCenter
+ if (vCenter.item == item->itemParent()) {
+ setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine)
+ - item->height()/2 + vCenterOffset);
+ } else if (vCenter.item->itemParent() == item->itemParent()) {
+ setItemY(position(vCenter.item, vCenter.anchorLine) - item->height()/2 + vCenterOffset);
+ }
+ } else if (usedAnchors & QFxAnchors::HasBaselineAnchor) {
+ //Handle baseline
+ if (baseline.item->itemParent() == item->itemParent()) {
+ setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset());
+ }
+ }
+ updatingVerticalAnchor = false;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << "Possible anchor loop detected on vertical anchor.";
+ }
+}
+
+void QFxAnchorsPrivate::updateHorizontalAnchors()
+{
+ if (fill || centeredIn || !isItemComplete())
+ return;
+
+ if (!updatingHorizontalAnchor) {
+ updatingHorizontalAnchor = true;
+
+ if (usedAnchors & QFxAnchors::HasLeftAnchor) {
+ //Handle stretching
+ bool invalid = true;
+ int width = 0;
+ if (usedAnchors & QFxAnchors::HasRightAnchor) {
+ invalid = calcStretch(left, right, leftMargin, -rightMargin, QFxAnchorLine::Left, width);
+ } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) {
+ invalid = calcStretch(left, hCenter, leftMargin, hCenterOffset, QFxAnchorLine::Left, width);
+ width *= 2;
+ }
+ if (!invalid)
+ setItemWidth(width);
+
+ //Handle left
+ if (left.item == item->itemParent()) {
+ setItemX(adjustedPosition(left.item, left.anchorLine) + leftMargin);
+ } else if (left.item->itemParent() == item->itemParent()) {
+ setItemX(position(left.item, left.anchorLine) + leftMargin);
+ }
+ } else if (usedAnchors & QFxAnchors::HasRightAnchor) {
+ //Handle stretching (left + right case is handled in updateLeftAnchor)
+ if (usedAnchors & QFxAnchors::HasHCenterAnchor) {
+ int width = 0;
+ bool invalid = calcStretch(hCenter, right, hCenterOffset, -rightMargin,
+ QFxAnchorLine::Left, width);
+ if (!invalid)
+ setItemWidth(width*2);
+ }
+
+ //Handle right
+ if (right.item == item->itemParent()) {
+ setItemX(adjustedPosition(right.item, right.anchorLine) - item->width() - rightMargin);
+ } else if (right.item->itemParent() == item->itemParent()) {
+ setItemX(position(right.item, right.anchorLine) - item->width() - rightMargin);
+ }
+ } else if (usedAnchors & QFxAnchors::HasHCenterAnchor) {
+ //Handle hCenter
+ if (hCenter.item == item->itemParent()) {
+ setItemX(adjustedPosition(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset);
+ } else if (hCenter.item->itemParent() == item->itemParent()) {
+ setItemX(position(hCenter.item, hCenter.anchorLine) - item->width()/2 + hCenterOffset);
+ }
+ }
+
+ updatingHorizontalAnchor = false;
+ } else {
+ // ### Make this certain :)
+ qmlInfo(item) << "Possible anchor loop detected on horizontal anchor.";
+ }
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasTopAnchor;
+ else
+ d->usedAnchors &= ~HasTopAnchor;
+
+ d->checkVValid();
+
+ d->remDepend(d->top.item);
+ d->top = edge;
+ d->addDepend(d->top.item);
+ d->updateVerticalAnchors();
+}
+
+void QFxAnchors::resetTop()
+{
+ setTop(QFxAnchorLine());
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasBottomAnchor;
+ else
+ d->usedAnchors &= ~HasBottomAnchor;
+
+ d->checkVValid();
+
+ d->remDepend(d->bottom.item);
+ d->bottom = edge;
+ d->addDepend(d->bottom.item);
+ d->updateVerticalAnchors();
+}
+
+void QFxAnchors::resetBottom()
+{
+ setBottom(QFxAnchorLine());
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasVCenterAnchor;
+ else
+ d->usedAnchors &= ~HasVCenterAnchor;
+
+ d->checkVValid();
+
+ d->remDepend(d->vCenter.item);
+ d->vCenter = edge;
+ d->addDepend(d->vCenter.item);
+ d->updateVerticalAnchors();
+}
+
+void QFxAnchors::resetVerticalCenter()
+{
+ setVerticalCenter(QFxAnchorLine());
+}
+
+QFxAnchorLine QFxAnchors::baseline() const
+{
+ Q_D(const QFxAnchors);
+ return d->baseline;
+}
+
+void QFxAnchors::setBaseline(const QFxAnchorLine &edge)
+{
+ Q_D(QFxAnchors);
+ if (!d->checkVAnchorValid(edge))
+ return;
+
+ if (edge.item)
+ d->usedAnchors |= HasBaselineAnchor;
+ else
+ d->usedAnchors &= ~HasBaselineAnchor;
+
+ d->checkVValid();
+
+ d->remDepend(d->baseline.item);
+ d->baseline = edge;
+ d->addDepend(d->baseline.item);
+ d->updateVerticalAnchors();
+}
+
+void QFxAnchors::resetBaseline()
+{
+ setBaseline(QFxAnchorLine());
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasLeftAnchor;
+ else
+ d->usedAnchors &= ~HasLeftAnchor;
+
+ d->checkHValid();
+
+ d->remDepend(d->left.item);
+ d->left = edge;
+ d->addDepend(d->left.item);
+ d->updateHorizontalAnchors();
+}
+
+void QFxAnchors::resetLeft()
+{
+ setLeft(QFxAnchorLine());
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasRightAnchor;
+ else
+ d->usedAnchors &= ~HasRightAnchor;
+
+ d->checkHValid();
+
+ d->remDepend(d->right.item);
+ d->right = edge;
+ d->addDepend(d->right.item);
+
+ d->updateHorizontalAnchors();
+}
+
+void QFxAnchors::resetRight()
+{
+ setRight(QFxAnchorLine());
+}
+
+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;
+
+ if (edge.item)
+ d->usedAnchors |= HasHCenterAnchor;
+ else
+ d->usedAnchors &= ~HasHCenterAnchor;
+
+ d->checkHValid();
+
+ d->remDepend(d->hCenter.item);
+ d->hCenter = edge;
+ d->addDepend(d->hCenter.item);
+ d->updateHorizontalAnchors();
+}
+
+void QFxAnchors::resetHorizontalCenter()
+{
+ setHorizontalCenter(QFxAnchorLine());
+}
+
+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();
+}
+
+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;
+ } else if (usedAnchors & QFxAnchors::HasBaselineAnchor &&
+ (usedAnchors & QFxAnchors::HasTopAnchor ||
+ usedAnchors & QFxAnchors::HasBottomAnchor ||
+ usedAnchors & QFxAnchors::HasVCenterAnchor)) {
+ qmlInfo(item) << "Baseline anchor can't be used in conjunction with top, bottom, or 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..0e44223
--- /dev/null
+++ b/src/declarative/fx/qfxanchors.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** 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 <QtCore/QObject>
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/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 QFxAnchorsPrivate;
+class Q_DECLARATIVE_EXPORT QFxAnchors : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFxAnchorLine left READ left WRITE setLeft RESET resetLeft)
+ Q_PROPERTY(QFxAnchorLine right READ right WRITE setRight RESET resetRight)
+ Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter WRITE setHorizontalCenter RESET resetHorizontalCenter)
+ Q_PROPERTY(QFxAnchorLine top READ top WRITE setTop RESET resetTop)
+ Q_PROPERTY(QFxAnchorLine bottom READ bottom WRITE setBottom RESET resetBottom)
+ Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter WRITE setVerticalCenter RESET resetVerticalCenter)
+ Q_PROPERTY(QFxAnchorLine baseline READ baseline WRITE setBaseline RESET resetBaseline)
+ 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);
+ virtual ~QFxAnchors();
+
+ enum UsedAnchor {
+ HasLeftAnchor = 0x01,
+ HasRightAnchor = 0x02,
+ HasTopAnchor = 0x04,
+ HasBottomAnchor = 0x08,
+ HasHCenterAnchor = 0x10,
+ HasVCenterAnchor = 0x20,
+ HasBaselineAnchor = 0x40,
+ Horizontal_Mask = HasLeftAnchor | HasRightAnchor | HasHCenterAnchor,
+ Vertical_Mask = HasTopAnchor | HasBottomAnchor | HasVCenterAnchor | HasBaselineAnchor
+ };
+ Q_DECLARE_FLAGS(UsedAnchors, UsedAnchor)
+
+ QFxAnchorLine left() const;
+ void setLeft(const QFxAnchorLine &edge);
+ Q_INVOKABLE void resetLeft(); //### temporarily invokable for testing
+
+ QFxAnchorLine right() const;
+ void setRight(const QFxAnchorLine &edge);
+ void resetRight();
+
+ QFxAnchorLine horizontalCenter() const;
+ void setHorizontalCenter(const QFxAnchorLine &edge);
+ void resetHorizontalCenter();
+
+ QFxAnchorLine top() const;
+ void setTop(const QFxAnchorLine &edge);
+ void resetTop();
+
+ QFxAnchorLine bottom() const;
+ void setBottom(const QFxAnchorLine &edge);
+ void resetBottom();
+
+ QFxAnchorLine verticalCenter() const;
+ void setVerticalCenter(const QFxAnchorLine &edge);
+ void resetVerticalCenter();
+
+ QFxAnchorLine baseline() const;
+ void setBaseline(const QFxAnchorLine &edge);
+ void resetBaseline();
+
+ 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);
+
+Q_SIGNALS:
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void topMarginChanged();
+ void bottomMarginChanged();
+ void verticalCenterOffsetChanged();
+ void horizontalCenterOffsetChanged();
+
+private:
+ friend class QFxItem;
+ 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..32d8b75
--- /dev/null
+++ b/src/declarative/fx/qfxanchors_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 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()
+ : updatingMe(false), updatingHorizontalAnchor(false),
+ updatingVerticalAnchor(false), item(0), usedAnchors(0), fill(0),
+ centeredIn(0), leftMargin(0), rightMargin(0), topMargin(0),
+ bottomMargin(0), vCenterOffset(0), hCenterOffset(0)
+ {
+ }
+
+ void init()
+ {
+ }
+
+ void clearItem(QFxItem *);
+
+ void addDepend(QFxItem *);
+ void remDepend(QFxItem *);
+ bool isItemComplete() const;
+
+ bool updatingMe:1;
+ bool updatingHorizontalAnchor:1;
+ bool updatingVerticalAnchor:1;
+
+ void setItemHeight(qreal);
+ void setItemWidth(qreal);
+ void setItemX(qreal);
+ void setItemY(qreal);
+ void setItemPos(const QPointF &);
+
+ void updateOnComplete();
+ void updateMe();
+ void update(QFxItem *, const QRectF &, const QRectF &);
+
+ bool checkHValid() const;
+ bool checkVValid() const;
+ bool checkHAnchorValid(QFxAnchorLine anchor) const;
+ bool checkVAnchorValid(QFxAnchorLine anchor) const;
+ bool calcStretch(const QFxAnchorLine &edge1, const QFxAnchorLine &edge2, int offset1, int offset2, QFxAnchorLine::AnchorLine line, int &stretch);
+
+ void updateHorizontalAnchors();
+ void updateVerticalAnchors();
+ void fillChanged();
+ void centeredInChanged();
+
+ QFxItem *item;
+ QFxAnchors::UsedAnchors usedAnchors;
+
+ QFxItem *fill;
+ QFxItem *centeredIn;
+
+ QFxAnchorLine left;
+ QFxAnchorLine right;
+ QFxAnchorLine top;
+ QFxAnchorLine bottom;
+ QFxAnchorLine vCenter;
+ QFxAnchorLine hCenter;
+ QFxAnchorLine baseline;
+
+ 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..029206b
--- /dev/null
+++ b/src/declarative/fx/qfxanimatedimageitem.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** 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
+ \qml
+Item {
+ width: anim.width; height: anim.height+8
+ AnimatedImage { id: anim; source: "pics/games-anim.gif" }
+ Rect { color: "red"; width: 4; height: 8; y: anim.height
+ x: (anim.width-width)*anim.currentFrame/(anim.frameCount-1)
+ }
+}
+ \endqml
+ \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 = qmlContext(this)->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 = qmlContext(this)->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..a0d14c4
--- /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 <QtDeclarative/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..4c6eb58
--- /dev/null
+++ b/src/declarative/fx/qfxblendedimage.cpp
@@ -0,0 +1,297 @@
+/****************************************************************************
+**
+** 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
+
+/*!
+ \qmlclass BlendedImage
+ \brief The BlendedImage elements blends two different images depending on a blend ratio.
+
+ This element can be used to simulate blur on slow devices by setting secondaryUrl with
+ a pre-rendered blurred version of primaryUrl.
+
+ 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.
+*/
+
+/*!
+ \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 secondaryUrl with
+ a pre-rendered blurred version of primaryUrl.
+
+ 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), _smooth(false), dirty(false)
+{
+#if defined(QFX_RENDER_OPENGL2)
+ setOptions(HasContents);
+#endif
+}
+
+/*!
+ \qmlproperty string BlendedImage::primaryUrl
+ 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);
+ primSrc = url;
+ primUrl = qmlContext(this)->resolvedUrl(url);
+ if (!primSrc.isEmpty())
+ QFxPixmap::get(qmlEngine(this), primUrl,this,SLOT(primaryLoaded()));
+}
+
+/*!
+ \qmlproperty string BlendedImage::secondaryUrl
+ 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);
+ secSrc = url;
+ secUrl = qmlContext(this)->resolvedUrl(url);
+ if (!secSrc.isEmpty())
+ QFxPixmap::get(qmlEngine(this), secUrl,this,SLOT(secondaryLoaded()));
+}
+
+/*!
+ \qmlproperty real BlendedImage::blend
+ 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();
+}
+
+/*!
+ \qmlproperty bool BlendedImage::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 BlendedImage 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.
+ */
+bool QFxBlendedImage::smoothTransform() const
+{
+ return _smooth;
+}
+
+void QFxBlendedImage::setSmoothTransform(bool s)
+{
+ if (_smooth == s)
+ return;
+ _smooth = s;
+ update();
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+
+void QFxBlendedImage::paintContents(QPainter &p)
+{
+ if (primSrc.isNull() && secSrc.isNull())
+ return;
+
+ if (_smooth) {
+ p.save();
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, _smooth);
+ }
+
+ if (_blend < 0.75)
+ p.drawPixmap(0, 0, primPix);
+ else
+ p.drawPixmap(0, 0, secPix);
+
+ if (_smooth) {
+ p.restore();
+ }
+}
+
+#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.toImage());
+ sec.setImage(secPix.toImage());
+
+ 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..baf4b64
--- /dev/null
+++ b/src/declarative/fx/qfxblendedimage.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/qfxitem.h>
+#if defined(QFX_RENDER_OPENGL2)
+#include <gltexture.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class Q_DECLARATIVE_EXPORT 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)
+ Q_PROPERTY(bool smooth READ smoothTransform WRITE setSmoothTransform)
+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);
+
+ bool smoothTransform() const;
+ void setSmoothTransform(bool);
+
+#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 _smooth;
+ bool dirty;
+#if defined(QFX_RENDER_OPENGL2)
+ GLTexture prim;
+ GLTexture sec;
+#endif
+ QPixmap primPix;
+ QPixmap 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..84799ec
--- /dev/null
+++ b/src/declarative/fx/qfxblurfilter.cpp
@@ -0,0 +1,467 @@
+/****************************************************************************
+**
+** 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 item. The following example
+ shows an icon at a blur radius of 0, 5 and 10.
+
+ \table
+ \row
+ \o
+ \qml
+HorizontalLayout {
+ Image {
+ source: "icon.png"
+ filter: Blur { radius: 0 }
+ }
+ Image {
+ source: "icon.png"
+ filter: Blur { radius: 5 }
+ }
+ Image {
+ source: "icon.png"
+ filter: Blur { radius: 10 }
+ }
+}
+ \endqml
+ \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 group_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..90285de
--- /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 <QtDeclarative/qsimplecanvasfilter.h>
+#include <QtDeclarative/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..d3f7061
--- /dev/null
+++ b/src/declarative/fx/qfxcomponentinstance.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** 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 ComponentInstance
+
+ \brief The QFxComponentInstance class provides a way to instantiate an item from a component.
+ */
+
+/*!
+ \qmlclass ComponentInstance QFxComponentInstance
+ \brief The ComponentInstance item allows you to instantiate a \l{Component}.
+
+ \qml
+ Item {
+ Component {
+ id: RedSquare
+ Rect { color: "red"; width: 10; height: 10 }
+ }
+
+ ComponentInstance { component: RedSquare }
+ }
+ \endqml
+*/
+QFxComponentInstance::QFxComponentInstance(QFxItem *parent)
+ : QFxItem(*(new QFxComponentInstancePrivate), parent)
+{
+ setOptions(IsFocusRealm);
+}
+
+QFxComponentInstance::QFxComponentInstance(QFxComponentInstancePrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ setOptions(IsFocusRealm);
+}
+
+/*!
+ \qmlproperty Component QFxComponentInstance::component
+
+ This property holds the component to instantiate.
+*/
+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(qmlContext(this));
+ 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());
+ }
+}
+
+/*!
+ \qmlproperty Item QFxComponentInstance::instance
+
+ This property holds the instantiated component.
+*/
+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..e749272
--- /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 <QtDeclarative/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..482442b
--- /dev/null
+++ b/src/declarative/fx/qfxcontentwrapper.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** 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)
+
+/*!
+ \qmlclass ContentWrapper QFxContentWrapper
+ \ingroup group_utility
+ \brief ContentWrapper provides a component which contains content.
+ \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
+ group box component definition itself.
+ In cases like these \l Content can be used to specify at what location in the component
+ the content should be placed. It is used in conjuntion with the \e content property of
+ ContentWrapper: any items listed as content will be placed in the location
+ specified by Content. The component containing the Content must be of type
+ ContentWrapper.
+
+ GroupBox component definition:
+ \quotefile doc/src/snippets/declarative/GroupBox.qml
+
+ \bold Note that in the above component definition ContentWrapper's \e children
+ property is specified explicitly since \e content is the default property.
+
+ Component use:
+ \table
+ \row \o \image content.png
+ \o \quotefile doc/src/snippets/declarative/content.qml
+ \endtable
+
+ \sa Content
+*/
+
+QFxContentWrapper::QFxContentWrapper(QFxItem *parent)
+: QFxItem(*(new QFxContentWrapperPrivate), parent)
+{
+}
+
+QFxContentWrapper::QFxContentWrapper(QFxContentWrapperPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+}
+
+/*!
+ \qmlproperty list<Item> ContentWrapper::content
+
+ Contains the list of elements to replace the \l Content
+ placeholder.
+
+ \sa Content
+*/
+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 group_utility
+ \brief Content is used as a placeholder for the content of a component.
+ \inherits Item
+
+ The Content element is used to place content within a component.
+ See \l ContentWrapper for usage.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxcontentwrapper.h b/src/declarative/fx/qfxcontentwrapper.h
new file mode 100644
index 0000000..d8fe0b8
--- /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 <QtDeclarative/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..a75fa1e
--- /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/qfxevents.cpp b/src/declarative/fx/qfxevents.cpp
new file mode 100644
index 0000000..94c2d2e
--- /dev/null
+++ b/src/declarative/fx/qfxevents.cpp
@@ -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$
+**
+****************************************************************************/
+
+#include "qfxevents_p.h"
+
+QT_BEGIN_NAMESPACE
+/*!
+ \qmlclass KeyEvent QFxKeyEvent
+ \brief The KeyEvent object provides information about a key event.
+
+ For example, the following changes the Item's state property when the Enter
+ key is pressed:
+ \qml
+Item {
+ focus: true
+ onKeyPress: { if (event.key == Qt.Key_Enter) state = 'ShowDetails'; }
+}
+ \endqml
+
+ The \l KeyActions object could also be used to achieve the above with
+ a clearer syntax.
+
+ \sa KeyActions
+*/
+
+/*!
+ \internal
+ \class QFxKeyEvent
+*/
+
+/*!
+ \qmlproperty int KeyEvent::key
+
+ This property holds the code of the key that was pressed or released.
+
+ See \l {Qt::Key}{Qt.Key} for the list of keyboard codes. These codes are
+ independent of the underlying window system. Note that this
+ function does not distinguish between capital and non-capital
+ letters, use the text() function (returning the Unicode text the
+ key generated) for this purpose.
+
+ A value of either 0 or \l {Qt::Key_unknown}{Qt.Key_Unknown} means that the event is not
+ the result of a known key; for example, it may be the result of
+ a compose sequence, a keyboard macro, or due to key event
+ compression.
+*/
+
+/*!
+ \qmlproperty string KeyEvent::text
+
+ This property holds the Unicode text that the key generated.
+ The text returned can be an empty string in cases where modifier keys,
+ such as Shift, Control, Alt, and Meta, are being pressed or released.
+ In such cases \c key will contain a valid value
+*/
+
+/*!
+ \qmlproperty bool KeyEvent::isAutoRepeat
+
+ This property holds whether this event comes from an auto-repeating key.
+*/
+
+/*!
+ \qmlproperty int KeyEvent::count
+
+ This property holds the number of keys involved in this event. If \l KeyEvent::text
+ is not empty, this is simply the length of the string.
+*/
+
+/*!
+ \qmlclass MouseEvent QFxMouseEvent
+ \brief The MouseEvent object provides information about a mouse event.
+
+ The position of the mouse can be found via the x and y properties.
+ The button that caused the event is available via the button property.
+*/
+
+/*!
+ \internal
+ \class QFxMouseEvent
+*/
+
+/*!
+ \qmlproperty int MouseEvent::x
+ \qmlproperty int MouseEvent::y
+
+ These properties hold the position of the mouse event.
+*/
+
+/*!
+ \qmlproperty enum MouseEvent::button
+
+ This property holds the button that caused the event. It can be one of:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MidButton
+ \endlist
+*/
+
+/*!
+ \qmlproperty int MouseEvent::buttons
+
+ This property holds the mouse buttons pressed when the event was generated.
+ For mouse move events, this is all buttons that are pressed down. For mouse
+ press and double click events this includes the button that caused the event.
+ For mouse release events this excludes the button that caused the event.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.LeftButton
+ \o Qt.RightButton
+ \o Qt.MidButton
+ \endlist
+*/
+
+/*!
+ \qmlproperty int MouseEvent::modifiers
+
+ This property holds the keyboard modifier flags that existed immediately
+ before the event occurred.
+
+ It contains a bitwise combination of:
+ \list
+ \o Qt.NoModifier - No modifier key is pressed.
+ \o Qt.ShiftModifier - A Shift key on the keyboard is pressed.
+ \o Qt.ControlModifier - A Ctrl key on the keyboard is pressed.
+ \o Qt.AltModifier - An Alt key on the keyboard is pressed.
+ \o Qt.MetaModifier - A Meta key on the keyboard is pressed.
+ \o Qt.KeypadModifier - A keypad button is pressed.
+ \endlist
+
+ For example, to react to a Shift key + Left mouse button click:
+ \qml
+MouseRegion {
+ onClick: { if (mouse.button == Qt.LeftButton && mouse.modifiers & Qt.ShiftModifier) doSomething(); }
+}
+ \endqml
+*/
+
+QML_DEFINE_NOCREATE_TYPE(QFxKeyEvent)
+QML_DEFINE_NOCREATE_TYPE(QFxMouseEvent)
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxevents_p.h b/src/declarative/fx/qfxevents_p.h
new file mode 100644
index 0000000..2eb29af
--- /dev/null
+++ b/src/declarative/fx/qfxevents_p.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 QFXEVENTS_P_H
+#define QFXEVENTS_P_H
+
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qml.h>
+#include <QtCore/qobject.h>
+#include <QtGui/qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFxKeyEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int key READ key)
+ Q_PROPERTY(QString text READ text)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool isAutoRepeat READ isAutoRepeat)
+ Q_PROPERTY(int count READ count)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QFxKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
+ : event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); }
+ QFxKeyEvent(const QKeyEvent &ke)
+ : event(ke) { event.setAccepted(false); }
+
+ int key() const { return event.key(); }
+ QString text() const { return event.text(); }
+ int modifiers() const { return event.modifiers(); }
+ bool isAutoRepeat() const { return event.isAutoRepeat(); }
+ int count() const { return event.count(); }
+
+ bool isAccepted() { return event.isAccepted(); }
+ void setAccepted(bool accepted) { event.setAccepted(accepted); }
+
+private:
+ QKeyEvent event;
+};
+
+QML_DECLARE_TYPE(QFxKeyEvent)
+
+class QFxMouseEvent : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int x READ x)
+ Q_PROPERTY(int y READ y)
+ Q_PROPERTY(int button READ button)
+ Q_PROPERTY(int buttons READ buttons)
+ Q_PROPERTY(int modifiers READ modifiers)
+ Q_PROPERTY(bool wasHeld READ wasHeld)
+ Q_PROPERTY(bool isClick READ isClick)
+ Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
+
+public:
+ QFxMouseEvent(int x, int y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers
+ , bool isClick=false, bool wasHeld=false)
+ : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers)
+ , _wasHeld(wasHeld), _isClick(isClick), _accepted(false) {}
+
+ int x() const { return _x; }
+ int y() const { return _y; }
+ int button() const { return _button; }
+ int buttons() const { return _buttons; }
+ int modifiers() const { return _modifiers; }
+ bool wasHeld() const { return _wasHeld; }
+ bool isClick() const { return _isClick; }
+
+ bool isAccepted() { return _accepted; }
+ void setAccepted(bool accepted) { _accepted = accepted; }
+
+private:
+ int _x;
+ int _y;
+ Qt::MouseButton _button;
+ Qt::MouseButtons _buttons;
+ Qt::KeyboardModifiers _modifiers;
+ bool _wasHeld;
+ bool _isClick;
+ bool _accepted;
+};
+
+QML_DECLARE_TYPE(QFxMouseEvent)
+
+QT_END_NAMESPACE
+
+#endif // QFXEVENTS_P_H
diff --git a/src/declarative/fx/qfxflickable.cpp b/src/declarative/fx/qfxflickable.cpp
new file mode 100644
index 0000000..bc4a5fc
--- /dev/null
+++ b/src/declarative/fx/qfxflickable.cpp
@@ -0,0 +1,1153 @@
+/****************************************************************************
+**
+** 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 <QPointer>
+#include <QTimer>
+
+QT_BEGIN_NAMESPACE
+
+ElasticValue::ElasticValue(QmlTimeLineValue &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 = QmlTimeLineEvent::timeLineEvent<QFxFlickablePrivate, &QFxFlickablePrivate::fixupX>(&_moveX, this);
+ fixupYEvent = QmlTimeLineEvent::timeLineEvent<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::LeftButton);
+ q->setOptions(QSimpleCanvasItem::ChildMouseFilter | 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()));
+ QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(heightChange()));
+ QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(widthChange()));
+}
+
+void QFxFlickablePrivate::fixupX()
+{
+ Q_Q(QFxFlickable);
+ if (!q->xflick() || _moveX.timeLine())
+ return;
+
+ vTime = _tl.time();
+
+ if (_moveX.value() > q->minXExtent() || q->maxXExtent() > 0) {
+ _tl.clear();
+ _tl.move(_moveX, q->minXExtent(), QEasingCurve(QEasingCurve::InOutQuad), 200);
+ flicked = false;
+ //emit flickingChanged();
+ } else if (_moveX.value() < q->maxXExtent()) {
+ _tl.clear();
+ _tl.move(_moveX, q->maxXExtent(), QEasingCurve(QEasingCurve::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.clear();
+ _tl.move(_moveY, q->minYExtent(), QEasingCurve(QEasingCurve::InOutQuad), 200);
+ //emit flickingChanged();
+ } else if (_moveY.value() < q->maxYExtent()) {
+ _tl.clear();
+ _tl.move(_moveY, q->maxYExtent(), QEasingCurve(QEasingCurve::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 item 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; source: "bigimage.png" }
+ }
+ \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 group_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; source: "bigimage.png" }
+}
+\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 QFxFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (!locked && _tl.isActive() && (qAbs(velocityX) > 10 || qAbs(velocityY) > 10))
+ stealMouse = true; // If we've been flicked then steal the click.
+ else
+ stealMouse = false;
+ pressed = true;
+ _tl.clear();
+ velocityX = -1;
+ velocityY = -1;
+ lastPos = QPoint();
+ lastPosTime.start();
+ pressPos = event->pos();
+ pressX = _moveX.value();
+ pressY = _moveY.value();
+ flicked = false;
+ pressTime.start();
+ if (dragMode == QFxFlickable::Elastic) {
+ elasticX.clear();
+ elasticY.clear();
+ }
+ velocityTime.start();
+}
+
+void QFxFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_Q(QFxFlickable);
+ if (locked || lastPosTime.isNull())
+ return;
+ bool rejectY = false;
+ bool rejectX = false;
+ bool moved = false;
+
+ if (q->yflick()) {
+ int dy = int(event->pos().y() - pressPos.y());
+ if (qAbs(dy) > FlickThreshold || pressTime.elapsed() > 200) {
+ qreal newY = dy + pressY;
+ const qreal minY = q->minYExtent();
+ const qreal maxY = q->maxYExtent();
+ if (newY > minY)
+ newY = minY + (newY - minY) / 2;
+ if (newY < maxY && maxY - minY < 0)
+ newY = maxY + (newY - maxY) / 2;
+ if (q->overShoot() || (newY <= minY && newY >= maxY)) {
+ if (dragMode == QFxFlickable::Hard)
+ _moveY.setValue(newY);
+ else
+ elasticY.setValue(newY);
+ moved = true;
+ } else if (!q->overShoot())
+ rejectY = true;
+ if (qAbs(dy) > FlickThreshold)
+ stealMouse = true;
+ }
+ }
+
+ if (q->xflick()) {
+ int dx = int(event->pos().x() - pressPos.x());
+ if (qAbs(dx) > FlickThreshold || pressTime.elapsed() > 200) {
+ qreal newX = dx + pressX;
+ if (q->overShoot() || (newX <= q->minXExtent() && newX >= q->maxXExtent())) {
+ if (dragMode == QFxFlickable::Hard)
+ _moveX.setValue(newX);
+ else
+ elasticX.setValue(newX);
+ moved = true;
+ } else if (!q->overShoot())
+ rejectX = true;
+ if (qAbs(dx) > FlickThreshold)
+ stealMouse = true;
+ }
+ }
+
+ if (!lastPos.isNull()) {
+ qreal elapsed = qreal(lastPosTime.restart()) / 1000.;
+ if (elapsed <= 0)
+ elapsed = 1;
+ if (q->yflick()) {
+ qreal diff = event->pos().y() - lastPos.y();
+ velocityY = diff / elapsed;
+ }
+
+ if (q->xflick()) {
+ qreal diff = event->pos().x() - lastPos.x();
+ velocityX = diff / elapsed;
+ }
+ }
+
+ if (rejectY) velocityY = 0;
+ if (rejectX) velocityX = 0;
+
+ if (moved) {
+ q->viewportMoved();
+ q->movementStarting();
+ }
+
+ lastPos = event->pos();
+}
+
+void QFxFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEvent *)
+{
+ Q_Q(QFxFlickable);
+
+ pressed = false;
+ if (lastPosTime.isNull())
+ return;
+
+ if (dragMode == QFxFlickable::Elastic) {
+ elasticY.clear();
+ elasticX.clear();
+ }
+
+ vTime = _tl.time();
+ if (qAbs(velocityY) > 10) {
+ qreal maxDistance = -1;
+ // -ve velocity means list is moving up
+ if (velocityY > 0) {
+ if (_moveY.value() < q->minYExtent())
+ maxDistance = qAbs(q->minYExtent() -_moveY.value() + (overShoot?30:0));
+ } else {
+ if (_moveY.value() > q->maxYExtent())
+ maxDistance = qAbs(q->maxYExtent() - _moveY.value()) + (overShoot?30:0);
+ }
+ if (maxDistance > 0) {
+ qreal v = velocityY;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ _tl.accel(_moveY, v, 500, maxDistance);
+ _tl.execute(fixupYEvent);
+ flicked = true;
+ emit q->flickingChanged();
+ emit q->flickStarted();
+ } else {
+ fixupY();
+ }
+ } else {
+ fixupY();
+ }
+ if (qAbs(velocityX) > 10) {
+ qreal maxDistance = -1;
+ // -ve velocity means list is moving up
+ if (velocityX > 0) {
+ if (_moveX.value() < q->minXExtent())
+ maxDistance = qAbs(q->minXExtent()) -_moveX.value() + (overShoot?30:0);
+ } else {
+ if (_moveX.value() > q->maxXExtent())
+ maxDistance = qAbs(q->maxXExtent() - _moveX.value()) + (overShoot?30:0);
+ }
+ if (maxDistance > 0) {
+ qreal v = velocityX;
+ if (maxVelocity != -1 && maxVelocity < qAbs(v)) {
+ if (v < 0)
+ v = -maxVelocity;
+ else
+ v = maxVelocity;
+ }
+ _tl.accel(_moveX, v, 500, maxDistance);
+ _tl.execute(fixupXEvent);
+ flicked = true;
+ emit q->flickingChanged();
+ emit q->flickStarted();
+ } else {
+ fixupX();
+ }
+ } else {
+ fixupX();
+ }
+ stealMouse = false;
+ lastPosTime = QTime();
+
+ if (!_tl.isActive())
+ q->movementEnding();
+}
+
+void QFxFlickable::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ d->handleMousePressEvent(event);
+ event->accept();
+}
+
+void QFxFlickable::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ d->handleMouseMoveEvent(event);
+ event->accept();
+}
+
+void QFxFlickable::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxFlickable);
+ d->handleMouseReleaseEvent(event);
+ event->accept();
+}
+
+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; source: "bigimage.png" }
+ }
+ \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);
+ // Make sure that we're entirely in view.
+ if (d->_moveX.value() > minXExtent() || maxXExtent() > 0) {
+ d->_tl.clear();
+ d->_moveX.setValue(minXExtent());
+ } else if (d->_moveX.value() < maxXExtent()) {
+ d->_tl.clear();
+ d->_moveX.setValue(maxXExtent());
+ }
+ emit viewportWidthChanged();
+ d->updateBeginningEnd();
+}
+
+void QFxFlickable::widthChange()
+{
+ Q_D(QFxFlickable);
+ if (d->vWidth < 0) {
+ d->_flick->setWidth(width());
+ emit viewportWidthChanged();
+ d->updateBeginningEnd();
+ }
+}
+
+void QFxFlickable::heightChange()
+{
+ Q_D(QFxFlickable);
+ if (d->vHeight < 0) {
+ d->_flick->setHeight(height());
+ 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);
+ // Make sure that we're entirely in view.
+ if (d->_moveY.value() > minYExtent() || maxYExtent() > 0) {
+ d->_tl.clear();
+ d->_moveY.setValue(minYExtent());
+ } else if (d->_moveY.value() < maxYExtent()) {
+ d->_tl.clear();
+ d->_moveY.setValue(maxYExtent());
+ }
+ 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:
+ d->handleMouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ d->handleMousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ d->handleMouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = static_cast<QFxItem*>(mouseGrabberItem());
+ if (grabber && d->stealMouse && !grabber->keepMouseGrab())
+ grabMouse();
+
+ 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:
+ return sendMouseEvent(e);
+ 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..77aaf50
--- /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 <QtDeclarative/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;
+
+ 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();
+ void heightChange();
+ void widthChange();
+
+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..a3b1500
--- /dev/null
+++ b/src/declarative/fx/qfxflickable_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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 "qmltimelinevalueproxy.h"
+#include "private/qmlanimation_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class ElasticValue : public QAbstractAnimation {
+ Q_OBJECT
+public:
+ ElasticValue(QmlTimeLineValue &);
+ 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;
+ QmlTimeLineValue &_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;
+ QmlTimeLineValueProxy<QFxItem> _moveX;
+ QmlTimeLineValueProxy<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;
+ QmlTimeLineEvent fixupXEvent;
+ QmlTimeLineEvent fixupYEvent;
+ int maxVelocity;
+ bool locked;
+ QFxFlickable::DragMode dragMode;
+ ElasticValue elasticY;
+ ElasticValue elasticX;
+ QTime velocityTime;
+ QPointF lastFlickablePosition;
+ int velocityDecay;
+
+ void updateVelocity();
+ struct Velocity : public QmlTimeLineValue
+ {
+ Velocity(QFxFlickablePrivate *p)
+ : parent(p) {}
+ virtual void setValue(qreal v) {
+ QmlTimeLineValue::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;
+
+ void handleMousePressEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseMoveEvent(QGraphicsSceneMouseEvent *);
+ void handleMouseReleaseEvent(QGraphicsSceneMouseEvent *);
+
+ // 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/qfxflipable.cpp b/src/declarative/fx/qfxflipable.cpp
new file mode 100644
index 0000000..4c02e74
--- /dev/null
+++ b/src/declarative/fx/qfxflipable.cpp
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** 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 "qfxflipable.h"
+#include "private/qfxitem_p.h"
+#include "qfxtransform.h"
+#include <QtDeclarative/qmlinfo.h>
+
+QML_DEFINE_TYPE(QFxFlipable,Flipable)
+
+class QFxFlipablePrivate : public QFxItemPrivate
+{
+public:
+ QFxFlipablePrivate() : current(QFxFlipable::Front), front(0), back(0), axis(0), rotation(0) {}
+
+ void setBackTransform();
+ void _q_updateAxis();
+
+ QFxFlipable::Side current;
+ QFxItem *front;
+ QFxItem *back;
+ QFxAxis *axis;
+ QFxRotation3D axisRotation;
+ qreal rotation;
+};
+
+/*!
+ \qmlclass Flipable QFxFlipable
+ \brief The Flipable item 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.
+
+ \qml
+Flipable {
+ id: flipable
+ width: 40
+ height: 40
+ axis: Axis {
+ startX: 20
+ startY: 0
+ endX: 20
+ endY: 40
+ }
+ front: Image { source: "front.png" }
+ back: Image { source: "back.png" }
+ states: [
+ State {
+ name: "back"
+ SetProperty {
+ target: flipable
+ property: "rotation"
+ value: 180
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ NumericAnimation {
+ easing: "easeInOutQuad"
+ properties: "rotation"
+ }
+ }
+ ]
+}
+ \endqml
+
+ \image flipable.gif
+*/
+
+/*!
+ \internal
+ \class QFxFlipable
+ \brief The QFxFlipable class provides a flipable surface.
+
+ \ingroup group_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 Axis Flipable::axis
+
+ The axis to flip around. See the \l Axis documentation for more
+ information on specifying an axis.
+*/
+
+QFxAxis *QFxFlipable::axis()
+{
+ Q_D(QFxFlipable);
+ return d->axis;
+}
+
+void QFxFlipable::setAxis(QFxAxis *axis)
+{
+ Q_D(QFxFlipable);
+ //### disconnect if we are already connected?
+ if (d->axis)
+ disconnect(d->axis, SIGNAL(updated()), this, SLOT(_q_updateAxis()));
+ d->axis = axis;
+ connect(d->axis, SIGNAL(updated()), this, SLOT(_q_updateAxis()));
+ d->_q_updateAxis();
+}
+
+void QFxFlipablePrivate::_q_updateAxis()
+{
+ axisRotation.axis()->setStartX(axis->startX());
+ axisRotation.axis()->setStartY(axis->startY());
+ axisRotation.axis()->setEndX(axis->endX());
+ axisRotation.axis()->setEndY(axis->endY());
+ axisRotation.axis()->setEndZ(axis->endZ());
+}
+
+void QFxFlipablePrivate::setBackTransform()
+{
+ if (!back)
+ return;
+
+ QPointF p1(0, 0);
+ QPointF p2(1, 0);
+ QPointF p3(1, 1);
+
+ axisRotation.setAngle(180);
+ p1 = axisRotation.transform().map(p1);
+ p2 = axisRotation.transform().map(p2);
+ p3 = axisRotation.transform().map(p3);
+ axisRotation.setAngle(rotation);
+
+ QSimpleCanvas::Matrix mat;
+#ifdef QFX_RENDER_OPENGL
+ mat.translate(back->width()/2,back->height()/2, 0);
+ if (back->width() && p1.x() >= p2.x())
+ mat.rotate(180, 0, 1, 0);
+ if (back->height() && p2.y() >= p3.y())
+ mat.rotate(180, 1, 0, 0);
+ mat.translate(-back->width()/2,-back->height()/2, 0);
+#else
+ mat.translate(back->width()/2,back->height()/2);
+ if (back->width() && p1.x() >= p2.x())
+ mat.rotate(180, Qt::YAxis);
+ if (back->height() && p2.y() >= p3.y())
+ mat.rotate(180, Qt::XAxis);
+ mat.translate(-back->width()/2,-back->height()/2);
+#endif
+ back->setTransform(mat);
+}
+
+/*!
+ \qmlproperty real Flipable::rotation
+ The angle to rotate the flipable. For example, to show the back side of the flipable
+ you can set the rotation to 180.
+*/
+qreal QFxFlipable::rotation() const
+{
+ Q_D(const QFxFlipable);
+ return d->rotation;
+}
+
+void QFxFlipable::setRotation(qreal angle)
+{
+ Q_D(QFxFlipable);
+ d->rotation = angle;
+ d->axisRotation.setAngle(angle);
+ setTransform(d->axisRotation.transform());
+
+
+ int simpleAngle = int(angle) % 360;
+
+ Side newSide;
+ if (simpleAngle < 91 || simpleAngle > 270) {
+ newSide = Front;
+ } else {
+ newSide = Back;
+ }
+
+ if (newSide != d->current) {
+ d->current = newSide;
+ if (d->front)
+ d->front->setOpacity((d->current==Front)?1.:0.);
+ if (d->back) {
+ d->setBackTransform();
+ d->back->setOpacity((d->current==Back)?1.:0.);
+ }
+ emit sideChanged();
+ }
+}
+
+/*!
+ \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;
+}
+
+//in some cases the user may want to specify a more complex transformation.
+//in that case, we still allow the generic use of transform.
+//(the logic here should be kept in sync with setBackTransform and setRotation)
+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();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qfxflipable.cpp"
diff --git a/src/declarative/fx/qfxflipable.h b/src/declarative/fx/qfxflipable.h
new file mode 100644
index 0000000..6630633
--- /dev/null
+++ b/src/declarative/fx/qfxflipable.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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 QFXFLIPABLE_H
+#define QFXFLIPABLE_H
+
+#include <QtCore/QObject>
+#include <QtGui/QTransform>
+#if defined(QFX_RENDER_OPENGL)
+#include <QtGui/qmatrix4x4.h>
+#endif
+#include <QtDeclarative/qfxitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QFxAxis;
+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(QFxAxis *axis READ axis WRITE setAxis)
+ Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
+ Q_PROPERTY(Side side READ side NOTIFY sideChanged)
+public:
+ QFxFlipable(QFxItem *parent=0);
+ ~QFxFlipable();
+
+ QFxItem *front();
+ void setFront(QFxItem *);
+
+ QFxItem *back();
+ void setBack(QFxItem *);
+
+ QFxAxis *axis();
+ void setAxis(QFxAxis *axis);
+
+ qreal rotation() const;
+ void setRotation(qreal angle);
+
+ enum Side { Front, Back };
+ Side side() const;
+
+protected:
+ virtual void transformChanged(const QSimpleCanvas::Matrix &);
+
+Q_SIGNALS:
+ void sideChanged();
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_updateAxis())
+ Q_DISABLE_COPY(QFxFlipable)
+ Q_DECLARE_PRIVATE(QFxFlipable)
+};
+QML_DECLARE_TYPE(QFxFlipable)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXFLIPABLE_H
diff --git a/src/declarative/fx/qfxfocuspanel.cpp b/src/declarative/fx/qfxfocuspanel.cpp
new file mode 100644
index 0000000..6da8564
--- /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 object 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 object 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..60f9118
--- /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 <QtDeclarative/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..9270bb2
--- /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 object 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..d2aadce
--- /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 <QtDeclarative/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..dde8fcf
--- /dev/null
+++ b/src/declarative/fx/qfxgridview.cpp
@@ -0,0 +1,1428 @@
+/****************************************************************************
+**
+** 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) {
+ QFxGridViewAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QFxGridViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+ 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() + view->cellHeight() - 1
+ : item->x() + view->cellWidth() - 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), requestedIndex(-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 *createItem(int modelIndex);
+ void releaseItem(FxGridItem *item);
+ void refill(qreal from, qreal to);
+
+ void updateGrid();
+ void layout(bool removed=false);
+ void updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ 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;
+ QHash<QFxItem*,int> unrequestedItems;
+ FxGridItem *currentItem;
+ QFxItem *tmpCurrent;
+ QFxGridView::Flow flow;
+ int visiblePos;
+ int visibleIndex;
+ int currentIndex;
+ int cellWidth;
+ int cellHeight;
+ int columns;
+ int requestedIndex;
+ 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);
+ QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(sizeChange()));
+ QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(sizeChange()));
+}
+
+void QFxGridViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visiblePos = 0;
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = -1;
+ createHighlight();
+ trackedItem = 0;
+}
+
+FxGridItem *QFxGridViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QFxGridView);
+ // create object
+ requestedIndex = modelIndex;
+ 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());
+ }
+ requestedIndex = 0;
+ return listItem;
+}
+
+
+void QFxGridViewPrivate::releaseItem(FxGridItem *item)
+{
+ Q_Q(QFxGridView);
+ if (!item)
+ return;
+ if (trackedItem == item) {
+ QObject::disconnect(trackedItem->item, SIGNAL(topChanged()), q, SLOT(trackedPositionChanged()));
+ QObject::disconnect(trackedItem->item, SIGNAL(leftChanged()), q, SLOT(trackedPositionChanged()));
+ trackedItem = 0;
+ }
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ 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;
+ if (!(item = createItem(modelIndex)))
+ break;
+ 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;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --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(), qreal(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();
+ }
+ updateUnrequestedPositions();
+}
+
+void QFxGridViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QFxGridView);
+ QHash<QFxItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QFxGridViewPrivate::updateUnrequestedPositions()
+{
+ QHash<QFxItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ if (flow == QFxGridView::LeftToRight) {
+ it.key()->setPos(QPointF(colPosAt(*it), rowPosAt(*it)));
+ } else {
+ it.key()->setPos(QPointF(rowPosAt(*it), colPosAt(*it)));
+ }
+ }
+}
+
+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(qmlContext(q));
+ 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) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = -1;
+ updateHighlight();
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ if (tmpCurrent) {
+ delete tmpCurrent;
+ tmpCurrent = 0;
+ }
+ FxGridItem *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ currentItem->setPosition(colPosAt(modelIndex), rowPosAt(modelIndex));
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ releaseItem(oldCurrentItem);
+}
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass GridView
+ \inherits Flickable
+ \brief The GridView item 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 QML.
+
+ 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 a QML model.
+
+ \image gridview.png
+
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml 3
+
+ The model is defined as a ListModel using QML:
+ \quotefile doc/src/snippets/declarative/gridview/dummydata/ContactModel.qml
+
+ In this case ListModel is a handy way for us to test our UI. In practice
+ the model would be implemented in C++, or perhaps via a SQL data source.
+
+
+*/
+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
+ {QAbstractItemModel} subclass, a VisualModel, or a simple list.
+*/
+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)));
+ disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*)));
+ }
+ 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(qmlContext(this));
+ 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)));
+ connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*)));
+ 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:
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml 0
+*/
+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(qmlContext(this));
+ 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:
+ \snippet doc/src/snippets/declarative/gridview/gridview.qml 1
+
+ \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 component, for example:
+
+ \code
+ Component {
+ id: Highlight
+ Rect {
+ id: Wrapper; color: "lightsteelblue"; radius: 4; width: 320; height: 60 >
+ y: Follow { source: Wrapper.GridView.view.current.y; spring: 3; damping: 0.2 }
+ x: Follow { source: Wrapper.GridView.view.current.x; spring: 3; damping: 0.2 }
+ }
+ }
+ \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
+ \qmlproperty int GridView::cellHeight
+
+ These properties holds the width and height of each cell in the grid
+
+ The default sell size is 100x100.
+*/
+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();
+ }
+}
+
+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();
+ }
+}
+
+void QFxGridView::sizeChange()
+{
+ Q_D(QFxGridView);
+ 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->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->index != -1)
+ listItem->index += count;
+ }
+ }
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->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->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.
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ 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
+ 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.
+ d->releaseItem(d->currentItem);
+ 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::createdItem(int index, QFxItem *item)
+{
+ Q_D(QFxGridView);
+ item->setItemParent(this);
+ if (d->requestedIndex != index) {
+ item->setItemParent(this);
+ d->unrequestedItems.insert(item, index);
+ if (d->flow == QFxGridView::LeftToRight) {
+ item->setPos(QPointF(d->colPosAt(index), d->rowPosAt(index)));
+ } else {
+ item->setPos(QPointF(d->rowPosAt(index), d->colPosAt(index)));
+ }
+ }
+}
+
+void QFxGridView::destroyingItem(QFxItem *item)
+{
+ Q_D(QFxGridView);
+ d->unrequestedItems.remove(item);
+}
+
+
+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..1514451
--- /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 <QtDeclarative/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);
+
+ 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();
+ void createdItem(int index, QFxItem *item);
+ void destroyingItem(QFxItem *item);
+ void sizeChange();
+
+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..6bf3148
--- /dev/null
+++ b/src/declarative/fx/qfxhighlightfilter.cpp
@@ -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$
+**
+****************************************************************************/
+
+#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()
+ : xOffset(0), yOffset(0), tiled(false) {}
+
+ 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
+
+ \qml
+Text {
+ id: highlighttext
+ color: "red"
+ font.size: 32
+ text: "Highlight"
+ filter: Highlight {
+ source: "pics/highlight.png"
+ xOffset: NumericAnimation {
+ running: true
+ repeat: true
+ from: 320
+ to: -320
+ duration: 2000
+ }
+ }
+}
+ \endqml
+ \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 group_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::source
+ This property holds the URL of the image to be used as the highlight.
+*/
+
+/*!
+ \property QFxHighlightFilter::source
+ \brief the URL of the image to be used as the highlight.
+*/
+QString QFxHighlightFilter::source() const
+{
+ return d->source;
+}
+
+void QFxHighlightFilter::imageLoaded()
+{
+ QPixmap img = QFxPixmap(d->url);
+#if defined(QFX_RENDER_OPENGL2)
+ if (!img.isNull())
+ d->tex.setImage(img.toImage());
+#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);
+ d->source = f;
+ d->url = qmlContext(this)->resolvedUrl(f);
+#if defined(QFX_RENDER_OPENGL2)
+ d->tex.clear();
+#endif
+ if (!f.isEmpty())
+ QFxPixmap::get(qmlEngine(this), 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..19e95ac
--- /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 <QtDeclarative/qsimplecanvasfilter.h>
+#include <QtDeclarative/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 source 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..22e5d97
--- /dev/null
+++ b/src/declarative/fx/qfximage.cpp
@@ -0,0 +1,1015 @@
+/****************************************************************************
+**
+** 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
+ \qml
+ Image { source: "pics/qtlogo.png" }
+ \endqml
+ \row
+ \o \image declarative-qtlogo2.png
+ \o Stretched
+ \qml
+ Image { width: 160; height: 160; source: "pics/qtlogo.png" }
+ \endqml
+ \row
+ \o \image declarative-qtlogo4.png
+ \o Grid-scaled
+ \qml
+ Image { scaleGrid.left: 20; scaleGrid.right: 10
+ scaleGrid.top: 14; scaleGrid.bottom: 14
+ width: 160; height: 160; source: "pics/qtlogo.png" }
+ \endqml
+ \row
+ \o \image declarative-qtlogo3.png
+ \o Tiled
+ \qml
+ Image { tile: true; width: 160; height: 160; source: "pics/qtlogo.png" }
+ \endqml
+ \endtable
+ */
+
+/*!
+ \internal
+ \class QFxImage Image
+ \brief The QFxImage class provides an image item that you can add to a QFxView.
+
+ \ingroup group_coreitems
+
+ Example:
+ \qml
+ Image { source: "pics/star.png" }
+ \endqml
+
+ 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->sciReply)
+ d->sciReply->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 source property will be unset. This property is intended
+ to be used only in C++, not in QML.
+*/
+QPixmap QFxImage::pixmap() const
+{
+ Q_D(const QFxImage);
+ return d->_pix;
+}
+
+void QFxImage::setPixmap(const QPixmap &pix)
+{
+ Q_D(QFxImage);
+ d->url = QUrl();
+ d->_pix = pix;
+ d->_opaque=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 {Image::source}{.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.
+
+ \qml
+ Item {
+ Image { source: "tile.png" }
+ Image { x: 80; width: 100; height: 100; source: "tile.png" }
+ Image { x: 190; width: 100; height: 100; tile: true; source: "tile.png" }
+ }
+ \endqml
+ \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;
+ 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;
+
+ QPainter::RenderHints oldHints = p.renderHints();
+ if (d->_smooth)
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->_smooth);
+
+ QPixmap 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 = pix.width();
+ int ph = pix.height();
+ int yy = 0;
+
+ while(yy < height()) {
+ int xx = 0;
+ while(xx < width()) {
+ p.drawPixmap(xx, yy, 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.drawPixmap(0, 0, pix);
+ p.setWorldTransform(old);
+ } else {
+ p.drawPixmap(0, 0, pix);
+ }
+ } else {
+ int sgl = d->_scaleGrid->left();
+ int sgr = d->_scaleGrid->right();
+ int sgt = d->_scaleGrid->top();
+ int sgb = d->_scaleGrid->bottom();
+
+ int w = width();
+ int h = height();
+ if (sgt + sgb > h)
+ sgt = sgb = h/2;
+ if (sgl + sgr > w)
+ sgl = sgr = w/2;
+
+ const int xSide = sgl + sgr;
+ const int ySide = sgt + sgb;
+
+ // Upper left
+ if (sgt && sgl)
+ p.drawPixmap(QRect(0, 0, sgl, sgt), pix, QRect(0, 0, sgl, sgt));
+ // Upper middle
+ if (pix.width() - xSide && sgt)
+ p.drawPixmap(QRect(sgl, 0, w - xSide, sgt), pix,
+ QRect(sgl, 0, pix.width() - xSide, sgt));
+ // Upper right
+ if (sgt && pix.width() - sgr)
+ p.drawPixmap(QPoint(w-sgr, 0), pix,
+ QRect(pix.width()-sgr, 0, sgr, sgt));
+ // Middle left
+ if (sgl && pix.height() - ySide)
+ p.drawPixmap(QRect(0, sgt, sgl, h - ySide), pix,
+ QRect(0, sgt, sgl, pix.height() - ySide));
+
+ // Middle
+ if (pix.width() - xSide && pix.height() - ySide)
+ p.drawPixmap(QRect(sgl, sgt, w - xSide, h - ySide),
+ pix,
+ QRect(sgl, sgt, pix.width() - xSide, pix.height() - ySide));
+ // Middle right
+ if (sgr && pix.height() - ySide)
+ p.drawPixmap(QRect(w-sgr, sgt, sgr, h - ySide), pix,
+ QRect(pix.width()-sgr, sgt, sgr, pix.height() - ySide));
+ // Lower left
+ if (sgl && sgr)
+ p.drawPixmap(QPoint(0, h - sgb), pix,
+ QRect(0, pix.height() - sgb, sgl, sgb));
+ // Lower Middle
+ if (pix.width() - xSide && sgb)
+ p.drawPixmap(QRect(sgl, h - sgb, w - xSide, sgb), pix,
+ QRect(sgl, pix.height() - sgb, pix.width() - xSide, sgb));
+ // Lower Right
+ if (sgr && sgb)
+ p.drawPixmap(QPoint(w-sgr, h - sgb), pix,
+ QRect(pix.width()-sgr, pix.height() - sgb, sgr, sgb));
+ }
+
+ if (d->_smooth)
+ p.setRenderHints(oldHints);
+}
+#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.toImage());
+ _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();
+}
+
+/*!
+ \qmlproperty enum Image::status
+
+ This property holds the status of image loading. It can be one of:
+ \list
+ \o Idle - no image has been set, or the image has been loaded
+ \o Loading - the images is currently being loaded
+ \o Error - an error occurred while loading the image
+ \endlist
+
+ \sa progress
+*/
+
+QFxImage::Status QFxImage::status() const
+{
+ Q_D(const QFxImage);
+ return d->status;
+}
+
+/*!
+ \qmlproperty real Image::progress
+
+ This property holds the progress of image loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
+
+qreal QFxImage::progress() const
+{
+ Q_D(const QFxImage);
+ return d->progress;
+}
+
+/*!
+ \qmlproperty string Image::source
+
+ Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt.
+
+ 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 {Image::scaleGrid.left}{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::source
+ \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)
+{
+#ifdef Q_ENABLE_PERFORMANCE_LOG
+ QFxPerfTimer<QFxPerf::PixmapLoad> perf;
+#endif
+ Q_D(QFxImage);
+ if (url == d->source)
+ return;
+
+ if (d->sciReply) {
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ }
+
+ if (!d->url.isEmpty())
+ QFxPixmap::cancelGet(d->url, this);
+ if (!d->sciurl.isEmpty())
+ QFxPixmap::cancelGet(d->sciurl, this);
+
+ d->source = url;
+ d->url = qmlContext(this)->resolvedUrl(url);
+ d->sciurl = QUrl();
+ if (d->progress != 0.0) {
+ d->progress = 0.0;
+ emit progressChanged(d->progress);
+ }
+
+ if (url.isEmpty()) {
+ setPixmap(QPixmap());
+ d->status = Idle;
+ d->progress = 1.0;
+ setImplicitWidth(0);
+ setImplicitHeight(0);
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ emit statusChanged(d->status);
+ emit sourceChanged(d->source);
+ emit progressChanged(1.0);
+ update();
+ } 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->sciReply = qmlEngine(this)->networkAccessManager()->get(req);
+ QObject::connect(d->sciReply, SIGNAL(finished()),
+ this, SLOT(sciRequestFinished()));
+ }
+ } else {
+ d->reply = QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
+ }
+ }
+
+ emit statusChanged(d->status);
+}
+
+void QFxImage::requestFinished()
+{
+ Q_D(QFxImage);
+ if (d->url.path().endsWith(QLatin1String(".sci"))) {
+ d->_pix = QFxPixmap(d->sciurl);
+ } else {
+ if (d->reply) {
+ disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ if (d->reply->error() != QNetworkReply::NoError)
+ d->status = Error;
+ }
+ d->_pix = QFxPixmap(d->url);
+ setOptions(QFxImage::SimpleItem, true);
+ }
+ setImplicitWidth(d->_pix.width());
+ setImplicitHeight(d->_pix.height());
+
+ if (d->status == Loading)
+ d->status = Idle;
+ d->progress = 1.0;
+#if defined(QFX_RENDER_OPENGL)
+ d->_texDirty = true;
+ d->_tex.clear();
+#endif
+ emit statusChanged(d->status);
+ emit sourceChanged(d->source);
+ emit progressChanged(1.0);
+ update();
+}
+
+void QFxImage::sciRequestFinished()
+{
+ Q_D(QFxImage);
+ if (d->sciReply->error() != QNetworkReply::NoError) {
+ d->status = Error;
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ emit statusChanged(d->status);
+ } else {
+ QFxGridScaledImage sci(d->sciReply);
+ d->sciReply->deleteLater();
+ d->sciReply = 0;
+ setGridScaledImage(sci);
+ }
+}
+
+void QFxImage::requestProgress(qint64 received, qint64 total)
+{
+ Q_D(QFxImage);
+ if (d->status == Loading && total > 0) {
+ d->progress = qreal(received)/total;
+ emit progressChanged(d->progress);
+ }
+}
+
+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()));
+ d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished()));
+ if (d->reply) {
+ connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
+ this, SLOT(requestProgress(qint64,qint64)));
+ } else {
+ d->progress = 1.0;
+ emit progressChanged(d->progress);
+ }
+ 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..4d5f134
--- /dev/null
+++ b/src/declarative/fx/qfximage.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QFXIMAGE_H
+#define QFXIMAGE_H
+
+#include <QtDeclarative/qfxitem.h>
+#include <QtNetwork/qnetworkreply.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 source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
+
+ 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;
+ qreal progress() 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);
+ void progressChanged(qreal progress);
+
+protected:
+ QFxImage(QFxImagePrivate &dd, QFxItem *parent);
+ virtual void componentComplete();
+
+private Q_SLOTS:
+ void requestFinished();
+ void sciRequestFinished();
+ void requestProgress(qint64,qint64);
+
+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..b3cccf9
--- /dev/null
+++ b/src/declarative/fx/qfximage_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** 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), sciReply(0), progress(0.0)
+ {
+ }
+
+ ~QFxImagePrivate()
+ {
+ delete _scaleGrid;
+ }
+
+ void setContent(QIODevice* dev, const QString &url);
+
+ QFxScaleGrid *scaleGrid()
+ {
+ if (!_scaleGrid)
+ _scaleGrid = new QFxScaleGrid;
+ return _scaleGrid;
+ }
+
+ QFxScaleGrid *_scaleGrid;
+ QPixmap _pix;
+ bool _tiled : 1;
+ bool _smooth : 1;
+ bool _opaque : 1;
+#if defined(QFX_RENDER_OPENGL)
+ void checkDirty();
+ bool _texDirty;
+ GLTexture _tex;
+#endif
+
+ QFxImage::Status status;
+ QString source;
+ QUrl url;
+ QUrl sciurl;
+ QNetworkReply *sciReply;
+ QPointer<QNetworkReply> reply;
+ qreal progress;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXIMAGE_P_H
diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp
new file mode 100644
index 0000000..7129757
--- /dev/null
+++ b/src/declarative/fx/qfxitem.cpp
@@ -0,0 +1,2100 @@
+/****************************************************************************
+**
+** 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 "qfxanchors_p.h"
+
+#include "qfxtransform.h"
+#include "qfxscalegrid.h"
+#include "qfxview.h"
+#include "qmlstategroup.h"
+
+#include "qfxitem_p.h"
+#include "qfxitem.h"
+#include "qfxevents_p.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)
+
+/*!
+ \group group_animation
+ \title Animation
+*/
+
+/*!
+ \group group_coreitems
+ \title Basic Items
+*/
+
+/*!
+ \group group_effects
+ \title Effects
+*/
+
+/*!
+ \group group_layouts
+ \title Layouts
+*/
+
+/*!
+ \group group_states
+ \title States and Transitions
+*/
+
+/*!
+ \group group_utility
+ \title Utility
+*/
+
+/*!
+ \group group_views
+ \title Views
+*/
+
+/*!
+ \group group_widgets
+ \title Widgets
+*/
+
+/*!
+ \internal
+ \class QFxContents
+ \ingroup group_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;
+
+ const QList<QSimpleCanvasItem *> &children = _item->QSimpleCanvasItem::children();
+ for (int i = 0; i < children.count(); ++i) {
+ const QSimpleCanvasItem *child = children.at(i);
+ int y = int(child->y());
+ if (y + child->height() > bottom)
+ bottom = y + child->height();
+ if (y < top)
+ top = 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;
+ const QList<QSimpleCanvasItem *> &children = _item->QSimpleCanvasItem::children();
+ for (int i = 0; i < children.count(); ++i) {
+ const QSimpleCanvasItem *child = children.at(i);
+ int x = int(child->x());
+ if (x + child->width() > right)
+ right = x + child->width();
+ if (x < left)
+ left = x;
+ }
+ _width = right - left;
+
+ if (_width != oldwidth)
+ emit widthChanged();
+}
+
+void QFxContents::setItem(QFxItem *item)
+{
+ _item = item;
+
+ const QList<QSimpleCanvasItem *> &children = _item->QSimpleCanvasItem::children();
+ for (int i = 0; i < children.count(); ++i) {
+ const QSimpleCanvasItem *child = children.at(i);
+ connect(child, SIGNAL(heightChanged()), this, SLOT(calcHeight()));
+ connect(child, SIGNAL(topChanged()), this, SLOT(calcHeight()));
+ connect(child, SIGNAL(widthChanged()), this, SLOT(calcWidth()));
+ connect(child, SIGNAL(leftChanged()), this, SLOT(calcWidth()));
+ }
+
+ calcHeight();
+ calcWidth();
+}
+
+/*!
+ \qmlclass Item QFxItem
+ \brief The Item is the most basic of all visual items in QML.
+ */
+
+/*!
+ \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 items in Qt Declarative inherit from QFxItem. Although QFxItem
+ has no visual appearance, it defines all the properties that are
+ common across visual items - like the x and y position, and the
+ width and height.
+
+ QFxItem is also useful for grouping items 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"
+ }
+ }
+ \endqml
+ \endqmltext
+
+ \ingroup group_coreitems
+*/
+
+/*!
+ \property QFxItem::activeFocus
+ This property indicates whether the item has the active focus.
+ */
+
+/*!
+ \fn void QFxItem::activeFocusChanged()
+
+ This signal is emitted when this item gains active focus.
+*/
+
+/*!
+ \fn void QFxItem::baselineOffsetChanged()
+
+ This signal is emitted when the baseline offset of the item
+ is changed.
+*/
+
+/*!
+ \fn void QFxItem::leftChanged()
+
+ This signal is emitted when the left coordinate of the item changes.
+*/
+
+/*!
+ \fn void QFxItem::topChanged()
+
+ This signal is emitted when the top 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
+*/
+
+/*!
+ \qmlsignal Item::onKeyPress(event)
+
+ This handler is called when a key is pressed.
+
+ The key event is available via the KeyEvent \a event.
+
+ \qml
+ Item {
+ onKeyPress: { if (event.key == Qt.Key_Enter) state='Enter' }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlsignal Item::onKeyRelease(event)
+
+ This handler is called when a key is released.
+
+ The key event is available in via the KeyEvent \a event.
+
+ \qml
+ Item {
+ onKeyRelease: { if (event.key == Qt.Key_Enter) state='Enter' }
+ }
+ \endqml
+*/
+
+/*!
+ \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 QSimpleCanvasItem::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);
+ for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) {
+ QFxAnchors *anchor = d->dependantAnchors.at(ii);
+ anchor->d_func()->clearItem(this);
+ }
+ for (int ii = 0; ii < d->dependantAnchors.count(); ++ii) {
+ QFxAnchors *anchor = d->dependantAnchors.at(ii);
+ anchor->d_func()->updateOnComplete();
+ }
+ 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.
+ \qml
+ Image {
+ source: "myimage.png"
+ transformOrigin: "Center"
+ scale: 4
+ }
+ \endqml
+
+ The default transform origin is \c TopLeft.
+*/
+
+/*!
+ \qmlproperty Item Item::parent
+ This property holds the parent of the item.
+*/
+
+/*!
+ \property QFxItem::parent
+ This property holds the parent of the item.
+*/
+void QFxItem::setItemParent(QFxItem *parent)
+{
+ setParent(parent);
+}
+
+/*!
+ \internal
+ \property QFxItem::moveToParent
+ Playing around with view2view transitions.
+ */
+
+/*!
+ \internal
+ */
+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 item.
+ 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 {}
+ ]
+ resources: [
+ Component {
+ id: myComponent
+ Text {}
+ }
+ ]
+ }
+ \endqml
+*/
+
+/*!
+ \property QFxItem::children
+
+ This property contains the list of visual children of this item.
+*/
+
+/*!
+ \property QFxItem::resources
+
+ This property contains non-visual resources that you want to
+ reference by name.
+*/
+
+/*!
+ 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 item. If you assign a visual item 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 {}
+ }
+ \endqml
+
+ instead of:
+ \qml
+ Item {
+ children: [
+ Text {},
+ Rect {}
+ ]
+ resources: [
+ Script {}
+ ]
+ }
+ \endqml
+
+ data is a behind-the-scenes property: you should never need to explicitly
+ specify it.
+ */
+
+/*!
+ \property QFxItem::data
+
+ The data property is allows you to freely mix the visual children
+ and the non-visual resources of an item. If you assign a visual
+ item to the data list it becomes a child and if you assign any
+ other object type, it is added as a resource.
+
+ 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;
+}
+
+/*!
+ \internal
+ \property QFxItem::qmlItem
+*/
+
+/*! \fn QFxItem *QFxItem::qmlItem() const
+ \internal
+ */
+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.
+*/
+
+/*! \fn void QFxItem::qmlChanged()
+ This signal is emitted whenever the item's dynamic QML
+ string changes.
+
+ \sa setQml()
+ */
+
+/*!
+ \property QFxItem::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 = qmlContext(this)->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(qmlEngine(this), d->_qmlurl, this);
+ if (!d->_qmlcomp->isLoading())
+ qmlLoaded();
+ else
+ QObject::connect(d->_qmlcomp, SIGNAL(statusChanged(QmlComponent::Status)),
+ this, SLOT(qmlLoaded()));
+ }
+}
+
+/*! \fn void QFxItem::newChildCreated(const QString &url, QScriptValue v)
+ This signal is emitted with the \a url and the script value \a v,
+ when a new child is created.
+ */
+
+/*!
+ \internal
+ */
+void QFxItem::qmlLoaded()
+{
+ Q_D(QFxItem);
+
+ { // newChild...
+ // ###
+ for (int i=0; i<d->_qmlnewloading.length(); ++i) {
+ QmlComponent *c = d->_qmlnewcomp.at(i);
+ if (c->isLoading())
+ continue;
+
+ QmlContext *ctxt = new QmlContext(qmlContext(this));
+ QObject* o = c ? c->create(ctxt):0;
+ QFxItem* ret = qobject_cast<QFxItem*>(o);
+ if (ret) {
+ ret->setItemParent(this);
+ QScriptValue v = qmlEngine(this)->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(qmlContext(this));
+ 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 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
+ */
+
+/*!
+ \property QFxItem::width
+
+ Defines the item's width relative to its parent.
+ */
+
+/*!
+ \property QFxItem::height
+
+ Defines the item's height relative to its parent.
+ */
+
+/*!
+ \property QFxItem::x
+
+ The x coordinate of the item relative to its parent.
+*/
+
+/*!
+ \property QFxItem::y
+
+ The y coordinate of the item relative to its parent.
+*/
+
+/*!
+ \property QFxItem::z
+
+ The z coordinate of the item relative to its parent.
+
+ A negative z coordinate means the item will be painted below its parent.
+*/
+
+
+/*!
+ \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
+ }
+ }
+ \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
+ }
+ }
+ \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
+ }
+ }
+ }
+ \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
+ }
+ }
+ }
+ \endqml
+ \endtable
+ */
+
+/*!
+ This function is called to handle this item's changes in
+ geometry from \a oldGeometry to \a newGeometry. If the two
+ geometries are the same, it doesn't do anything.
+ */
+void QFxItem::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ Q_D(QFxItem);
+
+ if (d->_anchors)
+ d->_anchors->d_func()->updateMe();
+
+ if (newGeometry.size() != oldGeometry.size()) {
+ if (rotation() && transformOrigin() != QFxItem::TopLeft)
+ setRotation(rotation());
+ if (scale() && transformOrigin() != QFxItem::TopLeft)
+ setScale(scale());
+ }
+
+ if (newGeometry.x() != oldGeometry.x())
+ emit leftChanged();
+ if (newGeometry.width() != oldGeometry.width())
+ emit widthChanged();
+ if (newGeometry.y() != oldGeometry.y())
+ emit topChanged();
+ if (newGeometry.height() != oldGeometry.height())
+ emit heightChanged();
+
+ for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) {
+ QFxAnchors *anchor = d->dependantAnchors.at(ii);
+ anchor->d_func()->update(this, newGeometry, oldGeometry);
+ }
+}
+
+/*!
+ \qmlproperty bool Item::flipVertically
+ \qmlproperty bool Item::flipHorizontally
+
+ When set, the item will be displayed flipped horizontally or vertically
+ about its center.
+ */
+
+/*!
+ \property QFxItem::flipVertically
+
+ 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));
+}
+
+/*!
+ \property QFxItem::flipHorizontally
+
+ When set, the item will be displayed flipped horizontally or vertically
+ about its center.
+ */
+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));
+}
+
+/*! \fn void QFxItem::keyPress(QFxKeyEvent *event)
+ This signal is emitted by keyPressEvent() for the \a event.
+ */
+
+/*! \fn void QFxItem::keyRelease(QFxKeyEvent *event)
+ This signal is emitted by keyReleaseEvent() for the \a event.
+ */
+
+/*!
+ \reimp
+*/
+void QFxItem::keyPressEvent(QKeyEvent *event)
+{
+ QFxKeyEvent ke(*event);
+ emit keyPress(&ke);
+ event->setAccepted(ke.isAccepted());
+ if (itemParent() && !ke.isAccepted())
+ itemParent()->keyPressEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QFxItem::keyReleaseEvent(QKeyEvent *event)
+{
+ QFxKeyEvent ke(*event);
+ 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. The identifier must be unique in thecomponent.
+*/
+
+/*!
+ \property QFxItem::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 the \l {components}{component}
+ where it is declared. The identifier must be unique in thecomponent.
+*/
+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;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::left() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->left;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::right() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->right;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::horizontalCenter() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->hCenter;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::top() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->top;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::bottom() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->bottom;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::verticalCenter() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->vCenter;
+}
+
+/*!
+ \internal
+*/
+QFxAnchorLine QFxItem::baseline() const
+{
+ Q_D(const QFxItem);
+ return d->anchorLines()->baseline;
+}
+
+/*!
+ \property QFxItem::top
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QFxItem::bottom
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QFxItem::left
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QFxItem::right
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QFxItem::horizontalCenter
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \property QFxItem::verticalCenter
+
+ One of the anchor lines of the item.
+
+ For more information see \l {anchor-layout}{Anchor Layouts}.
+*/
+
+/*!
+ \qmlproperty AnchorLine Item::top
+ \qmlproperty AnchorLine Item::bottom
+ \qmlproperty AnchorLine Item::left
+ \qmlproperty AnchorLine Item::right
+ \qmlproperty AnchorLine Item::horizontalCenter
+ \qmlproperty AnchorLine Item::verticalCenter
+ \qmlproperty AnchorLine Item::baseline
+
+ 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 AnchorLine Item::anchors.baseline
+
+ \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::baselineOffset
+ \brief The position of the item's baseline in local 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 0 is used.
+*/
+int QFxItem::baselineOffset() const
+{
+ Q_D(const QFxItem);
+ if (!d->_baselineOffset.isValid()) {
+ return 0;
+ } else
+ return d->_baselineOffset;
+}
+
+/*!
+ \internal
+*/
+void QFxItem::setBaselineOffset(int offset)
+{
+ Q_D(QFxItem);
+ if (offset == d->_baselineOffset)
+ return;
+
+ d->_baselineOffset = offset;
+ emit baselineOffsetChanged();
+
+ for(int ii = 0; ii < d->dependantAnchors.count(); ++ii) {
+ QFxAnchors *anchor = d->dependantAnchors.at(ii);
+ anchor->d_func()->updateVerticalAnchors();
+ }
+}
+
+/*!
+ \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"
+ x: 25; y: 25; width: 50; height: 50
+ rotation: 30
+ }
+ }
+ \endqml
+ \endtable
+*/
+
+/*! \fn void QFxItem::rotationChanged()
+ This signal is emitted when the rotation property is changed.
+
+ \sa setRotation()
+ */
+
+/*!
+ \property QFxItem::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).
+*/
+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"
+ x: 25; y: 25; width: 50; height: 50
+ scale: 1.4
+ }
+ }
+ \endqml
+ \endtable
+*/
+
+/*!
+ \property QFxItem::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).
+*/
+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 (not yet available) 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
+ }
+ }
+ }
+ \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
+ }
+ }
+ }
+ \endqml
+ \endtable
+*/
+
+/*!
+ \property QFxItem::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.
+*/
+
+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();
+}
+
+/*!
+ Returns a value indicating whether the mouse should
+ remain with this item.
+ */
+bool QFxItem::keepMouseGrab() const
+{
+ Q_D(const QFxItem);
+ return d->_keepMouse;
+}
+
+/*!
+ The flag indicating whether the mouse should remain
+ with this item is set to \a keep.
+ */
+void QFxItem::setKeepMouseGrab(bool keep)
+{
+ Q_D(QFxItem);
+ d->_keepMouse = keep;
+}
+
+/*!
+ This function emits the \e activeFocusChanged signal.
+ \a flag is not used.
+ */
+void QFxItem::activeFocusChanged(bool flag)
+{
+ Q_UNUSED(flag);
+ emit activeFocusChanged();
+}
+
+/*!
+ This function emits the \e focusChanged signal.
+ \a flag is not used.
+ */
+void QFxItem::focusChanged(bool flag)
+{
+ Q_UNUSED(flag);
+ 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 { ... }
+ ...
+ ]
+ }
+ \endqml
+
+ \sa {states-transitions}{States and Transitions}
+*/
+
+/*!
+ \property QFxItem::states
+ This property holds a list of states defined by the item.
+
+ \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 { ... }
+ ...
+ ]
+ }
+ \endqml
+
+ \sa {states-transitions}{States and Transitions}
+*/
+
+/*!
+ \property QFxItem::transitions
+ This property holds a list of transitions defined by the item.
+
+ \sa {states-transitions}{States and Transitions}
+*/
+QmlList<QmlTransition *>* QFxItem::transitions()
+{
+ Q_D(QFxItem);
+ return d->states()->transitionsProperty();
+}
+
+/*!
+ \internal
+ \property QFxItem::filter
+*/
+
+/*!
+ \qmlproperty list<Filter> Item::filter
+ This property holds a list of graphical filters to be applied to the item.
+
+ \l {Filter}{Filters} include things like \l {Blur}{blurring}
+ the item, or giving it a \l 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 QML will still be considered valid).
+
+ \qml
+ Item {
+ filter: [
+ Blur { ... },
+ Relection { ... }
+ ...
+ ]
+ }
+ \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.
+*/
+
+/*!
+ \property QFxItem::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';
+ }
+ }
+ \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}
+*/
+
+/*!
+ \property QFxItem::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';
+ }
+ }
+ \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.
+*/
+
+/*!
+ \property QFxItem::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);
+}
+
+/*!
+ \property QFxItem::focus
+ This property holds the item's focus state.
+*/
+
+/*!
+ \property QFxItem::focusable
+ This property holds whether the item has focus state.
+*/
+
+/*!
+ 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;
+}
+
+/*!
+ \property QFxItem::visible
+
+ This property specifies whether the item is visible or invisible.
+
+ Setting visibility to false sets opacity to 0. Setting the
+ visibility to true restores the opacity to its previous value.
+
+ \sa isVisible()
+*/
+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)
+{
+ 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 = qmlContext(this)->resolvedUri(type);
+ if (url.isEmpty())
+ return;
+
+ d->_qmlnewloading.append(url);
+ d->_qmlnewcomp.append(new QmlComponent(qmlEngine(this), url, this));
+
+ if (!d->_qmlnewcomp.last()->isLoading())
+ qmlLoaded();
+ else
+ connect(d->_qmlnewcomp.last(), SIGNAL(statusChanged(QmlComponent::Status)),
+ 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::ItemComponentComplete> cc;
+#endif
+ Q_D(QFxItem);
+ d->_classComplete = true;
+ if (d->_stateGroup)
+ d->_stateGroup->classComplete();
+}
+
+/*!
+ componentComplete() is called when all items 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()->d_func()->updateOnComplete();
+ if (!d->_transform.isEmpty())
+ updateTransform();
+}
+
+/*! \internal
+*/
+void QFxItem::parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *)
+{
+ emit parentChanged();
+}
+
+/*! \internal
+*/
+void QFxItem::reparentItems()
+{
+ qFatal("EEK");
+}
+
+/*!
+ \internal
+*/
+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);
+}
+
+/*!
+ \internal
+*/
+void QFxItem::transformChanged(const QSimpleCanvas::Matrix &)
+{
+}
+
+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;
+ baseline.item = q;
+ baseline.anchorLine = QFxAnchorLine::Baseline;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h
new file mode 100644
index 0000000..8ca1f9e
--- /dev/null
+++ b/src/declarative/fx/qfxitem.h
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** 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 <QtCore/QObject>
+#include <QtScript/qscriptvalue.h>
+#include <QtCore/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 QmlState;
+class QmlTransition;
+class QFxTransform;
+class QFxKeyEvent;
+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(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(QFxAnchorLine baseline READ baseline)
+ 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 &);
+
+ bool flipVertically() const;
+ void setFlipVertically(bool);
+ bool flipHorizontally() const;
+ void setFlipHorizontally(bool);
+
+ int baselineOffset() const;
+ void setBaselineOffset(int);
+
+ 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);
+
+public Q_SLOTS:
+ void newChild(const QString &url);
+
+Q_SIGNALS:
+ void leftChanged();
+ void widthChanged();
+ void heightChanged();
+ void topChanged();
+ void baselineOffsetChanged();
+ void stateChanged(const QString &);
+ void focusChanged();
+ void activeFocusChanged();
+ void parentChanged();
+ void keyPress(QFxKeyEvent *event);
+ void keyRelease(QFxKeyEvent *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:
+ QFxAnchorLine left() const;
+ QFxAnchorLine right() const;
+ QFxAnchorLine horizontalCenter() const;
+ QFxAnchorLine top() const;
+ QFxAnchorLine bottom() const;
+ QFxAnchorLine verticalCenter() const;
+ QFxAnchorLine baseline() const;
+
+ void init(QFxItem *parent);
+ friend class QmlStatePrivate;
+ friend class QFxAnchors;
+ 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..a54f523
--- /dev/null
+++ b/src/declarative/fx/qfxitem_p.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/qfxitem.h>
+#include <private/qsimplecanvasitem_p.h>
+#include <private/qmlnullablevalue_p.h>
+#include <QtDeclarative/qml.h>
+#include <QtDeclarative/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);
+
+ if (parent)
+ q->setItemParent(parent);
+ _baselineOffset.invalidate();
+ q->setAcceptedMouseButtons(Qt::NoButton);
+ }
+
+ 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;
+ }
+ QList<QFxAnchors *> dependantAnchors;
+ 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;
+ QFxAnchorLine baseline;
+ };
+ 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;
+};
+
+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..4aae74f
--- /dev/null
+++ b/src/declarative/fx/qfxkeyactions.cpp
@@ -0,0 +1,920 @@
+/****************************************************************************
+**
+** 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 item 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 item has a collection of properties that correspond to a
+ selection of common keys. When a given key is pressed, the item executes
+ the action script assigned to the matching property. If no action has
+ been set the KeyActions item does nothing.
+
+ To receive (and susequently respond to) key presses, the KeyActions class
+ must be in the current focus chain, just like any other item.
+
+ For basic mouse handling, see \l MouseRegion.
+
+ KeyActions is an invisible item: 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 item 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...keyZ
+
+ The action to take for the given letter.
+
+ The following example sets actions for the 'c' and 'x' keys.
+ \qml
+ KeyActions { keyC: "print('c is for cookie')"; keyX: "print('I like cookies')" }
+ \endqml
+*/
+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.
+ \qml
+ KeyActions { leftArrow: "print('You pressed left')"; rightArrow: "print('You pressed right')" }
+ \endqml
+*/
+
+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...digit9
+
+ The action to take for the given number key.
+
+ The following example sets actions for the '5' and '6' keys.
+ \qml
+ KeyActions { digit5: "print('5 is a prime number')"; digit6: "print('6 is a composite number')"; focus: true }
+ \endqml
+*/
+
+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::keyReturn
+ \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.
+ \qml
+ KeyActions { space: "print('Space pressed')" }
+ \endqml
+*/
+
+/*!
+ \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.
+ \qml
+ KeyActions { hangup: "print('Go away now')" }
+ \endqml
+*/
+
+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(qmlContext(this), d->action(key), this);
+ 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..cea992a
--- /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 <QtCore/QObject>
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qml.h>
+#include <QtDeclarative/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..e80f2c7
--- /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 item proxies key presses to a number of other items.
+ \inherits Item
+
+*/
+
+/*!
+ \internal
+ \class QFxKeyProxy
+ \brief The QFxKeyProxy class proxies key presses to a number of other items.
+ \ingroup group_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 = canvas()->focusItem(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 = canvas()->focusItem(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..38cff7a
--- /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 <QtDeclarative/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..a975778
--- /dev/null
+++ b/src/declarative/fx/qfxlayouts.cpp
@@ -0,0 +1,1082 @@
+/****************************************************************************
+**
+** 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 group_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.
+
+ \qml
+BaseLayout {
+ id: layout
+ y: 0
+ move: Transition {
+ NumericAnimation {
+ properties: "y"
+ ease: "easeOutBounce"
+ }
+ }
+}
+ \endqml
+*/
+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.
+
+ \qml
+BaseLayout {
+ id: layout
+ y: 0
+ add: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 0
+ to: 1
+ duration: 500
+ }
+ }
+}
+ \endqml
+*/
+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.
+ \qml
+BaseLayout {
+ id: layout
+ y: 0
+ remove: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 1
+ to: 0
+ duration: 500
+ }
+ }
+}
+ \endqml
+*/
+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);
+ QPointF p(item->x(), item->y());
+ if(d->aut & Horizontal)
+ p.setX(p.x() + d->_margin);
+ if(d->aut & Vertical)
+ p.setY(p.y() + d->_margin);
+ item->setPos(p);
+ 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 if (itemParent())
+ setImplicitWidth(itemParent()->width());
+ if (d->aut & Vertical)
+ setHeight(int(height));
+ else if (itemParent())
+ 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 item arranges its children in a vertical layout.
+ \inherits Item
+
+ The VerticalLayout item arranges its child items 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
+ \qml
+VerticalLayout {
+ spacing: 2
+ Rect { color: "red"; width: 50; height: 50 }
+ Rect { color: "green"; width: 20; height: 50 }
+ Rect { color: "blue"; width: 50; height: 20 }
+}
+ \endqml
+ \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 items 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 items which have their opacity set to or from zero so as to appear or disappear.
+
+ \table
+ \row
+ \o \image verticalLayout_transition.gif
+ \o
+ \qml
+VerticalLayout {
+ spacing: 2
+ remove: ...
+ add: ...
+ move: ...
+ ...
+}
+ \endqml
+ \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
+ \qml
+VerticalLayout {
+ id: layout
+ remove: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 1
+ to: 0
+ duration: 500
+ }
+ }
+}
+ \endqml
+ \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
+ \qml
+VerticalLayout {
+ id: layout
+ add: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 0
+ to: 1
+ duration: 500
+ }
+ }
+}
+ \endqml
+ \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
+ \qml
+VerticalLayout {
+ id: layout
+ move: Transition {
+ NumericAnimation {
+ properties: "y"
+ ease: "easeOutBounce"
+ }
+ }
+}
+ \endqml
+ \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 group_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);
+ }
+ voffset += child->height();
+ voffset += spacing();
+ }
+ setMovingItem(this);
+ setHeight(voffset);
+ setMovingItem(0);
+}
+
+QML_DEFINE_TYPE(QFxHorizontalLayout,HorizontalLayout)
+/*!
+ \qmlclass HorizontalLayout
+ \brief The HorizontalLayout item arranges its children in a horizontal layout.
+ \inherits Item
+
+ The HorizontalLayout item arranges its child items 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 items 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 items 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.
+ \qml
+HorizontalLayout {
+ spacing: 2
+ Rect { color: "red"; width: 50; height: 50 }
+ Rect { color: "green"; width: 20; height: 50 }
+ Rect { color: "blue"; width: 50; height: 20 }
+}
+ \endqml
+ \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.
+
+ \qml
+HorizontalLayout {
+ id: layout
+ remove: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 1
+ to: 0
+ duration: 500
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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.
+
+ \qml
+HorizontalLayout {
+ id: layout
+ add: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 0
+ to: 1
+ duration: 500
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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.
+
+ \qml
+HorizontalLayout {
+ id: layout
+ move: Transition {
+ NumericAnimation {
+ properties: "x"
+ ease: "easeOutBounce"
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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 group_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);
+ }
+ hoffset += child->width();
+ hoffset += spacing();
+ }
+ setWidth(hoffset);
+}
+
+QML_DEFINE_TYPE(QFxGridLayout,GridLayout)
+
+/*!
+ \qmlclass GridLayout QFxGridLayout
+ \brief The GridLayout item arranges its children in a grid layout.
+ \inherits Item
+
+ The GridLayout item arranges its child items 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 items 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 items 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 items. 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
+ \qml
+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 }
+}
+ \endqml
+ \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.
+
+ \qml
+GridLayout {
+ id: layout
+ remove: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 1
+ to: 0
+ duration: 500
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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.
+
+ \qml
+GridLayout {
+ id: layout
+ add: Transition {
+ NumericAnimation {
+ target: layout.item
+ properties: "opacity"
+ from: 0
+ to: 1
+ duration: 500
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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.
+
+ \qml
+GridLayout {
+ id: layout
+ move: Transition {
+ NumericAnimation {
+ properties: "x,y"
+ ease: "easeOutBounce"
+ }
+ }
+}
+ \endqml
+
+*/
+/*!
+ \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 group_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..b119d6f
--- /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 <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtDeclarative/qfxitem.h>
+#include <QtDeclarative/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..77b0ea1
--- /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 <private/qfxitem_p.h>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+#include <QtDeclarative/qfxlayouts.h>
+#include <QtDeclarative/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..432c6ac
--- /dev/null
+++ b/src/declarative/fx/qfxlistview.cpp
@@ -0,0 +1,1649 @@
+/****************************************************************************
+**
+** 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 "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) {
+ QFxListViewAttached *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QFxListViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+ }
+
+ 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), requestedIndex(-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 *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
+ }
+
+ bool mapRangeFromModel(int &index, int &count) const {
+ if (index + count < visibleIndex)
+ return false;
+
+ int lastIndex = -1;
+ for (int i = visibleItems.count()-1; i >= 0; --i) {
+ FxListItem *listItem = visibleItems.at(i);
+ if (listItem->index != -1) {
+ lastIndex = listItem->index;
+ break;
+ }
+ }
+
+ if (index > lastIndex)
+ return false;
+
+ int last = qMin(index + count - 1, lastIndex);
+ index = qMax(index, visibleIndex);
+ count = last - index + 1;
+
+ return true;
+ }
+
+ // 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 updateUnrequestedIndexes();
+ void updateUnrequestedPositions();
+ 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;
+ QHash<QFxItem*,int> unrequestedItems;
+ FxListItem *currentItem;
+ QFxItem *tmpCurrent;
+ Qt::Orientation orient;
+ int visiblePos;
+ int visibleIndex;
+ qreal averageSize;
+ int currentIndex;
+ int requestedIndex;
+ 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);
+ QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(refill()));
+ QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(refill()));
+}
+
+void QFxListViewPrivate::clear()
+{
+ for (int i = 0; i < visibleItems.count(); ++i)
+ releaseItem(visibleItems.at(i));
+ visibleItems.clear();
+ visiblePos = 0;
+ visibleIndex = 0;
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = -1;
+ createHighlight();
+ trackedItem = 0;
+}
+
+FxListItem *QFxListViewPrivate::createItem(int modelIndex)
+{
+ Q_Q(QFxListView);
+ // create object
+ requestedIndex = modelIndex;
+ 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(qmlContext(listItem->item), 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()));
+ }
+ requestedIndex = -1;
+
+ return listItem;
+}
+
+void QFxListViewPrivate::releaseItem(FxListItem *item)
+{
+ Q_Q(QFxListView);
+ if (!item)
+ return;
+ 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;
+ }
+ if (model->release(item->item) == 0) {
+ // item was not destroyed, and we no longer reference it.
+ unrequestedItems.insert(item->item, model->indexOf(item->item, q));
+ }
+ 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;
+ if (!(item = createItem(modelIndex)))
+ break;
+ item->setPosition(pos);
+ pos += item->size();
+ visibleItems.append(item);
+ ++modelIndex;
+ changed = true;
+ }
+ while (visibleIndex > 0 && visibleIndex <= model->count() && visiblePos > from) {
+ //qDebug() << "refill: prepend item" << visibleIndex-1 << "current top pos" << visiblePos;
+ if (!(item = createItem(visibleIndex-1)))
+ break;
+ --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());
+ }
+ updateUnrequestedPositions();
+}
+
+void QFxListViewPrivate::updateUnrequestedIndexes()
+{
+ Q_Q(QFxListView);
+ QHash<QFxItem*,int>::iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it)
+ *it = model->indexOf(it.key(), q);
+}
+
+void QFxListViewPrivate::updateUnrequestedPositions()
+{
+ QHash<QFxItem*,int>::const_iterator it;
+ for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) {
+ if (visibleItem(*it))
+ continue;
+ if (orient == Qt::Vertical)
+ it.key()->setY(positionAt(*it));
+ else
+ it.key()->setX(positionAt(*it));
+ }
+}
+
+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(qmlContext(q));
+ 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) {
+ currentItem->attached->setIsCurrentItem(false);
+ releaseItem(currentItem);
+ currentItem = 0;
+ currentIndex = -1;
+ updateHighlight();
+ emit q->currentIndexChanged();
+ }
+ return;
+ }
+
+ if (currentItem && currentIndex == modelIndex) {
+ updateHighlight();
+ return;
+ }
+
+ if (tmpCurrent) {
+ delete tmpCurrent;
+ tmpCurrent = 0;
+ }
+ FxListItem *oldCurrentItem = currentItem;
+ currentIndex = modelIndex;
+ currentItem = createItem(modelIndex);
+ fixCurrentVisibility = true;
+ if (oldCurrentItem && (!currentItem || oldCurrentItem->item != currentItem->item))
+ oldCurrentItem->attached->setIsCurrentItem(false);
+ if (currentItem) {
+ 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));
+ }
+ currentItem->item->setFocus(true);
+ currentItem->attached->setIsCurrentItem(true);
+ }
+ updateHighlight();
+ emit q->currentIndexChanged();
+ // Release the old current item
+ 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), QEasingCurve(QEasingCurve::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), QEasingCurve(QEasingCurve::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), QEasingCurve(QEasingCurve::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), QEasingCurve(QEasingCurve::InOutQuad), 200);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+
+/*!
+ \qmlclass ListView
+ \inherits Flickable
+ \brief The ListView item 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 QML.
+ The items are laid out vertically or horizontally and may be flicked to scroll.
+
+ The below example creates a very simple vertical list, using a QML model.
+ \image trivialListView.png
+
+ The user interface defines a delegate to display an item, a highlight,
+ and the ListView which uses the above.
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml 3
+
+ The model is defined as a ListModel using QML:
+ \quotefile doc/src/snippets/declarative/listview/dummydata/ContactModel.qml
+
+ In this case ListModel is a handy way for us to test our UI. In practice
+ the model would be implemented in C++, or perhaps via a SQL data source.
+*/
+
+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
+ {QAbstractItemModel} subclass, a VisualModel, or a simple list.
+
+ Models can also be created directly in QML, using a \l{ListModel}.
+*/
+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)));
+ disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ disconnect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*)));
+ }
+ 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(qmlContext(this));
+ 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)));
+ connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ connect(d->model, SIGNAL(destroyingItem(QFxItem*)), this, SLOT(destroyingItem(QFxItem*)));
+ 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:
+ \snippet doc/src/snippets/declarative/listview/listview.qml 0
+*/
+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(qmlContext(this));
+ 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.
+
+ \snippet doc/src/snippets/declarative/listview/listview.qml 1
+ \image trivialListView.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. The following example creates a highlight with
+ its motion defined by the spring \l {Follow}:
+
+ \snippet doc/src/snippets/declarative/listview/highlight.qml 1
+
+ \sa highlight
+*/
+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 - For mouse, the current item may be positioned anywhere,
+ whether within the visible area, or outside. During keyboard interaction,
+ the current item will be kept in the visible area and will prefer to be
+ positioned at the \l snapPosition, however the view will never scroll
+ beyond the beginning or end of the view.
+ \i SnapAuto - For both mouse and keyboard, the current item will be
+ kept at the \l {snapPosition}. Additionally, if the view is dragged or
+ flicked, the current item will be automatically updated to be the item
+ currently at the snapPosition.
+ \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 Vertical (default) and \c Horizontal.
+
+ Vertical Example:
+ \image trivialListView.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 ListView.section and
+ \c ListView.prevSection. These may be used to place a section header for
+ related items. The example below assumes that the model is sorted by size of
+ pet. The section expression is the size property. If \c ListView.section and
+ \c ListView.prevSection differ, the item will display a section header.
+
+ \snippet examples/declarative/listview/sections.qml 0
+
+ \image ListViewSections.png
+*/
+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;
+}
+
+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);
+ d->updateUnrequestedIndexes();
+ if (!d->visibleItems.count() || d->model->count() <= 1) {
+ d->layout();
+ d->updateCurrent(qMax(0, qMin(d->currentIndex, d->model->count()-1)));
+ emit countChanged();
+ return;
+ }
+
+ if (!d->mapRangeFromModel(modelIndex, count)) {
+ 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.
+ modelIndex = 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->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 index = modelIndex - 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 < count && 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);
+ listItem->setPosition(listItem->position() + (pos - initialPos));
+ if (listItem->index != -1)
+ listItem->index += count;
+ }
+ }
+ // everything is in order now - emit add() signal
+ for (int j = 0; j < added.count(); ++j)
+ added.at(j)->attached->emitAdd();
+ d->updateUnrequestedPositions();
+ emit countChanged();
+}
+
+void QFxListView::itemsRemoved(int modelIndex, int count)
+{
+ Q_D(QFxListView);
+ d->updateUnrequestedIndexes();
+ if (!d->mapRangeFromModel(modelIndex, count)) {
+ 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->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.
+ d->releaseItem(d->currentItem);
+ d->currentItem = 0;
+ d->currentIndex = -1;
+ d->updateCurrent(qMin(modelIndex, d->model->count()-1));
+ }
+ d->layout();
+ 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
+ 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.
+ d->releaseItem(d->currentItem);
+ 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->visiblePos = 0;
+ d->_tl.clear();
+ 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();
+}
+
+void QFxListView::createdItem(int index, QFxItem *item)
+{
+ Q_D(QFxListView);
+ if (d->requestedIndex != index) {
+ item->setItemParent(viewport());
+ d->unrequestedItems.insert(item, index);
+ if (d->orient == Qt::Vertical)
+ item->setY(d->positionAt(index));
+ else
+ item->setX(d->positionAt(index));
+ }
+}
+
+void QFxListView::destroyingItem(QFxItem *item)
+{
+ Q_D(QFxListView);
+ d->unrequestedItems.remove(item);
+}
+
+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..5dfb0e4
--- /dev/null
+++ b/src/declarative/fx/qfxlistview.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/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;
+
+ 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 Q_SLOTS:
+ void refill();
+ void trackedPositionChanged();
+ void itemResized();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void destroyRemoved();
+ void createdItem(int index, QFxItem *item);
+ void destroyingItem(QFxItem *item);
+};
+
+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..6eb358b
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion.cpp
@@ -0,0 +1,580 @@
+/****************************************************************************
+**
+** 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 "qfxevents_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 item enables simple mouse handling.
+ \inherits Item
+
+ A MouseRegion is typically used in conjunction with a visible item,
+ where the MouseRegion effectively 'proxies' mouse handling for that
+ item. For example, we can put a MouseRegion in a Rect that changes
+ the Rect color to red when clicked:
+ \snippet doc/src/snippets/declarative/mouseregion.qml 0
+
+ Many MouseRegion signals pass a \l {MouseEvent}{mouse} parameter that contains
+ additional information about the mouse event, such as the position, button,
+ and any key modifiers.
+
+ Below we have the previous
+ example extended so as to give a different color when you right click.
+ \snippet doc/src/snippets/declarative/mouseregion.qml 1
+
+ For basic key handling, see \l KeyActions.
+
+ MouseRegion is an invisible item: it is never painted.
+
+ \sa MouseEvent
+*/
+
+/*!
+ \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::onPositionChanged(mouse)
+
+ This handler is called when the mouse position changes.
+
+ The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
+ position, and any buttons currently pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onClicked(mouse)
+
+ 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 \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click wasHeld.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressed(mouse)
+
+ This handler is called when there is a press.
+ The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ position and which button was pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onReleased(mouse)
+
+ This handler is called when there is a release.
+ The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click wasHeld.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onPressAndHold(mouse)
+
+ This handler is called when there is a long press (currently 800ms).
+ The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ position of the press, and which button is pressed.
+*/
+
+/*!
+ \qmlsignal MouseRegion::onDoubleClicked(mouse)
+
+ This handler is called when there is a double-click (a press followed by a release followed by a press).
+ The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
+ position of the release of the click, and whether the click wasHeld.
+*/
+
+QML_DEFINE_TYPE(QFxMouseRegion,MouseRegion)
+
+/*!
+ \internal
+ \class QFxMouseRegion
+ \brief The QFxMouseRegion class provides a simple mouse handling abstraction for use within Qml.
+
+ \ingroup group_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 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->saveEvent(event);
+ 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);
+ setPressed(true);
+ event->accept();
+ }
+}
+
+void QFxMouseRegion::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if (!d->absorb) {
+ QFxItem::mouseMoveEvent(event);
+ return;
+ }
+
+ d->saveEvent(event);
+
+ // ### 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;
+ QFxMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ emit positionChanged(&me);
+ event->accept();
+}
+
+
+void QFxMouseRegion::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxMouseRegion);
+ if (!d->absorb)
+ QFxItem::mouseReleaseEvent(event);
+ else {
+ d->saveEvent(event);
+ 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();
+ d->saveEvent(event);
+ setPressed(true);
+ QFxMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
+ emit this->doubleClicked(&me);
+ 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;
+ QFxMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
+ emit pressAndHold(&me);
+ }
+ }
+}
+
+/*!
+ \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;
+ QFxMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
+ if (d->pressed) {
+ emit positionChanged(&me);
+ emit pressed(&me);
+ } else {
+ emit released(&me);
+ if (isclick)
+ emit clicked(&me);
+ }
+
+ 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 reduce the opacity of an image as it moves to the right:
+ \snippet doc/src/snippets/declarative/drag.qml 0
+*/
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxmouseregion.h b/src/declarative/fx/qfxmouseregion.h
new file mode 100644
index 0000000..d7db1dc
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/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 QFxMouseEvent;
+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(QFxMouseEvent *mouse);
+
+ void pressed(QFxMouseEvent *mouse);
+ void pressAndHold(QFxMouseEvent *mouse);
+ void released(QFxMouseEvent *mouse);
+ void clicked(QFxMouseEvent *mouse);
+ void doubleClicked(QFxMouseEvent *mouse);
+ 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..e444bf2
--- /dev/null
+++ b/src/declarative/fx/qfxmouseregion_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** 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 "qgraphicssceneevent.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(false), drag(0)
+ {
+ }
+
+ void init()
+ {
+ Q_Q(QFxMouseRegion);
+ q->setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
+ q->setOptions(QSimpleCanvasItem::HoverEvents | QSimpleCanvasItem::MouseEvents);
+ }
+
+ void saveEvent(QGraphicsSceneMouseEvent *event) {
+ lastPos = event->pos();
+ lastButton = event->button();
+ lastButtons = event->buttons();
+ lastModifiers = event->modifiers();
+ }
+
+ bool absorb : 1;
+ bool hovered : 1;
+ bool inside : 1;
+ bool pressed : 1;
+ bool longPress : 1;
+ bool moved : 1;
+ bool dragX : 1;
+ bool dragY : 1;
+ bool dragged : 1;
+ QFxDrag drag;
+ QPointF start;
+ QPointF startScene;
+ int startX;
+ int startY;
+ QPointF lastPos;
+ Qt::MouseButton lastButton;
+ Qt::MouseButtons lastButtons;
+ Qt::KeyboardModifiers lastModifiers;
+ QBasicTimer pressAndHoldTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QFXMOUSEREGION_P_H
diff --git a/src/declarative/fx/qfxpainteditem.cpp b/src/declarative/fx/qfxpainteditem.cpp
new file mode 100644
index 0000000..44adba7
--- /dev/null
+++ b/src/declarative/fx/qfxpainteditem.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** 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 "qfxpainteditem.h"
+#include "qfxpainteditem_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 QFxPaintedItem
+ \brief The QFxPaintedItem class is an abstract base class for QFxView items that want cached painting.
+ \ingroup group_coreitems
+
+ This is a convenience class for implementing items that paint their contents
+ using a QPainter. 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 QFxPaintedItem, you must reimplement drawContents() to draw
+ the contents of the item.
+*/
+
+/*!
+ \fn void QFxPaintedItem::drawContents(QPainter *painter, const QRect &rect)
+
+ This function is called when the cache needs to be refreshed. When
+ sub-classing QFxPaintedItem 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 QFxPaintedItem::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 QFxPaintedItem::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 QFxPaintedItem::dirtyCache(const QRect& rect)
+{
+ Q_D(QFxPaintedItem);
+ 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 QFxPaintedItem::clearCache()
+{
+ Q_D(QFxPaintedItem);
+ qDeleteAll(d->imagecache);
+ d->imagecache.clear();
+}
+
+/*!
+ Returns if smooth scaling of the cache contents is enabled.
+
+ \sa setSmooth()
+*/
+bool QFxPaintedItem::isSmooth() const
+{
+ Q_D(const QFxPaintedItem);
+ return d->smooth;
+}
+
+/*!
+ Returns the size of the contents.
+
+ \sa setContentsSize()
+*/
+QSize QFxPaintedItem::contentsSize() const
+{
+ Q_D(const QFxPaintedItem);
+ return d->contentsSize;
+}
+
+/*!
+ If \a smooth is true sets the image item to enable smooth scaling of
+ the cache contents.
+
+ \sa isSmooth()
+*/
+void QFxPaintedItem::setSmooth(bool smooth)
+{
+ Q_D(QFxPaintedItem);
+ if (d->smooth == smooth) return;
+ d->smooth = smooth;
+ clearCache();
+ update();
+}
+
+/*!
+ Sets the size of the contents to the given \a size.
+
+ \sa contentsSize()
+*/
+void QFxPaintedItem::setContentsSize(const QSize &size)
+{
+ Q_D(QFxPaintedItem);
+ if (d->contentsSize == size) return;
+ d->contentsSize = size;
+ clearCache();
+ update();
+}
+
+/*!
+ Constructs a new QFxPaintedItem with the given \a parent.
+*/
+QFxPaintedItem::QFxPaintedItem(QFxItem *parent)
+ : QFxItem(*(new QFxPaintedItemPrivate), parent)
+{
+ init();
+}
+
+/*!
+ \internal
+ Constructs a new QFxPaintedItem with the given \a parent and
+ initialized private data member \a dd.
+*/
+QFxPaintedItem::QFxPaintedItem(QFxPaintedItemPrivate &dd, QFxItem *parent)
+ : QFxItem(dd, parent)
+{
+ init();
+}
+
+/*!
+ Destroys the image item.
+*/
+QFxPaintedItem::~QFxPaintedItem()
+{
+}
+
+/*!
+ \internal
+*/
+void QFxPaintedItem::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 QFxPaintedItem::paintContents(QPainter &p)
+#elif defined(QFX_RENDER_OPENGL)
+/*!
+ \reimp
+*/
+void QFxPaintedItem::paintGLContents(GLPainter &p)
+#else
+#error "What render?"
+#endif
+{
+ Q_D(QFxPaintedItem);
+ const QRect content(QPoint(0,0),d->contentsSize);
+ if (content.width() <= 0 || content.height() <= 0)
+ return;
+
+#if defined(QFX_RENDER_QPAINTER)
+ bool oldAntiAliasing = p.testRenderHint(QPainter::Antialiasing);
+ bool oldSmoothPixmap = p.testRenderHint(QPainter::SmoothPixmapTransform);
+ if (d->smooth) {
+ 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
+
+ const QRect clip = mapFromScene(clipf).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(), area.y(), area.width(), area.height());
+ p.drawPixmap(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();
+ for (int i = 0; i < rects.count(); ++i) {
+ const QRect &r = rects.at(i);
+ QPixmap img(r.size());
+ img.fill(Qt::transparent);
+ {
+ QPainter qp(&img);
+ qp.translate(-r.x(),-r.y());
+ drawContents(&qp, r);
+ }
+ QFxPaintedItemPrivate::ImageCacheItem *newitem = new QFxPaintedItemPrivate::ImageCacheItem;
+ newitem->area = r;
+#if defined(QFX_RENDER_QPAINTER)
+ newitem->image = img;
+#else
+ newitem->image.setImage(img.toImage());
+#endif
+ d->imagecache.append(newitem);
+ QRectF target(r.x(), r.y(), r.width(), r.height());
+ p.drawPixmap(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.setRenderHints(QPainter::Antialiasing, oldAntiAliasing);
+ p.setRenderHints(QPainter::SmoothPixmapTransform, oldSmoothPixmap);
+ }
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpainteditem.h b/src/declarative/fx/qfxpainteditem.h
new file mode 100644
index 0000000..e086894
--- /dev/null
+++ b/src/declarative/fx/qfxpainteditem.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qfxitem.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+class QFxPaintedItemPrivate;
+class Q_DECLARATIVE_EXPORT QFxPaintedItem : public QFxItem
+{
+ Q_OBJECT
+public:
+ QFxPaintedItem(QFxItem *parent=0);
+ ~QFxPaintedItem();
+
+ 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:
+ QFxPaintedItem(QFxPaintedItemPrivate &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(QFxPaintedItem)
+ Q_DECLARE_PRIVATE(QFxPaintedItem)
+};
+QML_DECLARE_TYPE(QFxPaintedItem)
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/declarative/fx/qfxpainteditem_p.h b/src/declarative/fx/qfxpainteditem_p.h
new file mode 100644
index 0000000..d8d1a2a
--- /dev/null
+++ b/src/declarative/fx/qfxpainteditem_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 <private/qfxitem_p.h>
+#include <QtDeclarative/qsimplecanvas.h>
+
+#if defined(QFX_RENDER_OPENGL)
+#include "gltexture.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFxPaintedItemPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxPaintedItem)
+
+public:
+ QFxPaintedItemPrivate()
+ : max_imagecache_size(1000*1000), smooth(false)
+ {
+ }
+
+ struct ImageCacheItem {
+ ImageCacheItem() : age(0) {}
+ ~ImageCacheItem() { }
+ int age;
+ QRect area;
+#if defined(QFX_RENDER_QPAINTER)
+ QPixmap 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/qfxparticles.cpp b/src/declarative/fx/qfxparticles.cpp
new file mode 100644
index 0000000..41fb5bc
--- /dev/null
+++ b/src/declarative/fx/qfxparticles.cpp
@@ -0,0 +1,1200 @@
+/****************************************************************************
+**
+** 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 "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 group_effects
+ \brief The QFxParticleMotion class is the base class for particle motion.
+
+ This class causes the particles to remain static.
+*/
+
+/*!
+ Constructs a QFxParticleMotion with parent object \a parent.
+*/
+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 object moves particles linearly.
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionLinear
+ \ingroup group_effects
+ \brief The QFxParticleMotionLinear class moves the particles linearly.
+*/
+
+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 object moves particles towards a point.
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionGravity
+ \ingroup group_effects
+ \brief The QFxParticleMotionGravity class moves the particles towards a point.
+*/
+
+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 object 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.
+
+ \qml
+Rect {
+ width: 240
+ height: 320
+ color: "black"
+
+ Particles {
+ y: 0
+ width: parent.width
+ height: 30
+ source: "star.png"
+ lifeSpan: 5000
+ count: 50
+ angle: 70
+ angleDeviation: 36
+ velocity: 30
+ velocityDeviation: 10
+ ParticleMotionWander {
+ xvariance: 30
+ pace: 100
+ }
+ }
+}
+ \endqml
+
+ \sa Particles
+*/
+
+/*!
+ \internal
+ \class QFxParticleMotionWander
+ \ingroup group_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.
+*/
+
+/*!
+ \qmlproperty int QFxParticleMotionWander::xvariance
+ \qmlproperty int QFxParticleMotionWander::yvariance
+
+ These properties set the amount to wander in the x and y directions.
+*/
+
+/*!
+ \qmlproperty int 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 QFxParticlesPainter : public QFxItem
+{
+public:
+ QFxParticlesPainter(QFxParticlesPrivate *p, QFxItem* parent)
+ : QFxItem(parent), d(p)
+ {
+ setOptions(HasContents);
+ maxX = minX = maxY = minY = 0;
+ }
+
+#if defined(QFX_RENDER_QPAINTER)
+ void paintContents(QPainter &p);
+#elif defined(QFX_RENDER_OPENGL2)
+ void paintGLContents(GLPainter &);
+#endif
+
+ void updateSize();
+
+ qreal maxX;
+ qreal minX;
+ qreal maxY;
+ qreal minY;
+ QFxParticlesPrivate* d;
+};
+
+//---------------------------------------------------------------------------
+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()
+ {
+ Q_Q(QFxParticles);
+ paintItem = new QFxParticlesPainter(this, q);
+ }
+
+ void tick(int time);
+ void createParticle(int time);
+ void updateOpacity(QFxParticle &p, int age);
+
+ QString source;
+ QUrl url;
+ QPixmap 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;
+ QFxParticlesPainter *paintItem;
+
+ 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 object generates and moves particles.
+ \inherits Item
+
+ The particles created by this object cannot be dealt with directly, they can only be controlled through the parameters of the Particles object. The particles are all the same pixmap, specified by the user.
+
+ The particles are painted relative to the parent of the Particles object. Moving the
+ Particles object 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.
+
+ \qml
+Rect {
+ width: 240
+ height: 320
+ color: "black"
+ Particles {
+ y: 0
+ width: parent.width
+ height: 30
+ source: "star.png"
+ lifeSpan: 5000
+ count: 50
+ angle: 70
+ angleDeviation: 36
+ velocity: 30
+ velocityDeviation: 10
+ ParticleMotionWander {
+ xvariance: 30
+ pace: 100
+ }
+ }
+ Particles {
+ y: 300
+ x: 120
+ width: 1
+ height: 1
+ source: "star.png"
+ lifeSpan: 5000
+ count: 200
+ angle: 270
+ angleDeviation: 45
+ velocity: 50
+ velocityDeviation: 30
+ ParticleMotionGravity {
+ yattractor: 1000
+ xattractor: 0
+ acceleration: 25
+ }
+ }
+}
+ \endqml
+ \image particles.gif
+*/
+
+/*!
+ \internal
+ \class QFxParticles
+ \ingroup group_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::source
+ \brief the URL of the particle image.
+*/
+QString QFxParticles::source() 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::setSource(const QString &name)
+{
+ Q_D(QFxParticles);
+
+ if (name == d->source)
+ return;
+
+ if (!d->source.isEmpty())
+ QFxPixmap::cancelGet(d->url, this);
+ if (name.isEmpty()) {
+ d->source = name;
+ d->url = QUrl();
+ d->image = QPixmap();
+#if defined(QFX_RENDER_OPENGL)
+ d->texDirty = true;
+ d->tex.clear();
+#endif
+ update();
+ } else {
+ d->source = name;
+ d->url = qmlContext(this)->resolvedUrl(name);
+ QFxPixmap::get(qmlEngine(this), 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:
+
+ \qml
+Particles {
+ source: "star.png"
+ lifeSpan: 200
+ lifeSpanDeviation: 100
+}
+ \endqml
+*/
+
+/*!
+ \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:
+
+\qml
+Particles {
+ source: "star.png"
+ lifeSpan: 200
+ lifeSpanDeviation: 100
+}
+\endqml
+
+ \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:
+
+ \qml
+Particles {
+ source: "star.png"
+ angle: 60
+ angleDeviation: 90
+}
+ \endqml
+*/
+
+/*!
+ \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:
+
+\qml
+Particles {
+ source: "star.png"
+ angle: 60
+ angleDeviation: 90
+}
+\endqml
+
+ \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.
+
+ \qml
+Particles {
+ source: "star.png"
+ velocity: 50
+ velocityDeviation: 20
+}
+ \endqml
+*/
+
+/*!
+ \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.
+
+\qml
+Particles {
+ source: "star.png"
+ velocity: 50
+ velocityDeviation: 20
+}
+\endqml
+
+ \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 QFxParticles::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();
+}
+
+void QFxParticlesPainter::updateSize(){
+ setX(-500);
+ setY(-500);
+ setWidth(1000);
+ setHeight(1000);
+ return ;
+ const int parentX = parent()->x();
+ const int parentY = parent()->y();
+ //Have to use statistical approach to needed size as arbitrary particle
+ //motions make it impossible to calculate.
+ //max/min vars stored to give a never shrinking rect
+ for (int i = 0; i < d->particles.count(); ++i) {
+ const QFxParticle &particle = d->particles.at(i);
+ if(particle.x > maxX)
+ maxX = particle.x;
+ if(particle.x < minX)
+ minX = particle.x;
+ if(particle.y > maxY)
+ maxY = particle.y;
+ if(particle.y < minY)
+ minY = particle.y;
+ }
+
+ int myWidth = (int)(maxX-minX+0.5)+d->image.width();
+ int myX = (int)(minX - parentX);
+ int myHeight = (int)(maxY-minY+0.5)+d->image.height();
+ int myY = (int)(minY - parentY);
+ setWidth(myWidth);
+ setHeight(myHeight);
+ setX(myX);
+ setY(myY);
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxParticles::paintContents(QPainter &p)
+{
+ Q_UNUSED(p);
+ //painting is done by the ParticlesPainter, so it can have the right size
+}
+
+void QFxParticlesPainter::paintContents(QPainter &p)
+{
+ if (d->image.isNull())
+ return;
+
+ updateSize();
+ const int myX = x() + parent()->x();
+ const int myY = y() + parent()->y();
+
+ for (int i = 0; i < d->particles.count(); ++i) {
+ const QFxParticle &particle = d->particles.at(i);
+ p.setOpacity(particle.opacity);
+ p.drawPixmap(particle.x - myX, particle.y - myY, d->image);
+ }
+ update();//Should I need this? (GV does)
+}
+#elif defined(QFX_RENDER_OPENGL2)
+void QFxParticles::paintGLContents(GLPainter &)
+{
+ //painting is done by the ParticlesPainter, so it can have the right size
+}
+
+void QFxParticlesPainter::paintGLContents(GLPainter &p)
+{
+
+ if (d->image.isNull())
+ return;
+
+ updateSize();
+
+ if (d->texDirty && !d->image.isNull()) {
+ d->tex.setImage(d->image.toImage());
+ 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() + parent()->x());
+ const int myY = (int)(y() + parent()->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..6ef2582
--- /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 <QtDeclarative/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 Q_DECLARATIVE_EXPORT 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 Q_DECLARATIVE_EXPORT QFxParticleMotionLinear : public QFxParticleMotion
+{
+ Q_OBJECT
+public:
+ QFxParticleMotionLinear(QObject *parent=0)
+ : QFxParticleMotion(parent) {}
+
+ virtual void advance(QFxParticle &, int interval);
+};
+QML_DECLARE_TYPE(QFxParticleMotionLinear)
+
+class Q_DECLARATIVE_EXPORT 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 Q_DECLARATIVE_EXPORT 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 source READ source WRITE setSource)
+ 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 source() const;
+ void setSource(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..be731b1
--- /dev/null
+++ b/src/declarative/fx/qfxpath.cpp
@@ -0,0 +1,868 @@
+/****************************************************************************
+**
+** 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_NOCREATE_TYPE(QFxPathElement)
+QML_DEFINE_NOCREATE_TYPE(QFxCurve)
+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 PathElement
+ \brief PathElement is the base path type.
+
+ This type is the base for all path types. It cannot
+ be instantiated.
+
+ \sa Path, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+
+/*!
+ \internal
+ \class QFxPathElement
+ \ingroup group_utility
+*/
+
+/*!
+ \qmlclass Path QFxPath
+ \brief A Path object defines a path for use by \l PathView.
+
+ A Path is composed of one or more path segments - PathLine, PathQuad,
+ PathCubic.
+
+ The spacing of the items along the Path can be adjusted via a
+ PathPercent object.
+
+ PathAttribute allows named attributes with values to be defined
+ along the path.
+
+ \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic
+*/
+
+/*!
+ \internal
+ \class QFxPath
+ \ingroup group_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 real Path::startX
+ \qmlproperty real Path::startY
+ This property holds the starting position of the path.
+*/
+
+/*!
+ \property QFxPath::startX
+ \brief the starting x position of the path.
+*/
+
+qreal QFxPath::startX() const
+{
+ Q_D(const QFxPath);
+ return d->startX;
+}
+
+void QFxPath::setStartX(qreal x)
+{
+ Q_D(QFxPath);
+ d->startX = x;
+}
+
+
+/*!
+ \property QFxPath::startY
+ \brief the starting y position of the path.
+*/
+
+qreal QFxPath::startY() const
+{
+ Q_D(const QFxPath);
+ return d->startY;
+}
+
+void QFxPath::setStartY(qreal y)
+{
+ Q_D(QFxPath);
+ d->startY = y;
+}
+
+/*!
+ \qmlproperty list<PathElement> Path::pathElements
+ This property holds the objects composing the path.
+
+ \default
+
+ A path can contain the following path objects:
+ \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
+
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 2
+*/
+
+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::QFxPathViewPathCache> 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;
+}
+
+/****************************************************************************/
+
+qreal QFxCurve::x() const
+{
+ return _x;
+}
+
+void QFxCurve::setX(qreal x)
+{
+ if (_x != x) {
+ _x = x;
+ emit changed();
+ }
+}
+
+qreal QFxCurve::y() const
+{
+ return _y;
+}
+
+void QFxCurve::setY(qreal y)
+{
+ if (_y != y) {
+ _y = y;
+ emit changed();
+ }
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathAttribute
+ \brief The PathAttribute allows setting an attribute at a given position in a Path.
+
+ The PathAttribute object allows attibutes consisting of a name and
+ a value to be specified for the endpoints of path segments. The
+ attributes are exposed to the delegate as
+ \l{qmlintroduction.html#attached-properties} {Attached Properties}.
+ The value of an attribute at any particular point is interpolated
+ from the PathAttributes bounding the point.
+
+ The example below shows a path with the items scaled to 30% with
+ opacity 50% at the top of the path and scaled 100% with opacity
+ 100% at the bottom. Note the use of the PathView.scale and
+ PathView.opacity attached properties to set the scale and opacity
+ of the delegate.
+
+ \table
+ \row
+ \o \image declarative-pathattribute.png
+ \o
+ \snippet doc/src/snippets/declarative/pathview/pathattributes.qml 0
+ \endtable
+
+ \sa Path
+*/
+
+/*!
+ \internal
+ \class QFxPathAttribute
+ \ingroup group_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.
+
+ The example below creates a path consisting of a straight line from
+ 0,100 to 200,100:
+
+ \qml
+ Path {
+ startX: 0; startY: 100
+ PathLine { x: 200; y: 100 }
+ }
+ \endqml
+
+ \sa Path, PathQuad, PathCubic
+*/
+
+/*!
+ \internal
+ \class QFxPathLine
+ \ingroup group_utility
+ \brief The QFxPathLine class defines a straight line.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlproperty real PathLine::x
+ \qmlproperty real PathLine::y
+
+ Defines the end point of the line.
+*/
+
+void QFxPathLine::addToPath(QPainterPath &path)
+{
+ path.lineTo(x(), y());
+}
+
+/****************************************************************************/
+
+/*!
+ \qmlclass PathQuad
+ \brief The PathQuad defines a quadratic Bezier curve with a control point.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathquad.png
+ \o
+ \qml
+ Path {
+ startX: 0; startY: 0
+ PathQuad x: 200; y: 0; controlX: 100; controlY: 150 }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathCubic, PathLine
+*/
+
+/*!
+ \internal
+ \class QFxPathQuad
+ \ingroup group_utility
+ \brief The QFxPathQuad class defines a quadratic Bezier curve with a control point.
+
+ \sa QFxPath
+*/
+
+
+/*!
+ \qmlproperty real PathQuad::x
+ \qmlproperty real PathQuad::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real PathQuad::controlX
+ \qmlproperty real PathQuad::controlY
+
+ Defines the position of the control point.
+*/
+
+/*!
+ the x position of the control point.
+*/
+qreal QFxPathQuad::controlX() const
+{
+ return _controlX;
+}
+
+void QFxPathQuad::setControlX(qreal x)
+{
+ if (_controlX != x) {
+ _controlX = x;
+ emit changed();
+ }
+}
+
+
+/*!
+ the y position of the control point.
+*/
+qreal QFxPathQuad::controlY() const
+{
+ return _controlY;
+}
+
+void QFxPathQuad::setControlY(qreal 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.
+
+ The following QML produces the path shown below:
+ \table
+ \row
+ \o \image declarative-pathcubic.png
+ \o
+ \qml
+ Path {
+ startX: 20; startY: 0
+ PathCubic {
+ x: 180; y: 0; control1X: -10; control1Y: 90
+ control2X: 210; control2Y: 90
+ }
+ }
+ \endqml
+ \endtable
+
+ \sa Path, PathQuad, PathLine
+*/
+
+/*!
+ \internal
+ \class QFxPathCubic
+ \ingroup group_utility
+ \brief The QFxPathCubic class defines a cubic Bezier curve with two control points.
+
+ \sa QFxPath
+*/
+
+/*!
+ \qmlproperty real PathCubic::x
+ \qmlproperty real PathCubic::y
+
+ Defines the end point of the curve.
+*/
+
+/*!
+ \qmlproperty real PathCubic::control1X
+ \qmlproperty real PathCubic::control1Y
+
+ Defines the position of the first control point.
+*/
+
+/*!
+ \property QFxPathCubic::control1X
+ \brief the x position of the first control point.
+*/
+qreal QFxPathCubic::control1X() const
+{
+ return _control1X;
+}
+
+void QFxPathCubic::setControl1X(qreal x)
+{
+ if (_control1X != x) {
+ _control1X = x;
+ emit changed();
+ }
+}
+
+/*!
+ \property QFxPathCubic::control1Y
+ \brief the y position of the first control point.
+*/
+qreal QFxPathCubic::control1Y() const
+{
+ return _control1Y;
+}
+
+void QFxPathCubic::setControl1Y(qreal y)
+{
+ if (_control1Y != y) {
+ _control1Y = y;
+ emit changed();
+ }
+}
+
+/*!
+ \qmlproperty real PathCubic::control2X
+ \qmlproperty real PathCubic::control2Y
+
+ Defines the position of the second control point.
+*/
+
+/*!
+ \property QFxPathCubic::control2X
+ \brief the x position of the second control point.
+*/
+qreal QFxPathCubic::control2X() const
+{
+ return _control2X;
+}
+
+void QFxPathCubic::setControl2X(qreal x)
+{
+ if (_control2X != x) {
+ _control2X = x;
+ emit changed();
+ }
+}
+
+/*!
+ \property QFxPathCubic::control2Y
+ \brief the y position of the second control point.
+*/
+qreal QFxPathCubic::control2Y() const
+{
+ return _control2Y;
+}
+
+void QFxPathCubic::setControl2Y(qreal 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.
+
+ The examples below show the normal distrubution of items along a path
+ compared to a distribution which places 50% of the items along the
+ PathLine section of the path.
+ \table
+ \row
+ \o \image declarative-nopercent.png
+ \o
+ \qml
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathLine { x: 150; y: 80 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ }
+ \endqml
+ \row
+ \o \image declarative-percent.png
+ \o
+ \qml
+ Path {
+ startX: 20; startY: 0
+ PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 }
+ PathPercent { value: 0.25 }
+ PathLine { x: 150; y: 80 }
+ PathPercent { value: 0.75 }
+ PathQuad { x: 180; y: 0; controlX: 200; controlY: 80 }
+ PathPercent { value: 1 }
+ }
+ \endqml
+ \endtable
+
+ \sa Path
+*/
+
+/*!
+ \internal
+ \class QFxPathPercent
+ \ingroup group_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..39b9d01
--- /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 <QtCore/QObject>
+#include <QtGui/QPainterPath>
+#include <QtDeclarative/qml.h>
+#include <QtDeclarative/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(qreal x READ x WRITE setX NOTIFY changed)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY changed)
+public:
+ QFxCurve(QObject *parent=0) : QFxPathElement(parent), _x(0), _y(0) {}
+
+ qreal x() const;
+ void setX(qreal x);
+
+ qreal y() const;
+ void setY(qreal y);
+
+ virtual void addToPath(QPainterPath &) {}
+
+private:
+ qreal _x;
+ qreal _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(qreal controlX READ controlX WRITE setControlX NOTIFY changed)
+ Q_PROPERTY(qreal controlY READ controlY WRITE setControlY NOTIFY changed)
+public:
+ QFxPathQuad(QObject *parent=0) : QFxCurve(parent), _controlX(0), _controlY(0) {}
+
+ qreal controlX() const;
+ void setControlX(qreal x);
+
+ qreal controlY() const;
+ void setControlY(qreal y);
+
+ void addToPath(QPainterPath &path);
+
+private:
+ qreal _controlX;
+ qreal _controlY;
+};
+QML_DECLARE_TYPE(QFxPathQuad)
+
+class Q_DECLARATIVE_EXPORT QFxPathCubic : public QFxCurve
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal control1X READ control1X WRITE setControl1X NOTIFY changed)
+ Q_PROPERTY(qreal control1Y READ control1Y WRITE setControl1Y NOTIFY changed)
+ Q_PROPERTY(qreal control2X READ control2X WRITE setControl2X NOTIFY changed)
+ Q_PROPERTY(qreal control2Y READ control2Y WRITE setControl2Y NOTIFY changed)
+public:
+ QFxPathCubic(QObject *parent=0) : QFxCurve(parent), _control1X(0), _control1Y(0), _control2X(0), _control2Y(0) {}
+
+ qreal control1X() const;
+ void setControl1X(qreal x);
+
+ qreal control1Y() const;
+ void setControl1Y(qreal y);
+
+ qreal control2X() const;
+ void setControl2X(qreal x);
+
+ qreal control2Y() const;
+ void setControl2Y(qreal 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(qreal startX READ startX WRITE setStartX)
+ Q_PROPERTY(qreal startY READ startY WRITE setStartY)
+ Q_CLASSINFO("DefaultProperty", "pathElements")
+ Q_INTERFACES(QmlParserStatus)
+public:
+ QFxPath(QObject *parent=0);
+ ~QFxPath();
+
+ QList<QFxPathElement *>* pathElements();
+
+ qreal startX() const;
+ void setStartX(qreal x);
+
+ qreal startY() const;
+ void setStartY(qreal 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..625d778
--- /dev/null
+++ b/src/declarative/fx/qfxpathview.cpp
@@ -0,0 +1,890 @@
+/****************************************************************************
+**
+** 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 <QEvent>
+#include "qmlbindablevalue.h"
+#include "qmlstate.h"
+#include "qlistmodelinterface.h"
+#include "qmlopenmetaobject.h"
+
+#include "qfxpathview.h"
+#include "qfxpathview_p.h"
+#include <QGraphicsSceneEvent>
+
+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))
+ {
+ }
+
+ ~QFxPathViewAttached()
+ {
+ QFxPathView::attachedProperties.remove(parent());
+ }
+
+ 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 group_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 QML.
+
+ The items are laid out along a path defined by a \l Path and may be flicked to scroll.
+
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 0
+
+ \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.
+ Models can also be created directly in XML, using the ListModel element.
+*/
+
+/*!
+ \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->modelVariant;
+}
+
+void QFxPathView::setModel(const QVariant &model)
+{
+ Q_D(QFxPathView);
+ 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)));
+ disconnect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ for (int i=0; i<d->items.count(); i++){
+ QFxItem *p = d->items[i];
+ d->model->release(p);
+ }
+ d->items.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(qmlContext(this));
+ d->ownModel = true;
+ }
+ d->model->setModel(model);
+ }
+ if (d->model) {
+ connect(d->model, SIGNAL(itemsInserted(int,int)), this, SLOT(itemsInserted(int,int)));
+ connect(d->model, SIGNAL(itemsRemoved(int,int)), this, SLOT(itemsRemoved(int,int)));
+ connect(d->model, SIGNAL(createdItem(int, QFxItem*)), this, SLOT(createdItem(int,QFxItem*)));
+ }
+ d->firstIndex = 0;
+ d->pathOffset = 0;
+ 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:
+ \snippet doc/src/snippets/declarative/pathview/pathview.qml 1
+*/
+
+/*!
+ \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(qmlContext(this));
+ 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);
+ if (!d->items.count())
+ return;
+ 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);
+ for (int i=0; i<items.count(); i++){
+ QFxItem *p = items[i];
+ releaseItem(p);
+ }
+ items.clear();
+
+ if (!isValid())
+ return;
+
+ if (firstIndex >= model->count())
+ firstIndex = model->count()-1;
+ if (pathOffset >= model->count())
+ pathOffset = model->count()-1;
+
+ int numItems = pathItems >= 0 ? pathItems : model->count();
+ for (int i=0; i < numItems && i < model->count(); ++i){
+ QFxItem *item = getItem((i + firstIndex) % model->count());
+ if (!item) {
+ qWarning() << "PathView: Cannot create item, index" << (i + firstIndex) % model->count();
+ return;
+ }
+ items.append(item);
+ item->setZ(i);
+ }
+ q->refill();
+}
+
+void QFxPathViewPrivate::updateItem(QFxItem *item, qreal percent)
+{
+ if (QObject *obj = QFxPathView::qmlAttachedProperties(item)) {
+ foreach(const 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->isValid())
+ 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 wrapIndex= -1;
+ for (int i=0; i<d->items.count()-1; i++) {
+ if (rotatedPositions[i] > rotatedPositions[i+1]){
+ wrapIndex = i;
+ break;
+ }
+ }
+ if (wrapIndex != -1 ){
+ //A wraparound has occured
+ if (wrapIndex < d->items.count()/2){
+ while(wrapIndex-- >= 0){
+ QFxItem* p = d->items.takeFirst();
+ d->updateItem(p, 0.0);
+ d->releaseItem(p);
+ d->firstIndex++;
+ d->firstIndex %= d->model->count();
+ int index = (d->firstIndex + d->items.count())%d->model->count();
+ d->items << d->getItem(index);
+ d->items.last()->setZ(wrapIndex);
+ d->pathOffset++;
+ d->pathOffset=d->pathOffset % d->items.count();
+ }
+ } else {
+ while(wrapIndex++ < d->items.count()-1){
+ QFxItem* p = d->items.takeLast();
+ d->updateItem(p, 1.0);
+ d->releaseItem(p);
+ d->firstIndex--;
+ if (d->firstIndex < 0)
+ d->firstIndex = d->model->count() - 1;
+ d->items.prepend(d->getItem(d->firstIndex));
+ d->items.first()->setZ(d->firstIndex);
+ 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::itemsInserted(int modelIndex, int count)
+{
+ //XXX support animated insertion
+ Q_D(QFxPathView);
+ if (!d->isValid())
+ return;
+ if (d->pathItems == -1) {
+ for (int i = 0; i < count; ++i) {
+ QFxItem *item = d->getItem(modelIndex + i);
+ item->setZ(modelIndex + i);
+ d->items.insert(modelIndex + i, item);
+ }
+ refill();
+ } else {
+ //XXX This is pretty heavy handed until we reference count items.
+ d->regenerate();
+ }
+
+ // make sure the current item is still at the snap position
+ int itemIndex = (d->currentIndex - d->firstIndex + d->model->count())%d->model->count();
+ itemIndex += d->pathOffset;
+ itemIndex %= d->items.count();
+ qreal targetOffset = fmod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), 100);
+
+ if (targetOffset < 0)
+ targetOffset = 100.0 + targetOffset;
+ if (targetOffset != d->_offset)
+ d->moveOffset.setValue(targetOffset);
+}
+
+void QFxPathView::itemsRemoved(int modelIndex, int count)
+{
+ //XXX support animated removal
+ Q_D(QFxPathView);
+ if (!d->isValid())
+ return;
+ if (d->pathItems == -1) {
+ for (int i = 0; i < count; ++i) {
+ QFxItem* p = d->items.takeAt(modelIndex);
+ d->model->release(p);
+ }
+ d->snapToCurrent();
+ refill();
+ } else {
+ d->regenerate();
+ }
+
+ if (d->model->count() == 0) {
+ d->currentIndex = -1;
+ d->moveOffset.setValue(0);
+ return;
+ }
+
+ // make sure the current item is still at the snap position
+ if (d->currentIndex >= d->model->count())
+ d->currentIndex = d->model->count() - 1;
+ int itemIndex = (d->currentIndex - d->firstIndex + d->model->count())%d->model->count();
+ itemIndex += d->pathOffset;
+ itemIndex %= d->items.count();
+ qreal targetOffset = fmod(100 + (d->snapPos*100) - 100.0 * itemIndex / d->items.count(), 100);
+
+ if (targetOffset < 0)
+ targetOffset = 100.0 + targetOffset;
+ if (targetOffset != d->_offset)
+ d->moveOffset.setValue(targetOffset);
+}
+
+void QFxPathView::createdItem(int index, QFxItem *item)
+{
+ Q_D(QFxPathView);
+ if (d->requestedIndex != index) {
+ item->setItemParent(this);
+ d->updateItem(item, index < d->firstIndex ? 0.0 : 1.0);
+ }
+}
+
+void QFxPathView::destroyingItem(QFxItem *item)
+{
+ Q_UNUSED(item);
+}
+
+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), QEasingCurve(QEasingCurve::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, QEasingCurve(QEasingCurve::OutQuad), int(200 * _offset / distance));
+ tl.set(moveOffset, 100.0);
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InQuad), int(200 * (100-targetOffset) / distance));
+ } else if (targetOffset - _offset <= -50.0) {
+ qreal distance = 100 - _offset + targetOffset;
+ tl.move(moveOffset, 100.0, QEasingCurve(QEasingCurve::OutQuad), int(200 * (100-_offset) / distance));
+ tl.set(moveOffset, 0.0);
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InQuad), int(200 * targetOffset / distance));
+ } else {
+ tl.move(moveOffset, targetOffset, QEasingCurve(QEasingCurve::InOutQuad), 200);
+ }
+}
+
+QHash<QObject*, QObject*> QFxPathView::attachedProperties;
+QObject *QFxPathView::qmlAttachedProperties(QObject *obj)
+{
+ QObject *rv = attachedProperties.value(obj);
+ if (!rv) {
+ rv = new QFxPathViewAttached(obj);
+ attachedProperties.insert(obj, rv);
+ }
+ return rv;
+}
+
+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..cbdafa8
--- /dev/null
+++ b/src/declarative/fx/qfxpathview.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** 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 <QtDeclarative/qfxitem.h>
+#include <QtDeclarative/qfxpath.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();
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void createdItem(int index, QFxItem *item);
+ void destroyingItem(QFxItem *item);
+
+protected:
+ QFxPathView(QFxPathViewPrivate &dd, QFxItem *parent);
+
+private:
+ friend class QFxPathViewAttached;
+ 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..b5c5ba2
--- /dev/null
+++ b/src/declarative/fx/qfxpathview_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 "qmltimelinevalueproxy.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), requestedIndex(-1), model(0)
+ , moveReason(Other)
+ {
+ fixupOffsetEvent = QmlTimeLineEvent::timeLineEvent<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()));
+ }
+
+ QFxItem *getItem(int modelIndex) {
+ Q_Q(QFxPathView);
+ requestedIndex = modelIndex;
+ QFxItem *item = model->item(modelIndex);
+ if (item)
+ item->setItemParent(q);
+ requestedIndex = -1;
+ return item;
+ }
+ void releaseItem(QFxItem *item) {
+ model->release(item);
+ }
+
+ bool isValid() const {
+ return model && model->count() > 0 && model->delegate() && path;
+ }
+
+ 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;
+ bool stealMouse : 1;
+ bool ownModel : 1;
+ QTime lastPosTime;
+ QPointF lastPos;
+ QFxItem *activeItem;
+ qreal snapPos;
+ qreal dragMargin;
+ QmlTimeLine tl;
+ QmlTimeLineValueProxy<QFxPathViewPrivate> moveOffset;
+ QmlTimeLineEvent fixupOffsetEvent;
+ int firstIndex;
+ int pathItems;
+ int pathOffset;
+ int requestedIndex;
+ 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..0ea94f5
--- /dev/null
+++ b/src/declarative/fx/qfxpixmap.cpp
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** 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 <QPixmapCache>
+#include <qfxperf.h>
+#include <QtDeclarative/qmlengine.h>
+#include <QFile>
+
+QT_BEGIN_NAMESPACE
+class QSharedNetworkReply;
+typedef QHash<QString, QSharedNetworkReply *> QFxSharedNetworkReplyHash;
+static QFxSharedNetworkReplyHash qfxActiveNetworkReplies;
+
+class QSharedNetworkReply
+{
+public:
+ QSharedNetworkReply(QNetworkReply *r) : reply(r), refCount(1) {}
+ ~QSharedNetworkReply()
+ {
+ reply->deleteLater();
+ }
+ QNetworkReply *reply;
+
+ int refCount;
+ void addRef()
+ {
+ ++refCount;
+ }
+ void release()
+ {
+ Q_ASSERT(refCount > 0);
+ --refCount;
+ if (refCount == 0) {
+ QString key = reply->url().toString();
+ qfxActiveNetworkReplies.remove(key);
+ delete this;
+ }
+ }
+};
+
+class QFxPixmapPrivate
+{
+public:
+ QFxPixmapPrivate() {}
+
+ QPixmap pixmap;
+};
+
+/*!
+ \internal
+ \class QFxPixmap
+ \ingroup group_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
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ if (url.scheme()==QLatin1String("file")) {
+ d->pixmap.load(url.toLocalFile());
+ } else
+#endif
+ {
+ QString key = url.toString();
+ if (!QPixmapCache::find(key,&d->pixmap)) {
+ QFxSharedNetworkReplyHash::Iterator iter = qfxActiveNetworkReplies.find(key);
+ if (iter == qfxActiveNetworkReplies.end()) {
+ // API usage error
+ qWarning() << "QFxPixmap: URL not loaded" << url;
+ } else {
+ if ((*iter)->reply->error()) {
+ qWarning() << "Network error loading" << url << (*iter)->reply->errorString();
+ } else {
+ QImage img;
+ if (img.load((*iter)->reply, 0)) {
+ d->pixmap = QPixmap::fromImage(img);
+ QPixmapCache::insert(key, d->pixmap);
+ } else {
+ qWarning() << "Format error loading" << url;
+ }
+ }
+ (*iter)->release();
+ }
+ }
+ }
+}
+
+QFxPixmap::QFxPixmap(const QFxPixmap &o)
+: d(new QFxPixmapPrivate)
+{
+ d->pixmap = o.d->pixmap;
+}
+
+QFxPixmap::~QFxPixmap()
+{
+ delete d;
+}
+
+QFxPixmap &QFxPixmap::operator=(const QFxPixmap &o)
+{
+ d->pixmap = o.d->pixmap;
+ return *this;
+}
+
+bool QFxPixmap::isNull() const
+{
+ return d->pixmap.isNull();
+}
+
+int QFxPixmap::width() const
+{
+ return d->pixmap.width();
+}
+
+int QFxPixmap::height() const
+{
+ return d->pixmap.height();
+}
+
+QFxPixmap::operator const QPixmap &() const
+{
+ return d->pixmap;
+}
+
+/*!
+ 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.
+
+ Returns a QNetworkReply if the image is not immediately available, otherwise
+ returns 0. The QNetworkReply must not be stored - it may be destroyed at any time.
+*/
+QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot)
+{
+#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
+ if (url.scheme()==QLatin1String("file")) {
+ QObject dummy;
+ QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot);
+ return 0;
+ }
+#endif
+
+ QString key = url.toString();
+ if (QPixmapCache::find(key,0)) {
+ QObject dummy;
+ QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot);
+ return 0;
+ }
+
+ QFxSharedNetworkReplyHash::Iterator iter = qfxActiveNetworkReplies.find(key);
+ if (iter == qfxActiveNetworkReplies.end()) {
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
+ QSharedNetworkReply *item = new QSharedNetworkReply(engine->networkAccessManager()->get(req));
+ iter = qfxActiveNetworkReplies.insert(key, item);
+ } else {
+ (*iter)->addRef();
+ }
+
+ QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot);
+ return (*iter)->reply;
+}
+
+/*!
+ Stops the given slot being invoked if the given url finishes loading.
+ May also cancel loading (eg. if no other pending request).
+
+ Any connections to the QNetworkReply returned by get() will be
+ disconnected.
+*/
+void QFxPixmap::cancelGet(const QUrl& url, QObject* obj)
+{
+ QString key = url.toString();
+ QFxSharedNetworkReplyHash::Iterator iter = qfxActiveNetworkReplies.find(key);
+ if (iter == qfxActiveNetworkReplies.end())
+ return;
+ QObject::disconnect((*iter)->reply, 0, obj, 0);
+ (*iter)->release();
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h
new file mode 100644
index 0000000..ae693c1
--- /dev/null
+++ b/src/declarative/fx/qfxpixmap.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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 <QtCore/QString>
+#include <QtGui/QPixmap>
+#include <QtDeclarative/qsimplecanvas.h>
+#include <QtDeclarative/qfxglobal.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+class QmlEngine;
+class QNetworkReply;
+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 QNetworkReply *get(QmlEngine *, const QUrl& url, QObject*, const char* slot);
+ static void cancelGet(const QUrl& url, QObject* obj);
+
+ bool isNull() const;
+
+ int width() const;
+ int height() const;
+
+ operator const QPixmap &() 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..c156753
--- /dev/null
+++ b/src/declarative/fx/qfxrect.cpp
@@ -0,0 +1,1005 @@
+/****************************************************************************
+**
+** 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)
+QML_DEFINE_TYPE(QFxGradientStop,GradientStop)
+QML_DEFINE_TYPE(QFxGradient,Gradient)
+
+/*!
+ \internal
+ \class QFxPen
+ \ingroup group_utility
+ \brief The QFxPen class provides a pen used for drawing rect borders on a QFxView.
+
+ By default, the pen is invalid and nothing is drawn. You must either set a color (then the default
+ width is 0) or a width (then the default color is black).
+
+ A width of 0 indicates a cosmetic pen, a single-pixel line on the border of the item being painted.
+
+ Example:
+ \qml
+ Rect { pen.width: 2; pen.color: "red" ... }
+ \endqml
+*/
+
+/*! \property QFxPen::width
+ \brief the width of the pen.
+
+ A width of 0 is a single-pixel line on the border of the item being painted.
+
+ If the width is less than 0 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 \l {http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG color keyword name}
+ (as defined by the World Wide Web Consortium). For example:
+ \qml
+ // rect with green border using hexidecimal notation
+ Rect { pen.color: "#00FF00" }
+
+ // rect with steelblue border using SVG color name
+ Rect { pen.color: "steelblue" }
+ \endqml
+
+ For the full set of ways to specify color, see Qt's QColor::setNamedColor documentation.
+*/
+
+void QFxPen::setColor(const QColor &c)
+{
+ _color = c;
+ _valid = _color.alpha() ? true : false;
+ emit updated();
+}
+
+/*!
+ \property QFxPen::width
+ \brief the width of the pen.
+
+ \qml
+ // rect with green border using hexidecimal notation
+ Rect { pen.width: 4 }
+ \endqml
+
+ A width of 0 creates a thin line. For no line, use a negative width or a transparent color.
+
+ Odd pen widths generally lead to half-pixel painting.
+*/
+void QFxPen::setWidth(int w)
+{
+ _width = w;
+ _valid = (_width < 0) ? false : true;
+ emit updated();
+}
+
+
+/*!
+ \qmlclass GradientStop QFxGradientStop
+ \brief The GradientStop item defines the color at a position in a Gradient
+
+ \sa Gradient
+*/
+
+/*!
+ \qmlproperty real GradientStop::position
+ \qmlproperty color GradientStop::color
+
+ Sets a \e color at a \e position in a gradient.
+*/
+
+void QFxGradientStop::updateGradient()
+{
+ if (QFxGradient *grad = qobject_cast<QFxGradient*>(parent()))
+ grad->doUpdate();
+}
+
+/*!
+ \qmlclass Gradient QFxGradient
+ \brief The Gradient item defines a gradient fill.
+
+ A gradient is defined by two or more colors, which will be blended seemlessly. The
+ colors are specified at their position in the range 0.0 - 1.0 via
+ the GradientStop item. For example, the following code paints a
+ Rect with a gradient starting with red, blending to yellow at 1/3 of the
+ size of the Rect, and ending with Green:
+
+ \table
+ \row
+ \o \image gradient.png
+ \o \quotefile doc/src/snippets/declarative/gradient.qml
+ \endtable
+
+ \sa GradientStop
+*/
+
+/*!
+ \qmlproperty list<GradientStop> Gradient::stops
+ This property holds the gradient stops describing the gradient.
+*/
+
+const QGradient *QFxGradient::gradient() const
+{
+ if (!m_gradient && !m_stops.isEmpty()) {
+ m_gradient = new QLinearGradient(0,0,0,1.0);
+ for (int i = 0; i < m_stops.count(); ++i) {
+ const QFxGradientStop *stop = m_stops.at(i);
+ m_gradient->setCoordinateMode(QGradient::ObjectBoundingMode);
+ m_gradient->setColorAt(stop->position(), stop->color());
+ }
+ }
+
+ return m_gradient;
+}
+
+void QFxGradient::doUpdate()
+{
+ delete m_gradient;
+ m_gradient = 0;
+ emit updated();
+}
+
+QML_DEFINE_TYPE(QFxRect,Rect)
+
+/*!
+ \qmlclass Rect QFxRect
+ \brief The Rect item 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.
+
+ \qml
+ Rect {
+ width: 100
+ height: 100
+ color: "red"
+ pen.color: "black"
+ pen.width: 5
+ radius: 10
+ }
+ \endqml
+
+ \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.
+
+ \qml
+ Rect {
+ width: 100
+ height: 100
+ color: "red"
+ pen.color: "black"
+ pen.width: 5
+ radius: 10
+ }
+ \endqml
+
+ \image declarative-rect.png
+
+ A QFxRect object can be instantiated in Qml using the tag \l Rect.
+
+ \ingroup group_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 = QPixmap();
+#endif
+#if defined(QFX_RENDER_OPENGL)
+ Q_D(QFxRect);
+ d->_rectTexture.clear();
+#endif
+ const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0;
+ setPaintMargin((pw+1)/2);
+ 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 Gradient Rect::gradient
+
+ The gradient to use to fill the rect.
+
+ This property allows for the construction of simple vertical gradients.
+ Other gradients may by formed by adding rotation to the rect.
+
+ \table
+ \row
+ \o \image declarative-rect_gradient.png
+ \o
+ \qml
+ Rect { y: 0; width: 80; height: 80; color: "lightsteelblue" }
+ Rect { y: 100; width: 80; height: 80
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "lightsteelblue" }
+ GradientStop { position: 1.0; color: "blue" }
+ }
+ }
+ Rect { rotation: 90; x: 80; y: 200; width: 80; height: 80
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: "lightsteelblue" }
+ GradientStop { position: 1.0; color: "blue" }
+ }
+ }
+ // The x offset is needed because the rotation is from the top left corner
+ \endqml
+ \endtable
+
+ \sa Gradient, color
+*/
+QFxGradient *QFxRect::gradient() const
+{
+ Q_D(const QFxRect);
+ return d->gradient;
+}
+
+void QFxRect::setGradient(QFxGradient *gradient)
+{
+ Q_D(QFxRect);
+ if (d->gradient == gradient)
+ return;
+ if (d->gradient)
+ disconnect(d->gradient, SIGNAL(updated()), this, SLOT(doUpdate()));
+ d->gradient = gradient;
+ if (d->gradient)
+ connect(d->gradient, SIGNAL(updated()), this, SLOT(doUpdate()));
+ update();
+}
+
+
+/*!
+ \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 = QPixmap();
+#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.
+
+ \qml
+ // green rect using hexidecimal notation
+ Rect { color: "#00FF00" }
+
+ // steelblue rect using SVG color name
+ Rect { color: "steelblue" }
+ \endqml
+*/
+
+/*!
+ \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 = QPixmap();
+#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.
+
+ \qml
+ Rect { x: 0; width: 80; height: 80; color: "lightsteelblue" }
+ Rect { x: 100; width: 80; height: 80; color: "lightsteelblue"; tintColor: "#10FF0000" }
+ \endqml
+ \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;
+ }
+}
+
+
+#if defined(QFX_RENDER_QPAINTER)
+void QFxRect::generateRoundedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectImage.isNull()) {
+ const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0;
+ d->_rectImage = QPixmap(d->_radius*2 + 3 + pw*2, d->_radius*2 + 3 + pw*2);
+ d->_rectImage.fill(Qt::transparent);
+ QPainter p(&(d->_rectImage));
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->_pen && d->_pen->isValid()) {
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->_color);
+ p.drawRoundedRect((pw+1)/2, (pw+1)/2, d->_rectImage.width()-(pw+1)/2*2, d->_rectImage.height()-(pw+1)/2*2, d->_radius, d->_radius);
+ }
+}
+
+void QFxRect::generateBorderedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectImage.isNull()) {
+ const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0;
+ d->_rectImage = QPixmap(d->pen()->width()*2 + 3 + pw*2, d->pen()->width()*2 + 3 + pw*2);
+ d->_rectImage.fill(Qt::transparent);
+ QPainter p(&(d->_rectImage));
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->_pen && d->_pen->isValid()) {
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->_color);
+ p.drawRect(qreal(pw+1)/2, qreal(pw+1)/2, d->_rectImage.width()-(pw+1)/2*2, d->_rectImage.height()-(pw+1)/2*2);
+ }
+}
+#elif defined(QFX_RENDER_OPENGL)
+void QFxRect::generateRoundedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectTexture.isNull()) {
+ const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0;
+ QImage roundRect(d->_radius*2 + 4 + pw*2, d->_radius*2 + 4 + pw*2, QImage::Format_ARGB32_Premultiplied);
+ roundRect.fill(0);
+ QPainter p(&roundRect);
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->_pen && d->_pen->isValid()) {
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->_color);
+ p.drawRoundedRect((pw+1)/2, (pw+1)/2, roundRect.width()-(pw+1)/2*2, roundRect.height()-(pw+1)/2*2, d->_radius, d->_radius);
+ d->_rectTexture.setImage(roundRect);
+ }
+}
+
+void QFxRect::generateBorderedRect()
+{
+ Q_D(QFxRect);
+ if (d->_rectTexture.isNull()) {
+ const int pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0;
+ QImage borderedRect(pw*2 + 4, pw*2 + 4, QImage::Format_ARGB32_Premultiplied);
+ borderedRect.fill(0);
+ QPainter p(&(borderedRect));
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->_pen && d->_pen->isValid()) {
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(d->_color);
+ p.drawRect(qreal(pw+1)/2, qreal(pw+1)/2, borderedRect.width()-(pw+1)/2*2, borderedRect.height()-(pw+1)/2*2);
+ 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->gradient && d->gradient->gradient()) )
+ drawRect(p);
+ else
+ p.fillRect(QRect(0, 0, width(), height()), d->getColor());
+}
+
+void QFxRect::drawRect(QPainter &p)
+{
+ Q_D(QFxRect);
+ if (d->gradient && d->gradient->gradient() /*|| p.usingQt() */) {
+ // XXX This path is still slower than the image path
+ // Image path won't work for gradients though
+ QPainter::RenderHints oldHints = p.renderHints();
+ p.setRenderHint(QPainter::Antialiasing);
+ if (d->_pen && d->_pen->isValid()) {
+ QPen pn(QColor(pen()->color()), pen()->width());
+ p.setPen(pn);
+ } else {
+ p.setPen(Qt::NoPen);
+ }
+ p.setBrush(*d->gradient->gradient());
+ if (d->_radius > 0.)
+ p.drawRoundedRect(0, 0, width(), height(), d->_radius, d->_radius);
+ else
+ p.drawRect(0, 0, width(), height());
+ p.setRenderHints(oldHints);
+ } else {
+ int offset = 0;
+ const int pw = d->_pen && d->_pen->isValid() ? (d->_pen->width()+1)/2*2 : 0;
+
+ if (d->_radius > 0) {
+ generateRoundedRect();
+ //### implicit conversion to int
+ offset = int(d->_radius+1.5+pw);
+ } else {
+ generateBorderedRect();
+ offset = pw+1;
+ }
+
+ //basically same code as QFxImage uses to paint sci images
+ int w = width()+pw;
+ int h = height()+pw;
+ int xOffset = offset;
+ int xSide = xOffset * 2;
+ bool xMiddles=true;
+ if (xSide > w) {
+ xMiddles=false;
+ xOffset = w/2 + 1;
+ xSide = xOffset * 2;
+ }
+ int yOffset = offset;
+ int ySide = yOffset * 2;
+ bool yMiddles=true;
+ if (ySide > h) {
+ yMiddles = false;
+ yOffset = h/2 + 1;
+ ySide = yOffset * 2;
+ }
+
+ // Upper left
+ p.drawPixmap(QRect(-pw/2, -pw/2, xOffset, yOffset), d->_rectImage, QRect(0, 0, xOffset, yOffset));
+
+ // Upper middle
+ if (xMiddles)
+ p.drawPixmap(QRect(xOffset-pw/2, -pw/2, width() - xSide + pw, yOffset), d->_rectImage,
+ QRect(d->_rectImage.width()/2, 0, 1, yOffset));
+ // Upper right
+ p.drawPixmap(QPoint(width()-xOffset+pw/2, -pw/2), d->_rectImage,
+ QRect(d->_rectImage.width()-xOffset, 0, xOffset, yOffset));
+ // Middle left
+ if (yMiddles)
+ p.drawPixmap(QRect(-pw/2, yOffset-pw/2, xOffset, height() - ySide + pw), d->_rectImage,
+ QRect(0, d->_rectImage.height()/2, xOffset, 1));
+
+ // Middle
+ if (xMiddles && yMiddles)
+ // XXX paint errors in animation example
+ //p.fillRect(xOffset-pw/2, yOffset-pw/2, width() - xSide + pw, height() - ySide + pw, d->getColor());
+ p.drawPixmap(QRect(xOffset-pw/2, yOffset-pw/2, width() - xSide + pw, height() - ySide + pw), d->_rectImage,
+ QRect(d->_rectImage.width()/2, d->_rectImage.height()/2, 1, 1));
+ // Middle right
+ if (yMiddles)
+ p.drawPixmap(QRect(width()-xOffset+pw/2, yOffset-pw/2, xOffset, height() - ySide + pw), d->_rectImage,
+ QRect(d->_rectImage.width()-xOffset, d->_rectImage.height()/2, xOffset, 1));
+ // Lower left
+ p.drawPixmap(QPoint(-pw/2, height() - yOffset + pw/2), d->_rectImage, QRect(0, d->_rectImage.height() - yOffset, xOffset, yOffset));
+
+ // Lower Middle
+ if (xMiddles)
+ p.drawPixmap(QRect(xOffset-pw/2, height() - yOffset +pw/2, width() - xSide + pw, yOffset), d->_rectImage,
+ QRect(d->_rectImage.width()/2, d->_rectImage.height() - yOffset, 1, yOffset));
+ // Lower Right
+ p.drawPixmap(QPoint(width()-xOffset+pw/2, height() - yOffset+pw/2), d->_rectImage,
+ QRect(d->_rectImage.width()-xOffset, d->_rectImage.height() - yOffset, xOffset, yOffset));
+ }
+}
+#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->gradient) {
+ float widthV = width();
+ float heightV = height();
+
+ GLfloat vertices[] = { 0, heightV,
+ widthV, heightV,
+ 0, 0,
+ widthV, 0 };
+
+ int count = d->gradient->stops()->size();
+ GLfloat colors[count*8];
+ for (int i = 0; i < count; i += 8) {
+ QFxGradientStop *g = d->gradient->stops()->at(i);
+ QColor c = g->color();
+ colors[i] = c.redF(); colors[i+4] = colors[i];
+ colors[i+1] = c.greenF(); colors[i+5] = colors[i+1];
+ colors[i+2] = c.blueF(); colors[i+6] = colors[i+2];
+ colors[i+3] = c.alphaF() * p.activeOpacity; colors[i+7] = colors[i+3];
+ }
+
+ 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, count*2);
+ 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;
+ qreal pw = d->_pen && d->_pen->isValid() ? d->_pen->width() : 0.0;
+
+ if (d->_radius > 0) {
+ generateRoundedRect();
+ offset = d->_radius + pw+1.5;
+ } else {
+ generateBorderedRect();
+ offset = pw+1.5;
+ }
+
+ QGLShaderProgram *shader = p.useTextureShader();
+
+ float texWidth = d->_rectTexture.width();
+ float texHeight = d->_rectTexture.height();
+ if (!texWidth || !texHeight)
+ return;
+
+ float widthV = qreal(width())+pw/2;
+ float heightV = qreal(height())+pw/2;
+
+ float xOffset = offset;
+ bool xMiddles = true;
+ if (xOffset*2 > width()+pw) {
+ xMiddles = false;
+ xOffset = (width()+pw)/2;
+ }
+ float yOffset = offset;
+ bool yMiddles = true;
+ if (yOffset*2 > height()+pw) {
+ yMiddles = false;
+ yOffset = (height()+pw)/2;
+ }
+
+ float texleft = xOffset / texWidth;
+ float imgleft = xOffset-pw/2;
+ float texright = (texWidth-xOffset) / texWidth;
+ float imgright = widthV - xOffset;
+
+ float textop = yOffset / texHeight;
+ float imgtop = yOffset-pw/2;
+ float texbottom = (texHeight-yOffset) / texHeight;
+ float imgbottom = heightV - yOffset;
+
+ //Bug 231768: Inappropriate interpolation was occuring on 3x3 textures
+ if (offset==1)
+ texleft=texright=textop=texbottom=0.5;
+
+ float vert1[] = { -pw/2, -pw/2,
+ -pw/2, imgtop,
+ imgleft, -pw/2,
+ imgleft, imgtop,
+ imgright, -pw/2,
+ imgright, imgtop,
+ widthV, -pw/2,
+ widthV, imgtop };
+ float tex1[] = { 0, 0,
+ 0, textop,
+ texleft, 0,
+ texleft, textop,
+ texright, 0,
+ texright, textop,
+ 1, 0,
+ 1, textop };
+ float vert2[] = { -pw/2, imgtop,
+ -pw/2, 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[] = { -pw/2, heightV,
+ -pw/2, imgbottom,
+ imgleft, heightV,
+ imgleft, imgbottom,
+ imgright, heightV,
+ imgright, imgbottom,
+ widthV, heightV,
+ widthV, imgbottom };
+ float tex3[] = { 0, 1,
+ 0, texbottom,
+ texleft, 1,
+ texleft, texbottom,
+ texright, 1,
+ texright, texbottom,
+ 1, 1,
+ 1, texbottom };
+
+ 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);
+ if (yMiddles) {
+ 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 texWidth = d->_rectTexture.width();
+ float texHeight = d->_rectTexture.height();
+ if (!texWidth || !texHeight)
+ 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) / texWidth;
+ imgleft = offset;
+ texright = 1. - float(offset) / texWidth;
+ imgright = widthV - offset;
+ textop = 1. - float(offset) / texHeight;
+ imgtop = offset;
+ texbottom = float(offset) / texHeight;
+ 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..c279a1c
--- /dev/null
+++ b/src/declarative/fx/qfxrect.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QFXRECT_H
+#define QFXRECT_H
+
+#include <QtDeclarative/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(0), _color("#000000"), _valid(false)
+ {}
+
+ int width() const { return _width; }
+ void setWidth(int w);
+
+ 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 Q_DECLARATIVE_EXPORT QFxGradientStop : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal position READ position WRITE setPosition)
+ Q_PROPERTY(QColor color READ color WRITE setColor)
+
+public:
+ QFxGradientStop(QObject *parent=0) : QObject(parent) {}
+
+ qreal position() const { return m_position; }
+ void setPosition(qreal position) { m_position = position; updateGradient(); }
+
+ QColor color() const { return m_color; }
+ void setColor(const QColor &color) { m_color = color; updateGradient(); }
+
+private:
+ void updateGradient();
+
+private:
+ qreal m_position;
+ QColor m_color;
+};
+QML_DECLARE_TYPE(QFxGradientStop)
+
+class Q_DECLARATIVE_EXPORT QFxGradient : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QList<QFxGradientStop *> *stops READ stops)
+ Q_CLASSINFO("DefaultProperty", "stops")
+
+public:
+ QFxGradient(QObject *parent=0) : QObject(parent), m_gradient(0) {}
+ ~QFxGradient() { delete m_gradient; }
+
+ QList<QFxGradientStop *> *stops() { return &m_stops; }
+
+ const QGradient *gradient() const;
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ void doUpdate();
+
+private:
+ QList<QFxGradientStop *> m_stops;
+ mutable QGradient *m_gradient;
+ friend class QFxGradientStop;
+};
+QML_DECLARE_TYPE(QFxGradient)
+
+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(QFxGradient *gradient READ gradient WRITE setGradient)
+ 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 &);
+
+ QFxPen *pen();
+
+ QFxGradient *gradient() const;
+ void setGradient(QFxGradient *gradient);
+
+ 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..8cafcbb
--- /dev/null
+++ b/src/declarative/fx/qfxrect_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 QFxGradient;
+
+class QFxRectPrivate : public QFxItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxRect)
+
+public:
+ QFxRectPrivate()
+ : gradient(0), _pen(0), _radius(0)
+ {
+ }
+
+ ~QFxRectPrivate()
+ {
+ delete _pen;
+ }
+
+ void init()
+ {
+ }
+
+#if defined(QFX_RENDER_OPENGL)
+ GLTexture _rectTexture;
+#endif
+ QColor getColor();
+ QColor _color;
+ QFxGradient *gradient;
+ 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)
+ QPixmap _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..2e57aa7
--- /dev/null
+++ b/src/declarative/fx/qfxreflectionfilter.cpp
@@ -0,0 +1,352 @@
+/****************************************************************************
+**
+** 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.
+
+ \qml
+HorizontalLayout {
+ Image {
+ source: "icon.png"
+ filter: Reflection { }
+ }
+ Image {
+ source: "icon.png"
+ filter: Reflection { offset: 1 }
+ }
+ Image {
+ source: "icon.png"
+ filter: Reflection { offset: 1; alpha: 0.5 }
+ }
+ Image {
+ source: "icon.png"
+ filter: Reflection { offset: 1; alpha: 0.5; height: 50 }
+ }
+ Image {
+ source: "icon.png"
+ filter: Reflection { offset: 1; alpha: 0.5; height: 50; scale: 0.5 }
+ }
+}
+ \endqml
+
+ \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.
+*/
+
+/*!
+ \internal
+ \class QFxReflectionFilter
+ \ingroup group_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.
+
+ \qml
+Image {
+ id: myImage
+ source: "album.png"
+ filter: Reflection {
+ height: myImage.height * 0.5
+ }
+}
+ \endqml
+ */
+/*!
+ \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..6e56b5e
--- /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 <QtDeclarative/qsimplecanvasfilter.h>
+#include <QtDeclarative/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..0211ebb
--- /dev/null
+++ b/src/declarative/fx/qfxrepeater.cpp
@@ -0,0 +1,356 @@
+/****************************************************************************
+**
+** 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 item allows you to repeat a component based on a data source.
+
+ The Repeater item 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 items}.
+
+ 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 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.
+
+ \snippet doc/src/snippets/declarative/repeater.qml 0
+
+ \image repeater.png
+
+ 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.
+ */
+
+/*!
+ \internal
+ \class QFxRepeater
+ \ingroup group_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.
+
+ \snippet doc/src/snippets/declarative/repeater.qml 0
+
+ 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.
+
+ 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.
+*/
+
+/*!
+ \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::componentComplete()
+{
+ QFxItem::componentComplete();
+ 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() || !isComponentComplete())
+ 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(qmlContext(this), 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(qmlContext(this), 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(qmlContext(this), 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(qmlContext(this), 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(qmlContext(this), 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..c1b194a
--- /dev/null
+++ b/src/declarative/fx/qfxrepeater.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 QFXREPEATER_H
+#define QFXREPEATER_H
+
+#include <QtDeclarative/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 componentComplete();
+ 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..abe8e0d
--- /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..c59cb32
--- /dev/null
+++ b/src/declarative/fx/qfxscalegrid.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** 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 <QtCore/QString>
+#include <QtCore/QObject>
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qsimplecanvas.h>
+#include <QtDeclarative/qfxpixmap.h>
+#include <QtDeclarative/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..10c332c
--- /dev/null
+++ b/src/declarative/fx/qfxshadowfilter.cpp
@@ -0,0 +1,214 @@
+/****************************************************************************
+**
+** 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
+ \qml
+Rect {
+ radius: 5
+ color: "lightsteelblue"
+ width: 100
+ height: 100
+ filter: Shadow {
+ yOffset: 8
+ xOffset: 8
+ }
+}
+
+Image {
+ source: "pics/qtlogo.png"
+ filter: Shadow {
+ yOffset: 8
+ xOffset: 8
+ }
+}
+ \endqml
+ \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 group_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::yOffset
+ \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..67d165a
--- /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 <QtDeclarative/qsimplecanvasfilter.h>
+#include <QtDeclarative/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..702ec81
--- /dev/null
+++ b/src/declarative/fx/qfxtext.cpp
@@ -0,0 +1,950 @@
+/****************************************************************************
+**
+** 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 item allows you to add formatted text to a scene.
+ \inherits Item
+
+ It can display both plain and rich text. For example:
+
+ \qml
+ Text { text: "Hello World!"; font.family: "Helvetica"; font.size: 24; color: "red" }
+ Text { text: "<b>Hello</b> <i>World!</i>" }
+ \endqml
+
+ \image declarative-text.png
+
+ 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.
+*/
+
+/*!
+ \internal
+ \class QFxText
+ \qmlclass Text
+ \ingroup group_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:
+
+ \qml
+ Text { text: "Hello World!"; font.family: "Helvetica"; font.size: 24; color: "red" }
+ Text { text: "<b>Hello</b> <i>World!</i>" }
+ \endqml
+
+ \image text.png
+
+ 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 line of plain text to a set width.
+
+ A QFxText object can be instantiated in Qml using the tag \c Text.
+*/
+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 string Text::font.family
+ \qmlproperty bool Text::font.bold
+ \qmlproperty bool Text::font.italic
+ \qmlproperty real Text::font.size
+
+ Set the Text's font attributes.
+
+ \note \c font.size sets the font's point size (not pixel 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.
+
+ \qml
+ //green text using hexadecimal notation
+ Text { color: "#00FF00"; ... }
+
+ //steelblue text using SVG color name
+ Text { color: "steelblue"; ... }
+ \endqml
+*/
+
+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.
+
+ \qml
+ 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" }
+ }
+ \endqml
+
+ \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 items
+ 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 item'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::elide
+
+ Set this property to elide parts of the text fit to the Text item'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...?
+ layout.clearLayout();
+ layout.setFont(f);
+ layout.setText(tmp);
+ size = setupTextLayout(&layout);
+ cachedLayoutSize = size;
+ }
+ 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()
+{
+ QPixmap img = QPixmap(imgCache.size());
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ QPoint pos(imgCache.rect().topLeft());
+ pos += QPoint(-1, 0);
+ ppm.drawPixmap(pos, imgStyleCache);
+ pos += QPoint(2, 0);
+ ppm.drawPixmap(pos, imgStyleCache);
+ pos += QPoint(-1, -1);
+ ppm.drawPixmap(pos, imgStyleCache);
+ pos += QPoint(0, 2);
+ ppm.drawPixmap(pos, imgStyleCache);
+
+ pos += QPoint(0, -1);
+ ppm.drawPixmap(pos, imgCache);
+ ppm.end();
+
+ imgCache = img;
+}
+
+void QFxTextPrivate::drawOutline(int yOffset)
+{
+ QPixmap img = QPixmap(imgCache.size());
+ img.fill(Qt::transparent);
+
+ QPainter ppm(&img);
+
+ QPoint pos(imgCache.rect().topLeft());
+ pos += QPoint(0, yOffset);
+ ppm.drawPixmap(pos, imgStyleCache);
+
+ pos += QPoint(0, -yOffset);
+ ppm.drawPixmap(pos, imgCache);
+ ppm.end();
+
+ imgCache = img;
+}
+
+QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout)
+{
+ Q_Q(QFxText);
+ layout->setCacheEnabled(true);
+
+ QFont f; if (_font) f = _font->font();
+ QFontMetrics fm = QFontMetrics(f);
+
+ 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();
+
+ 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);
+}
+
+QPixmap QFxTextPrivate::wrappedTextImage(bool drawStyle)
+{
+ //do layout
+ QFont f; if (_font) f = _font->font();
+ QSize size = cachedLayoutSize;
+
+ int x = 0;
+ for (int i = 0; i < layout.lineCount(); ++i) {
+ QTextLine line = layout.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
+ QPixmap img(size);
+ img.fill(Qt::transparent);
+ QPainter p(&img);
+ if (drawStyle) {
+ p.setPen(styleColor);
+ }
+ else
+ p.setPen(color);
+ p.setFont(f);
+ layout.draw(&p, QPointF(0, 0));
+ return img;
+}
+
+QPixmap QFxTextPrivate::richTextImage(bool drawStyle)
+{
+ QSize size = doc->size().toSize();
+
+ //paint text
+ QPixmap img(size);
+ img.fill(Qt::transparent);
+ 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 = QPixmap();
+ imgStyleCache = QPixmap();
+ } else if (richText) {
+ imgCache = richTextImage(false);
+ if (style != QFxText::Normal)
+ imgStyleCache = richTextImage(true); //### should use styleColor
+ } else {
+ imgCache = 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.toImage());
+#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;
+ }
+
+ bool needClip = !clip() && (d->imgCache.width() > width() ||
+ d->imgCache.height() > height());
+
+ if (needClip) {
+ p.save();
+ p.setClipRect(boundingRect());
+ }
+ p.drawPixmap(x, y, d->imgCache);
+ if (needClip)
+ p.restore();
+}
+
+#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..99ab2be
--- /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 <QtDeclarative/qfxitem.h>
+#include <QtDeclarative/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..dfaef63
--- /dev/null
+++ b/src/declarative/fx/qfxtext_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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"
+#include <QtGui/qtextlayout.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);
+
+ QPixmap wrappedTextImage(bool drawStyle);
+ QPixmap 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
+ QPixmap imgCache;
+ QPixmap imgStyleCache;
+ QFxText::HAlignment hAlign;
+ QFxText::VAlignment vAlign;
+ Qt::TextElideMode elideMode;
+ bool dirty;
+ bool wrap;
+ bool richText;
+ bool singleline;
+ QTextControl *control;
+ QTextDocument *doc;
+ QTextLayout layout;
+ QSize cachedLayoutSize;
+};
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp
new file mode 100644
index 0000000..5492aaa
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit.cpp
@@ -0,0 +1,938 @@
+/****************************************************************************
+**
+** 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 "qfxevents_p.h"
+#include <QTextLayout>
+#include <QTextLine>
+#include <QTextDocument>
+#include <QGraphicsSceneMouseEvent>
+
+#include <QDebug>
+
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxTextEdit, TextEdit)
+
+/*!
+ \qmlclass TextEdit
+ \brief The TextEdit item allows you to add editable formatted text to a scene.
+
+ It can display both plain and rich text. For example:
+
+ \qml
+TextEdit {
+ id: edit
+ text: "<b>Hello</b> <i>World!</i>"
+ focus: true
+ focusable: true
+ font.family: "Helvetica"
+ font.size: 20
+ color: "blue"
+ width: 240
+}
+ \endqml
+
+ \image declarative-textedit.gif
+
+ \sa Text
+*/
+
+/*!
+ \internal
+ \class QFxTextEdit
+ \qmlclass TextEdit
+ \ingroup group_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)
+: QFxPaintedItem(*(new QFxTextEditPrivate), parent)
+{
+ Q_D(QFxTextEdit);
+ d->init();
+}
+
+/*!
+\internal
+*/
+QFxTextEdit::QFxTextEdit(QFxTextEditPrivate &dd, QFxItem *parent)
+ : QFxPaintedItem(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);
+ if (QFxTextEdit::text() == text)
+ return;
+ 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
+ \qml
+VerticalLayout {
+ TextEdit {
+ font.size: 24
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ TextEdit {
+ font.size: 24
+ textFormat: "RichText"
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+ TextEdit {
+ font.size: 24
+ textFormat: "PlainText"
+ text: "<b>Hello</b> <i>World!</i>"
+ }
+}
+ \endqml
+ \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.
+
+ \qml
+// green text using hexadecimal notation
+TextEdit { color: "#00FF00"; ... }
+
+// steelblue text using SVG color name
+TextEdit { color: "steelblue"; ... }
+ \endqml
+*/
+
+/*!
+ \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 color TextEdit::highlightColor
+
+ The text highlight color, used behind selections.
+*/
+
+/*!
+ \property QFxTextEdit::highlightColor
+ \brief the text edit's default text highlight color
+*/
+QColor QFxTextEdit::highlightColor() const
+{
+ Q_D(const QFxTextEdit);
+ return d->highlightColor;
+}
+
+void QFxTextEdit::setHighlightColor(const QColor &color)
+{
+ Q_D(QFxTextEdit);
+ if (d->highlightColor == color)
+ return;
+
+ clearCache();
+ d->highlightColor = color;
+ QPalette pal = d->control->palette();
+ pal.setColor(QPalette::Highlight, 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 items
+ 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 QFxTextEdit::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 QFxTextEdit::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 item'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();
+}
+
+/*!
+ \property QFxTextEdit::cursorVisible
+ \brief If true the text edit shows a cursor.
+
+ This property is set and unset when the text edit gets focus, but it can also
+ be set directly (useful, for example, if a KeyProxy might forward keys to it).
+*/
+bool QFxTextEdit::isCursorVisible() const
+{
+ Q_D(const QFxTextEdit);
+ return d->cursorVisible;
+}
+
+void QFxTextEdit::setCursorVisible(bool on)
+{
+ Q_D(QFxTextEdit);
+ if (d->cursorVisible == on)
+ return;
+ d->cursorVisible = on;
+ QFocusEvent focusEvent(on ? QEvent::FocusIn : QEvent::FocusOut);
+ if (!on && !d->preserveSelection)
+ d->control->setCursorIsFocusIndicator(true);
+ d->control->processEvent(&focusEvent, QPointF(0, 0));
+}
+
+/*!
+ \qmlproperty bool TextEdit::focusOnPress
+
+ Whether the TextEdit should gain focus on a mouse press. By default this is
+ set to false;
+*/
+bool QFxTextEdit::focusOnPress() const
+{
+ Q_D(const QFxTextEdit);
+ return d->focusOnPress;
+}
+
+void QFxTextEdit::setFocusOnPress(bool on)
+{
+ Q_D(QFxTextEdit);
+ if (d->focusOnPress == on)
+ return;
+ d->focusOnPress = on;
+}
+
+/*!
+ \qmlproperty bool TextEdit::preserveSelection
+
+ Whether the TextEdit should keep the selection visible when it loses focus to another
+ item in the scene. By default this is set to true;
+*/
+bool QFxTextEdit::preserveSelection() const
+{
+ Q_D(const QFxTextEdit);
+ return d->preserveSelection;
+}
+
+void QFxTextEdit::setPreserveSelection(bool on)
+{
+ Q_D(QFxTextEdit);
+ if (d->preserveSelection == on)
+ return;
+ d->preserveSelection = on;
+}
+
+qreal QFxTextEdit::textMargin() const
+{
+ Q_D(const QFxTextEdit);
+ return d->textMargin;
+}
+
+void QFxTextEdit::setTextMargin(qreal margin)
+{
+ Q_D(QFxTextEdit);
+ if (d->textMargin == margin)
+ return;
+ d->textMargin = margin;
+ d->document->setDocumentMargin(d->textMargin);
+}
+
+void QFxTextEdit::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ if (newGeometry.width() != oldGeometry.width())
+ updateSize();
+ QFxPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+/*!
+ \internal
+*/
+void QFxTextEdit::dump(int depth)
+{
+ QByteArray ba(depth * 4, ' ');
+ qWarning() << ba.constData() << propertyInfo();
+ QFxPaintedItem::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);
+ QFxPaintedItem::componentComplete();
+ if (d->dirty) {
+ updateSize();
+ d->dirty = false;
+ }
+}
+
+/*!
+ \qmlproperty bool TextEdit::readOnly
+
+ Whether the user an interact with the TextEdit item. 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 \a event.
+*/
+bool QFxTextEdit::event(QEvent *event)
+{
+ Q_D(QFxTextEdit);
+ if (event->type() == QEvent::ShortcutOverride) {
+ d->control->processEvent(event, QPointF(0, 0));
+ return true;
+ }
+ return QFxPaintedItem::event(event);
+}
+
+/*!
+\overload
+Handles the given key \a event.
+*/
+void QFxTextEdit::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QFxTextEdit);
+ //### experiment with allowing 'overrides' to key events
+ QFxKeyEvent ke(*event);
+ emit keyPress(&ke);
+ event->setAccepted(ke.isAccepted());
+ if (event->isAccepted())
+ return;
+
+ 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);
+ //### experiment with allowing 'overrides' to key events
+ QFxKeyEvent ke(*event);
+ emit keyRelease(&ke);
+ event->setAccepted(ke.isAccepted());
+ if (event->isAccepted())
+ return;
+
+ d->control->processEvent(event, QPointF(0, 0));
+}
+
+/*!
+ \overload
+ Handles changing of the focus property. Focus is applied to the control
+ even if the edit does not have active focus. This is because things
+ like KeyProxy can give the behavior of focus even when activeFocus isn't
+ true.
+*/
+void QFxTextEdit::focusChanged(bool hasFocus)
+{
+ setCursorVisible(hasFocus);
+}
+
+/*!
+ Causes all text to be selected.
+*/
+void QFxTextEdit::selectAll()
+{
+ Q_D(QFxTextEdit);
+ d->control->selectAll();
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ if (d->focusOnPress)
+ setFocus(true);
+ d->control->processEvent(event, QPointF(0, 0));
+ if (!event->isAccepted())
+ QFxPaintedItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ d->control->processEvent(event, QPointF(0, 0));
+ if (!event->isAccepted())
+ QFxPaintedItem::mousePressEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ d->control->processEvent(event, QPointF(0, 0));
+ if (!event->isAccepted())
+ QFxPaintedItem::mouseDoubleClickEvent(event);
+}
+
+/*!
+\overload
+Handles the given mouse \a event.
+*/
+void QFxTextEdit::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QFxTextEdit);
+ d->control->processEvent(event, QPointF(0, 0));
+ if (!event->isAccepted())
+ QFxPaintedItem::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(textMargin);
+ document->setUndoRedoEnabled(false); // flush undo buffer.
+ document->setUndoRedoEnabled(true);
+ updateDefaultTextOption();
+}
+
+void QFxTextEdit::q_textChanged()
+{
+ if (!widthValid())
+ updateSize(); //### optimize: we get 3 calls to updateSize every time a letter is typed
+ emit textChanged(text());
+}
+
+//### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't
+// need to do all the calculations each time
+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 + d->textMargin);
+ 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()
+{
+ QTextOption opt = document->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;
+ document->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..b761a1b
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QFXTEXTEDIT_H
+#define QFXTEXTEDIT_H
+
+#include <QtDeclarative/qfxtext.h>
+#include <QtDeclarative/qfxpainteditem.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 QFxPaintedItem
+{
+ 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(QColor highlightColor READ highlightColor WRITE setHighlightColor)
+ 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_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible)
+ Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress)
+ Q_PROPERTY(bool preserveSelection READ preserveSelection WRITE setPreserveSelection)
+ Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin)
+
+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);
+
+ QColor highlightColor() const;
+ void setHighlightColor(const QColor &c);
+
+ HAlignment hAlign() const;
+ void setHAlign(HAlignment align);
+
+ VAlignment vAlign() const;
+ void setVAlign(VAlignment align);
+
+ bool wrap() const;
+ void setWrap(bool w);
+
+ bool isCursorVisible() const;
+ void setCursorVisible(bool on);
+
+ bool focusOnPress() const;
+ void setFocusOnPress(bool on);
+
+ bool preserveSelection() const;
+ void setPreserveSelection(bool on);
+
+ qreal textMargin() const;
+ void setTextMargin(qreal margin);
+
+ 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();
+
+public Q_SLOTS:
+ void selectAll();
+
+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);
+
+ bool event(QEvent *);
+ void keyPressEvent(QKeyEvent *);
+ void keyReleaseEvent(QKeyEvent *);
+
+ void focusChanged(bool);
+
+ // mouse filter?
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(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..f733a4c
--- /dev/null
+++ b/src/declarative/fx/qfxtextedit_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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 "qfxpainteditem_p.h"
+#include "qml.h"
+
+
+QT_BEGIN_NAMESPACE
+class QTextLayout;
+class QTextDocument;
+class QTextControl;
+class QFxTextEditPrivate : public QFxPaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxTextEdit)
+
+public:
+ QFxTextEditPrivate()
+ : font(0), color("black"), imgDirty(true), hAlign(QFxTextEdit::AlignLeft), vAlign(QFxTextEdit::AlignTop),
+ dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), preserveSelection(true),
+ textMargin(0.0), format(QFxTextEdit::AutoText), document(0)
+ {
+ }
+
+ void init();
+
+ void updateDefaultTextOption();
+ void relayoutDocument();
+
+ QString text;
+ QmlFont font;
+ QColor color;
+ QColor highlightColor;
+ QString style;
+ QColor styleColor;
+ bool imgDirty;
+#if defined(QFX_RENDER_OPENGL)
+ GLTexture texture;
+#endif
+ QPixmap imgCache;
+ QPixmap imgStyleCache;
+ QFxTextEdit::HAlignment hAlign;
+ QFxTextEdit::VAlignment vAlign;
+ bool dirty;
+ bool wrap;
+ bool richText;
+ bool cursorVisible;
+ bool focusOnPress;
+ bool preserveSelection;
+ qreal textMargin;
+ 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..a4c5d22
--- /dev/null
+++ b/src/declarative/fx/qfxtransform.cpp
@@ -0,0 +1,895 @@
+/****************************************************************************
+**
+** 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_NOCREATE_TYPE(QFxTransform);
+
+/*!
+ \qmlclass Transform
+ \brief A transformation.
+*/
+QFxTransform::QFxTransform(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QFxTransform::~QFxTransform()
+{
+}
+
+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();
+}
+
+/*!
+ \qmlclass Axis
+ \brief A Axis object defines an axis that can be used for rotation or translation.
+
+ An axis is specified by 2 points in 3D space: a start point and
+ an end point. While technically the axis is the line running through these two points
+ (and thus many different sets of two points could define the same axis), the distance
+ between the points does matter for translation along an axis.
+
+ \image 3d-axis.png
+
+ \qml
+ Axis { startX: 20; startY: 0; endX: 40; endY: 60; endZ: 20 }
+ \endqml
+*/
+
+QML_DEFINE_TYPE(QFxAxis, Axis)
+
+QFxAxis::QFxAxis(QObject *parent)
+: QObject(parent), _startX(0), _startY(0), _endX(0), _endY(0), _endZ(0)
+{
+}
+
+QFxAxis::~QFxAxis()
+{
+}
+
+/*!
+ \qmlproperty real Axis::startX
+ \qmlproperty real Axis::startY
+
+ The start point of the axis. The z-position of the start point is assumed to be 0, and cannot
+ be changed.
+*/
+qreal QFxAxis::startX() const
+{
+ return _startX;
+}
+
+void QFxAxis::setStartX(qreal x)
+{
+ _startX = x;
+ emit updated();
+}
+
+qreal QFxAxis::startY() const
+{
+ return _startY;
+}
+
+void QFxAxis::setStartY(qreal y)
+{
+ _startY = y;
+ emit updated();
+}
+
+/*!
+ \qmlproperty real Axis::endX
+ \qmlproperty real Axis::endY
+ \qmlproperty real Axis::endZ
+
+ The end point of the axis.
+*/
+qreal QFxAxis::endX() const
+{
+ return _endX;
+}
+
+void QFxAxis::setEndX(qreal x)
+{
+ _endX = x;
+ emit updated();
+}
+
+qreal QFxAxis::endY() const
+{
+ return _endY;
+}
+
+void QFxAxis::setEndY(qreal y)
+{
+ _endY = y;
+ emit updated();
+}
+
+qreal QFxAxis::endZ() const
+{
+ return _endZ;
+}
+
+void QFxAxis::setEndZ(qreal z)
+{
+ _endZ = z;
+ emit updated();
+}
+
+/*!
+ \qmlclass Rotation
+ \brief A Rotation object provides a way to rotate an Item around a point.
+
+ The following example rotates a Rect around its interior point 25, 25:
+ \qml
+ Rect {
+ width: 100; height: 100
+ color: "blue"
+ transform: Rotation { originX: 25; originY: 25; angle: 45}
+ }
+ \endqml
+*/
+
+QFxRotation::QFxRotation(QObject *parent)
+: QFxTransform(parent), _originX(0), _originY(0), _angle(0), _dirty(true)
+{
+}
+
+QFxRotation::~QFxRotation()
+{
+}
+
+/*!
+ \qmlproperty real Rotation::originX
+ \qmlproperty real Rotation::originY
+
+ The point to rotate around.
+*/
+qreal QFxRotation::originX() const
+{
+ return _originX;
+}
+
+void QFxRotation::setOriginX(qreal ox)
+{
+ _originX = ox;
+ update();
+}
+
+qreal QFxRotation::originY() const
+{
+ return _originY;
+}
+
+void QFxRotation::setOriginY(qreal oy)
+{
+ _originY = oy;
+ update();
+}
+
+/*!
+ \qmlproperty real Rotation::angle
+
+ The angle, in degrees, to rotate.
+*/
+qreal QFxRotation::angle() const
+{
+ return _angle;
+}
+
+void QFxRotation::setAngle(qreal angle)
+{
+ if (_angle == angle)
+ return;
+ _angle = angle;
+ update();
+ emit angleChanged();
+}
+
+bool QFxRotation::isIdentity() const
+{
+ return (_angle == 0.);
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+QTransform QFxRotation::transform() const
+{
+ if (_dirty) {
+ _transform = QTransform();
+ _dirty = false;
+ _transform.translate(_originX, _originY);
+ _transform.rotate(_angle);
+ _transform.translate(-_originX, -_originY);
+ }
+ return _transform;
+}
+#elif defined(QFX_RENDER_OPENGL)
+QMatrix4x4 QFxRotation::transform() const
+{
+ if (_dirty) {
+ _transform = QMatrix4x4();
+ _dirty = false;
+ _transform.translate(_originX, _originY);
+ _transform.rotate(_angle, 0, 0, 1);
+ _transform.translate(-_originX, -_originY);
+ }
+ return _transform;
+}
+#endif
+
+void QFxRotation::update()
+{
+ _dirty = true;
+ QFxTransform::update();
+}
+
+QML_DEFINE_TYPE(QFxRotation, Rotation)
+
+/*!
+ \qmlclass Rotation3D
+ \brief A Rotation3D object provides a way to rotate an Item around an axis.
+
+ Here is an example of various rotations applied to an \l Image.
+ \snippet doc/src/snippets/declarative/rotation.qml 0
+
+ \image axisrotation.png
+*/
+
+QML_DEFINE_TYPE(QFxRotation3D,Rotation3D)
+
+QFxRotation3D::QFxRotation3D(QObject *parent)
+: QFxTransform(parent), _angle(0), _dirty(true)
+{
+ connect(&_axis, SIGNAL(updated()), this, SLOT(update()));
+}
+
+QFxRotation3D::~QFxRotation3D()
+{
+}
+
+/*!
+ \qmlproperty real Rotation3D::axis.startX
+ \qmlproperty real Rotation3D::axis.startY
+ \qmlproperty real Rotation3D::axis.endX
+ \qmlproperty real Rotation3D::axis.endY
+ \qmlproperty real Rotation3D::axis.endZ
+
+ A rotation axis is specified by 2 points in 3D space: a start point and
+ an end point. The z-position of the start point is assumed to be 0, and cannot
+ be changed.
+
+ \image 3d-rotation-axis.png
+
+ \sa Axis
+*/
+QFxAxis *QFxRotation3D::axis()
+{
+ return &_axis;
+}
+
+/*!
+ \qmlproperty real Rotation3D::angle
+
+ The angle, in degrees, to rotate around the specified axis.
+*/
+qreal QFxRotation3D::angle() const
+{
+ return _angle;
+}
+
+void QFxRotation3D::setAngle(qreal angle)
+{
+ _angle = angle;
+ update();
+}
+
+bool QFxRotation3D::isIdentity() const
+{
+ return (_angle == 0.) || (_axis.endZ() == 0. && _axis.endY() == _axis.startY() && _axis.endX() == _axis.startX());
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+const qreal inv_dist_to_plane = 1. / 1024.;
+QTransform QFxRotation3D::transform() const
+{
+ if (_dirty) {
+ _transform = QTransform();
+
+ if (!isIdentity()) {
+ if (angle() != 0.) {
+ QTransform rotTrans;
+ rotTrans.translate(-_axis.startX(), -_axis.startY());
+ QTransform rotTrans2;
+ rotTrans2.translate(_axis.startX(), _axis.startY());
+
+ qreal rad = angle() * 2. * M_PI / 360.;
+ qreal c = ::cos(rad);
+ qreal s = ::sin(rad);
+
+ qreal x = _axis.endX() - _axis.startX();
+ qreal y = _axis.endY() - _axis.startY();
+ qreal z = _axis.endZ();
+
+ 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*inv_dist_to_plane,
+ y*x*(1-c)+z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*inv_dist_to_plane,
+ 0, 0, 1);
+
+ _transform *= rotTrans;
+ _transform *= rot;
+ _transform *= rotTrans2;
+ }
+ }
+
+ _dirty = false;
+ }
+
+ return _transform;
+}
+#elif defined(QFX_RENDER_OPENGL)
+QMatrix4x4 QFxRotation3D::transform() const
+{
+ if (_dirty) {
+ _dirty = false;
+ _transform = QMatrix4x4();
+
+ if (!isIdentity()) {
+ if (angle() != 0.) {
+ qreal x = _axis.endX() - _axis.startX();
+ qreal y = _axis.endY() - _axis.startY();
+ qreal z = _axis.endZ();
+
+ _transform.translate(_axis.startX(), _axis.startY(), 0);
+ _transform.rotate(angle(), x, y, z);
+ _transform.translate(-_axis.startX(), -_axis.startY(), 0);
+ }
+ }
+ }
+
+ return _transform;
+}
+#endif
+
+void QFxRotation3D::update()
+{
+ _dirty = true;
+ QFxTransform::update();
+}
+
+/*!
+ \internal
+ \qmlclass Translation3D
+ \brief A Translation3D object provides a way to move an Item along an axis.
+
+ The following example translates the image to 10, 3.
+ \qml
+Image {
+ source: "logo.png"
+ transform: [
+ Translation3D {
+ axis.startX: 0
+ axis.startY: 0
+ axis.endX: 1
+ axis.endY: .3
+ distance: 10
+ }
+ ]
+}
+ \endqml
+*/
+
+QML_DEFINE_TYPE(QFxTranslation3D,Translation3D)
+
+QFxTranslation3D::QFxTranslation3D(QObject *parent)
+: QFxTransform(parent), _distance(0), _dirty(true)
+{
+ connect(&_axis, SIGNAL(updated()), this, SLOT(update()));
+}
+
+QFxTranslation3D::~QFxTranslation3D()
+{
+}
+
+/*!
+ \qmlproperty real Translation3D::axis.startX
+ \qmlproperty real Translation3D::axis.startY
+ \qmlproperty real Translation3D::axis.endX
+ \qmlproperty real Translation3D::axis.endY
+ \qmlproperty real Translation3D::axis.endZ
+
+ A translation axis is specified by 2 points in 3D space: a start
+ point and an end point. The z-position of the start point is assumed
+ to be 0, and cannot be changed. Changing the z-position of the end
+ point is only valid when running under OpenGL.
+
+ \sa Axis
+*/
+QFxAxis *QFxTranslation3D::axis()
+{
+ return &_axis;
+}
+
+/*!
+ \qmlproperty real Translation3D::distance
+
+ The distance to translate along the specified axis. distance is a
+ multiplier; in the example below, a distance of 1 would translate to
+ 100, 50, while a distance of 0.5 would translate to 50, 25.
+
+ \qml
+ Translation3D { axis.startX: 0; axis.startY: 0; axis.endX: 100; axis.endY: 50 }
+ \endqml
+*/
+qreal QFxTranslation3D::distance() const
+{
+ return _distance;
+}
+
+void QFxTranslation3D::setDistance(qreal distance)
+{
+ _distance = distance;
+ update();
+}
+
+bool QFxTranslation3D::isIdentity() const
+{
+ return (_distance == 0.) || (_axis.endZ() == 0. && _axis.endY() == _axis.startY() && _axis.endX() == _axis.startX());
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+QTransform QFxTranslation3D::transform() const
+{
+ if (_dirty) {
+ _transform = QTransform();
+
+ if (!isIdentity()) {
+ if (distance() != 0.) {
+ QTransform trans;
+ trans.translate((_axis.endX() - _axis.startX()) * distance(),
+ (_axis.endY() - _axis.startY()) * distance());
+ _transform *= trans;
+ }
+ }
+
+ _dirty = false;
+ }
+
+ return _transform;
+}
+#elif defined(QFX_RENDER_OPENGL)
+QMatrix4x4 QFxTranslation3D::transform() const
+{
+ if (_dirty) {
+ _dirty = false;
+ _transform = QMatrix4x4();
+
+ if (!isIdentity()) {
+ if (distance() != 0.)
+ _transform.translate((_axis.endX() - _axis.startX()) * distance(),
+ (_axis.endY() - _axis.startY()) * distance(),
+ (_axis.endZ()) * distance());
+
+ }
+ }
+
+ return _transform;
+}
+#endif
+
+void QFxTranslation3D::update()
+{
+ _dirty = true;
+
+#if !defined(QFX_RENDER_OPENGL)
+ if (_axis.endZ() != 0. && distance() != 0.) {
+ qmlInfo(this) << "QTransform cannot translate along Z-axis.";
+ }
+#endif
+
+ QFxTransform::update();
+}
+
+/*!
+ \internal
+ \qmlclass Perspective
+ \brief A Perspective object specifies a perspective transformation.
+
+ A Perspective transform only affects an item when running under
+ OpenGL. When running under software rasterization it has no effect.
+*/
+
+QML_DEFINE_TYPE(QFxPerspective,Perspective)
+
+QFxPerspective::QFxPerspective(QObject *parent)
+ : QFxTransform(parent)
+{
+}
+
+QFxPerspective::~QFxPerspective()
+{
+}
+
+#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
+
+/*!
+ \qmlproperty real Perspective::angle
+*/
+
+/*!
+ \qmlproperty real Perspective::aspect
+*/
+
+/*!
+ \qmlproperty real Perspective::x
+*/
+
+/*!
+ \qmlproperty real Perspective::y
+*/
+
+/*!
+ \qmlproperty real Perspective::scale
+*/
+
+/*!
+ \qmlclass Squish
+ \brief A Squish object allows you to distort an item's appearance by 'squishing' it.
+
+ Conceptually, a Squish works by allowing you to move the four corners of an item,
+ and distorting the item to fit into the newly created polygon.
+
+ \image squish-transform.png
+
+ Here is an example of various \l Image squishes.
+ \qml
+ Rect {
+ id: Screen
+ width: 360; height: 80
+ color: "white"
+
+ HorizontalLayout {
+ margin: 10
+ spacing: 10
+ Image { source: "qt.png" }
+ Image {
+ source: "qt.png"
+ transform: Squish {
+ x:0; y:0; width:60; height:60
+ topLeftX:0; topLeftY:0
+ topRightX:50; topRightY:10
+ bottomLeftX:0; bottomLeftY:60
+ bottomRightX: 60; bottomRightY:60
+ }
+ }
+ Image {
+ source: "qt.png"
+ transform: Squish {
+ x:0; y:0; width:60; height:60
+ topLeftX:0; topLeftY:0
+ topRightX:50; topRightY:0
+ bottomLeftX:10; bottomLeftY:50
+ bottomRightX: 60; bottomRightY:60
+ }
+ }
+ Image {
+ source: "qt.png"
+ transform: Squish {
+ x:0; y:0; width:60; height:60
+ topLeftX:0; topLeftY:10
+ topRightX:60; topRightY:10
+ bottomLeftX:0; bottomLeftY:50
+ bottomRightX: 60; bottomRightY:50
+ }
+ }
+ Image {
+ source: "qt.png"
+ transform: Squish {
+ x:0; y:0; width:60; height:60
+ topLeftX:10; topLeftY:0
+ topRightX:50; topRightY:0
+ bottomLeftX:10; bottomLeftY:60
+ bottomRightX: 50; bottomRightY:60
+ }
+ }
+ }
+ }
+ \endqml
+
+ \image squish.png
+*/
+QML_DEFINE_TYPE(QFxSquish,Squish)
+
+QFxSquish::QFxSquish(QObject *parent)
+ : QFxTransform(parent)
+{
+}
+
+QFxSquish::~QFxSquish()
+{
+}
+
+/*!
+ \qmlproperty real Squish::x
+ \qmlproperty real Squish::y
+ \qmlproperty real Squish::width
+ \qmlproperty real Squish::height
+
+ This is usually set to the original geometry of the item being squished.
+*/
+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();
+}
+
+/*!
+ \qmlproperty real Squish::topLeftX
+ \qmlproperty real Squish::topLeftY
+
+ The top left point for the squish.
+*/
+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();
+}
+
+/*!
+ \qmlproperty real Squish::topRightX
+ \qmlproperty real Squish::topRightY
+
+ The top right point for the squish.
+*/
+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();
+}
+
+/*!
+ \qmlproperty real Squish::bottomLeftX
+ \qmlproperty real Squish::bottomLeftY
+
+ The bottom left point for the squish.
+*/
+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();
+}
+
+/*!
+ \qmlproperty real Squish::bottomRightX
+ \qmlproperty real Squish::bottomRightY
+
+ The bottom right point for the squish.
+*/
+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();
+}
+
+bool QFxSquish::isIdentity() const
+{
+ return false;
+}
+
+#if defined(QFX_RENDER_QPAINTER)
+QTransform 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;
+ QTransform::quadToQuad(poly, poly2, t);
+ return t;
+}
+#elif defined(QFX_RENDER_OPENGL)
+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;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/declarative/fx/qfxtransform.h b/src/declarative/fx/qfxtransform.h
new file mode 100644
index 0000000..7be8adc
--- /dev/null
+++ b/src/declarative/fx/qfxtransform.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 QFXTRANSFORM_H
+#define QFXTRANSFORM_H
+
+#include <QtCore/QObject>
+#include <QtGui/QTransform>
+#if defined(QFX_RENDER_OPENGL)
+#include <QtGui/qmatrix4x4.h>
+#endif
+#include <QtDeclarative/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);
+ ~QFxTransform();
+
+ void update();
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+};
+QML_DECLARE_TYPE(QFxTransform)
+
+class Q_DECLARATIVE_EXPORT QFxAxis : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal startX READ startX WRITE setStartX)
+ Q_PROPERTY(qreal startY READ startY WRITE setStartY)
+ Q_PROPERTY(qreal endX READ endX WRITE setEndX)
+ Q_PROPERTY(qreal endY READ endY WRITE setEndY)
+ Q_PROPERTY(qreal endZ READ endZ WRITE setEndZ)
+public:
+ QFxAxis(QObject *parent=0);
+ ~QFxAxis();
+
+ qreal startX() const;
+ void setStartX(qreal);
+
+ qreal startY() const;
+ void setStartY(qreal);
+
+ qreal endX() const;
+ void setEndX(qreal);
+
+ qreal endY() const;
+ void setEndY(qreal);
+
+ qreal endZ() const;
+ void setEndZ(qreal);
+
+Q_SIGNALS:
+ void updated();
+
+private:
+ qreal _startX;
+ qreal _startY;
+ qreal _endX;
+ qreal _endY;
+ qreal _endZ;
+};
+QML_DECLARE_TYPE(QFxAxis)
+
+class Q_DECLARATIVE_EXPORT QFxRotation : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(qreal originX READ originX WRITE setOriginX)
+ Q_PROPERTY(qreal originY READ originY WRITE setOriginY)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged())
+public:
+ QFxRotation(QObject *parent=0);
+ ~QFxRotation();
+
+ qreal originX() const;
+ void setOriginX(qreal);
+
+ qreal originY() const;
+ void setOriginY(qreal);
+
+ qreal angle() const;
+ void setAngle(qreal);
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+
+Q_SIGNALS:
+ void angleChanged();
+
+private Q_SLOTS:
+ void update();
+private:
+ qreal _originX;
+ qreal _originY;
+ qreal _angle;
+
+ mutable bool _dirty;
+ mutable QSimpleCanvas::Matrix _transform;
+};
+QML_DECLARE_TYPE(QFxRotation)
+
+class Q_DECLARATIVE_EXPORT QFxRotation3D : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFxAxis *axis READ axis)
+ Q_PROPERTY(qreal angle READ angle WRITE setAngle)
+public:
+ QFxRotation3D(QObject *parent=0);
+ ~QFxRotation3D();
+
+ QFxAxis *axis();
+
+ qreal angle() const;
+ void setAngle(qreal);
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+
+private Q_SLOTS:
+ void update();
+private:
+ QFxAxis _axis;
+ qreal _angle;
+
+ mutable bool _dirty;
+ mutable QSimpleCanvas::Matrix _transform;
+};
+QML_DECLARE_TYPE(QFxRotation3D)
+
+class Q_DECLARATIVE_EXPORT QFxTranslation3D : public QFxTransform
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QFxAxis *axis READ axis)
+ Q_PROPERTY(qreal distance READ distance WRITE setDistance)
+public:
+ QFxTranslation3D(QObject *parent=0);
+ ~QFxTranslation3D();
+
+ QFxAxis *axis();
+
+ qreal distance() const;
+ void setDistance(qreal);
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+
+private Q_SLOTS:
+ void update();
+private:
+ QFxAxis _axis;
+ qreal _distance;
+
+ mutable bool _dirty;
+ mutable QSimpleCanvas::Matrix _transform;
+};
+QML_DECLARE_TYPE(QFxTranslation3D)
+
+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);
+ ~QFxPerspective();
+
+ 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 topLeftX READ topLeft_x WRITE settopLeft_x)
+ Q_PROPERTY(qreal topLeftY READ topLeft_y WRITE settopLeft_y)
+ Q_PROPERTY(qreal topRightX READ topRight_x WRITE settopRight_x)
+ Q_PROPERTY(qreal topRightY READ topRight_y WRITE settopRight_y)
+ Q_PROPERTY(qreal bottomLeftX READ bottomLeft_x WRITE setbottomLeft_x)
+ Q_PROPERTY(qreal bottomLeftY READ bottomLeft_y WRITE setbottomLeft_y)
+ Q_PROPERTY(qreal bottomRightX READ bottomRight_x WRITE setbottomRight_x)
+ Q_PROPERTY(qreal bottomRightY READ bottomRight_y WRITE setbottomRight_y)
+public:
+ QFxSquish(QObject *parent=0);
+ ~QFxSquish();
+
+ 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);
+
+ virtual bool isIdentity() const;
+ virtual QSimpleCanvas::Matrix transform() const;
+
+private:
+ QPointF p;
+ QSizeF s;
+ QPointF p1, p2, p3, p4;
+};
+QML_DECLARE_TYPE(QFxSquish)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFXTRANSFORM_H
diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp
new file mode 100644
index 0000000..c60a379
--- /dev/null
+++ b/src/declarative/fx/qfxvisualitemmodel.cpp
@@ -0,0 +1,771 @@
+/****************************************************************************
+**
+** 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 "private/qmetaobjectbuilder_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;
+
+ struct ObjectRef {
+ ObjectRef(QObject *object=0) : obj(object), ref(1) {}
+ QObject *obj;
+ int ref;
+ };
+ class Cache : public QHash<int, ObjectRef> {
+ public:
+ QObject *getItem(int index) {
+ QObject *item = 0;
+ QHash<int,ObjectRef>::iterator it = find(index);
+ if (it != end()) {
+ (*it).ref++;
+ item = (*it).obj;
+ }
+ return item;
+ }
+ QObject *item(int index) {
+ QObject *item = 0;
+ QHash<int, ObjectRef>::const_iterator it = find(index);
+ if (it != end())
+ item = (*it).obj;
+ return item;
+ }
+ void insertItem(int index, QObject *obj) {
+ insert(index, ObjectRef(obj));
+ }
+ bool releaseItem(QObject *obj) {
+ QHash<int, ObjectRef>::iterator it = begin();
+ for (; it != end(); ++it) {
+ ObjectRef &objRef = *it;
+ if (objRef.obj == obj) {
+ if (--objRef.ref == 0) {
+ erase(it);
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+ };
+
+ Cache m_cache;
+ QHash<QObject *, QmlPackage*> m_packaged;
+
+ 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.value(iter.key());
+ }
+ }
+ } 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(0)))
+{
+}
+
+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)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)),
+ this, SLOT(_q_createdPackage(int,QmlPackage*)));
+ QObject::disconnect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)),
+ this, SLOT(_q_destroyingPackage(QmlPackage*)));
+ 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)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(createdPackage(int,QmlPackage*)),
+ this, SLOT(_q_createdPackage(int,QmlPackage*)));
+ QObject::connect(d->m_visualItemModel, SIGNAL(destroyingPackage(QmlPackage*)),
+ this, SLOT(_q_destroyingPackage(QmlPackage*)));
+ 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);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->delegate();
+ 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);
+}
+
+/*
+ Returns ReleaseStatus flags.
+*/
+QFxVisualItemModel::ReleaseFlags QFxVisualItemModel::release(QFxItem *item)
+{
+ Q_D(QFxVisualItemModel);
+ if (d->m_visualItemModel)
+ return d->m_visualItemModel->release(item);
+
+ ReleaseFlags stat = 0;
+ QObject *obj = item;
+ bool inPackage = false;
+
+ QHash<QObject*,QmlPackage*>::iterator it = d->m_packaged.find(item);
+ if (it != d->m_packaged.end()) {
+ QmlPackage *package = *it;
+ d->m_packaged.erase(it);
+ if (d->m_packaged.contains(item))
+ stat |= Referenced;
+ inPackage = true;
+ obj = package; // fall through and delete
+ }
+
+ if (d->m_cache.releaseItem(obj)) {
+ if (inPackage)
+ emit destroyingPackage(qobject_cast<QmlPackage*>(obj));
+ stat |= Destroyed;
+ delete obj;
+ } else if (!inPackage) {
+ stat |= Referenced;
+ }
+
+ return stat;
+}
+
+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 = d->m_cache.getItem(index);
+ if (!nobj) {
+ QmlContext *ccontext = d->m_context;
+ if (!ccontext) ccontext = qmlContext(this);
+ QmlContext *ctxt = new QmlContext(ccontext);
+ 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();
+ if (nobj) {
+ ctxt->setParent(nobj);
+ data->setParent(nobj);
+ d->m_cache.insertItem(index, nobj);
+ if (QmlPackage *package = qobject_cast<QmlPackage *>(nobj))
+ emit createdPackage(index, package);
+ } else {
+ delete data;
+ delete ctxt;
+ qWarning() << d->m_delegate->errors();
+ }
+ }
+ 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.insertMulti(item, 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;
+ QObject *nobj = d->m_cache.item(index);
+ if (nobj) {
+ QFxItem *item = qobject_cast<QFxItem *>(nobj);
+ if (item) {
+ QmlExpression e(qmlContext(item), expression, objectContext);
+ e.setTrackChange(false);
+ value = e.value();
+ }
+ } else {
+ QmlContext *ccontext = d->m_context;
+ if (!ccontext) ccontext = qmlContext(this);
+ QmlContext *ctxt = new QmlContext(ccontext);
+ 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;
+}
+
+int QFxVisualItemModel::indexOf(QFxItem *item, QObject *objectContext) const
+{
+ QmlExpression e(qmlContext(item), QLatin1String("index"), objectContext);
+ e.setTrackChange(false);
+ QVariant value = e.value();
+ if (value.isValid())
+ return value.toInt();
+ return -1;
+}
+
+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 (QObject *item = d->m_cache.item(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).value(role));
+ } 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,QFxVisualItemModelPrivate::ObjectRef> items;
+ for (QHash<int,QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= index) {
+ QFxVisualItemModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() + count;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QFxVisualItemModelData *data = d->data(objRef.obj);
+ 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, QFxVisualItemModelPrivate::ObjectRef> items;
+ for (QHash<int, QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+ if (iter.key() >= index && iter.key() < index + count) {
+ QFxVisualItemModelPrivate::ObjectRef objRef = *iter;
+ iter = d->m_cache.erase(iter);
+ items.insertMulti(-1, objRef); //XXX perhaps better to maintain separately
+ QFxVisualItemModelData *data = d->data(objRef.obj);
+ data->setIndex(-1);
+ } else if (iter.key() >= index + count) {
+ QFxVisualItemModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - count;
+ iter = d->m_cache.erase(iter);
+ items.insert(index, objRef);
+ QFxVisualItemModelData *data = d->data(objRef.obj);
+ 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,QFxVisualItemModelPrivate::ObjectRef> items;
+ for (QHash<int,QFxVisualItemModelPrivate::ObjectRef>::Iterator iter = d->m_cache.begin();
+ iter != d->m_cache.end(); ) {
+
+ if (iter.key() >= from && iter.key() < from + count) {
+ QFxVisualItemModelPrivate::ObjectRef objRef = *iter;
+ int index = iter.key() - from + to;
+ iter = d->m_cache.erase(iter);
+
+ items.insert(index, objRef);
+
+ QFxVisualItemModelData *data = d->data(objRef.obj);
+ 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);
+}
+
+void QFxVisualItemModel::_q_createdPackage(int index, QmlPackage *package)
+{
+ Q_D(QFxVisualItemModel);
+ emit createdItem(index, qobject_cast<QFxItem*>(package->part(d->m_part)));
+}
+
+void QFxVisualItemModel::_q_destroyingPackage(QmlPackage *package)
+{
+ Q_D(QFxVisualItemModel);
+ emit destroyingItem(qobject_cast<QFxItem*>(package->part(d->m_part)));
+}
+
+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..968cc2e
--- /dev/null
+++ b/src/declarative/fx/qfxvisualitemmodel.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 QFXVISUALITEMMODEL_H
+#define QFXVISUALITEMMODEL_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtDeclarative/qml.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+/*****************************************************************************
+ *****************************************************************************
+ XXX Experimental
+ *****************************************************************************
+*****************************************************************************/
+
+class QFxItem;
+class QmlComponent;
+class QmlPackage;
+class QFxVisualItemModelPrivate;
+class Q_DECLARATIVE_EXPORT 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 &);
+
+ enum ReleaseFlag { Referenced = 0x01, Destroyed = 0x02 };
+ Q_DECLARE_FLAGS(ReleaseFlags, ReleaseFlag)
+
+ int count() const;
+ QFxItem *item(int index, bool complete=true);
+ QFxItem *item(int index, const QByteArray &, bool complete=true);
+ ReleaseFlags release(QFxItem *item);
+ void completeItem();
+ QVariant evaluate(int index, const QString &expression, QObject *objectContext);
+
+ int indexOf(QFxItem *item, QObject *objectContext) const;
+
+ QObject *parts();
+
+Q_SIGNALS:
+ void itemsInserted(int index, int count);
+ void itemsRemoved(int index, int count);
+ void itemsMoved(int from, int to, int count);
+ void createdItem(int index, QFxItem *item);
+ void createdPackage(int index, QmlPackage *package);
+ void destroyingItem(QFxItem *item);
+ void destroyingPackage(QmlPackage *package);
+
+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&);
+ void _q_createdPackage(int index, QmlPackage *package);
+ void _q_destroyingPackage(QmlPackage *package);
+
+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..bfccd34
--- /dev/null
+++ b/src/declarative/fx/qfxwebview.cpp
@@ -0,0 +1,1076 @@
+/****************************************************************************
+**
+** 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/qfxpainteditem_p.h>
+
+QT_BEGIN_NAMESPACE
+QML_DEFINE_TYPE(QFxWebView,WebView)
+
+static const int MAX_DOUBLECLICK_TIME=500; // XXX need better gesture system
+
+class QFxWebSettings : public QObject {
+ Q_OBJECT
+ /*
+ StandardFont,
+ FixedFont,
+ SerifFont,
+ SansSerifFont,
+ CursiveFont,
+ FantasyFont
+
+ MinimumFontSize,
+ MinimumLogicalFontSize,
+ DefaultFontSize,
+ DefaultFixedFontSize
+ */
+
+ Q_PROPERTY(bool autoLoadImages READ autoLoadImages WRITE setAutoLoadImages)
+ Q_PROPERTY(bool javascriptEnabled READ javascriptEnabled WRITE setJavascriptEnabled)
+ Q_PROPERTY(bool javaEnabled READ javaEnabled WRITE setJavaEnabled)
+ Q_PROPERTY(bool pluginsEnabled READ pluginsEnabled WRITE setPluginsEnabled)
+ Q_PROPERTY(bool privateBrowsingEnabled READ privateBrowsingEnabled WRITE setPrivateBrowsingEnabled)
+ Q_PROPERTY(bool javascriptCanOpenWindows READ javascriptCanOpenWindows WRITE setJavascriptCanOpenWindows)
+ Q_PROPERTY(bool javascriptCanAccessClipboard READ javascriptCanAccessClipboard WRITE setJavascriptCanAccessClipboard)
+ Q_PROPERTY(bool developerExtrasEnabled READ developerExtrasEnabled WRITE setDeveloperExtrasEnabled)
+ Q_PROPERTY(bool linksIncludedInFocusChain READ linksIncludedInFocusChain WRITE setLinksIncludedInFocusChain)
+ Q_PROPERTY(bool zoomTextOnly READ zoomTextOnly WRITE setZoomTextOnly)
+ Q_PROPERTY(bool printElementBackgrounds READ printElementBackgrounds WRITE setPrintElementBackgrounds)
+ Q_PROPERTY(bool offlineStorageDatabaseEnabled READ offlineStorageDatabaseEnabled WRITE setOfflineStorageDatabaseEnabled)
+ Q_PROPERTY(bool offlineWebApplicationCacheEnabled READ offlineWebApplicationCacheEnabled WRITE setOfflineWebApplicationCacheEnabled)
+ Q_PROPERTY(bool localStorageDatabaseEnabled READ localStorageDatabaseEnabled WRITE setLocalStorageDatabaseEnabled)
+
+public:
+ QFxWebSettings() {}
+
+ bool autoLoadImages() const { return s->testAttribute(QWebSettings::AutoLoadImages); }
+ void setAutoLoadImages(bool on) { s->setAttribute(QWebSettings::AutoLoadImages, on); }
+ bool javascriptEnabled() const { return s->testAttribute(QWebSettings::JavascriptEnabled); }
+ void setJavascriptEnabled(bool on) { s->setAttribute(QWebSettings::JavascriptEnabled, on); }
+ bool javaEnabled() const { return s->testAttribute(QWebSettings::JavaEnabled); }
+ void setJavaEnabled(bool on) { s->setAttribute(QWebSettings::JavaEnabled, on); }
+ bool pluginsEnabled() const { return s->testAttribute(QWebSettings::PluginsEnabled); }
+ void setPluginsEnabled(bool on) { s->setAttribute(QWebSettings::PluginsEnabled, on); }
+ bool privateBrowsingEnabled() const { return s->testAttribute(QWebSettings::PrivateBrowsingEnabled); }
+ void setPrivateBrowsingEnabled(bool on) { s->setAttribute(QWebSettings::PrivateBrowsingEnabled, on); }
+ bool javascriptCanOpenWindows() const { return s->testAttribute(QWebSettings::JavascriptCanOpenWindows); }
+ void setJavascriptCanOpenWindows(bool on) { s->setAttribute(QWebSettings::JavascriptCanOpenWindows, on); }
+ bool javascriptCanAccessClipboard() const { return s->testAttribute(QWebSettings::JavascriptCanAccessClipboard); }
+ void setJavascriptCanAccessClipboard(bool on) { s->setAttribute(QWebSettings::JavascriptCanAccessClipboard, on); }
+ bool developerExtrasEnabled() const { return s->testAttribute(QWebSettings::DeveloperExtrasEnabled); }
+ void setDeveloperExtrasEnabled(bool on) { s->setAttribute(QWebSettings::DeveloperExtrasEnabled, on); }
+ bool linksIncludedInFocusChain() const { return s->testAttribute(QWebSettings::LinksIncludedInFocusChain); }
+ void setLinksIncludedInFocusChain(bool on) { s->setAttribute(QWebSettings::LinksIncludedInFocusChain, on); }
+ bool zoomTextOnly() const { return s->testAttribute(QWebSettings::ZoomTextOnly); }
+ void setZoomTextOnly(bool on) { s->setAttribute(QWebSettings::ZoomTextOnly, on); }
+ bool printElementBackgrounds() const { return s->testAttribute(QWebSettings::PrintElementBackgrounds); }
+ void setPrintElementBackgrounds(bool on) { s->setAttribute(QWebSettings::PrintElementBackgrounds, on); }
+ bool offlineStorageDatabaseEnabled() const { return s->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled); }
+ void setOfflineStorageDatabaseEnabled(bool on) { s->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, on); }
+ bool offlineWebApplicationCacheEnabled() const { return s->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled); }
+ void setOfflineWebApplicationCacheEnabled(bool on) { s->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, on); }
+ bool localStorageDatabaseEnabled() const { return s->testAttribute(QWebSettings::LocalStorageDatabaseEnabled); }
+ void setLocalStorageDatabaseEnabled(bool on) { s->setAttribute(QWebSettings::LocalStorageDatabaseEnabled, on); }
+
+ QWebSettings *s;
+};
+
+
+class QFxWebViewPrivate : public QFxPaintedItemPrivate
+{
+ Q_DECLARE_PUBLIC(QFxWebView)
+
+public:
+ QFxWebViewPrivate()
+ : QFxPaintedItemPrivate(), page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0),
+ 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)
+ QPixmap 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;
+ 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;
+ mutable QFxWebSettings settings;
+};
+
+
+/*!
+ \qmlclass WebView
+ \brief The WebView item 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 item 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.
+
+ \qml
+ WebView {
+ url: "http://www.nokia.com"
+ width: 490
+ height: 400
+ scale: 0.5
+ smooth: true
+ }
+ \endqml
+
+ \image webview.png
+
+ The item 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 item 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)
+ : QFxPaintedItem(*(new QFxWebViewPrivate), parent)
+{
+ init();
+}
+
+QFxWebView::QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent)
+ : QFxPaintedItem(dd, parent)
+{
+ init();
+}
+
+QFxWebView::~QFxWebView()
+{
+ Q_D(QFxWebView);
+ delete d->page;
+}
+
+void QFxWebView::init()
+{
+ Q_D(QFxWebView);
+
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setOptions(HasContents | MouseEvents);
+ setFocusable(true);
+
+ d->page = 0;
+}
+
+void QFxWebView::componentComplete()
+{
+ QFxPaintedItem::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 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 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
+{
+ return page()->mainFrame()->url().toString();
+}
+
+void QFxWebView::setUrl(const QString &n)
+{
+ Q_D(QFxWebView);
+ if (n == page()->mainFrame()->url().toString())
+ return;
+
+ page()->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+
+ QUrl url(n);
+ if (url.isRelative())
+ url = qmlContext(this)->resolvedUrl(n);
+
+ if (isComponentComplete())
+ 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 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 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 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();
+}
+
+void QFxWebView::updateCacheForVisibility()
+{
+ Q_D(QFxWebView);
+ if (!isVisible())
+ d->clearCache();
+}
+
+void QFxWebView::expandToWebPage()
+{
+ Q_D(QFxWebView);
+ QSize cs = 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 != page()->viewportSize()) {
+ 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();
+ QFxPaintedItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QFxWebView::paintPage(const QRect& r)
+{
+ Q_D(QFxWebView);
+ if (d->page->mainFrame()->contentsSize() != contentsSize())
+ setContentsSize(d->page->mainFrame()->contentsSize());
+ 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 QFxWebView::cacheSize
+
+ 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();
+ QFxPaintedItem::dump(depth);
+}
+
+void QFxWebView::drawContents(QPainter *p, const QRect &r)
+{
+ page()->mainFrame()->render(p,r);
+}
+
+QString QFxWebView::propertyInfo() const
+{
+ return 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) {
+ page()->event(d->lastPress);
+ delete d->lastPress;
+ d->lastPress = 0;
+ }
+ if (d->lastRelease) {
+ 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())
+ QFxPaintedItem::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())
+ QFxPaintedItem::mouseReleaseEvent(event);
+}
+
+void QFxWebView::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive && !d->dcTimer.isActive()) {
+ QMouseEvent *me = sceneMouseEventToMouseEvent(event);
+ 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())
+ QFxPaintedItem::mouseMoveEvent(event);
+}
+
+void QFxWebView::keyPressEvent(QKeyEvent* event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive)
+ page()->event(event);
+ if (!event->isAccepted())
+ QFxPaintedItem::keyPressEvent(event);
+}
+
+void QFxWebView::keyReleaseEvent(QKeyEvent* event)
+{
+ Q_D(const QFxWebView);
+ if (d->interactive)
+ page()->event(event);
+ if (!event->isAccepted())
+ QFxPaintedItem::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
+{
+ return 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
+{
+ return page()->action(QWebPage::Forward);
+}
+
+/*!
+ \qmlproperty action WebView::reload
+ This property holds the action for reloading with the current URL
+*/
+QAction *QFxWebView::reloadAction() const
+{
+ return page()->action(QWebPage::Reload);
+}
+
+/*!
+ \qmlproperty action WebView::stop
+ This property holds the action for stopping loading with the current URL
+*/
+QAction *QFxWebView::stopAction() const
+{
+ return 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
+{
+ return page()->mainFrame()->title();
+}
+
+
+
+/*!
+ \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
+{
+ return page()->mainFrame()->icon().pixmap(QSize(256,256));
+}
+
+
+/*!
+ \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)
+{
+ page()->mainFrame()->setTextSizeMultiplier(factor);
+}
+
+/*!
+ Returns the value of the multiplier used to scale the text in a Web page.
+*/
+qreal QFxWebView::textSizeMultiplier() const
+{
+ return 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);
+
+ if (!d->page) {
+ QFxWebView *self = const_cast<QFxWebView*>(this);
+ QWebPage *wp = new QFxWebPage(self);
+
+ // QML items 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(qmlEngine(this)->networkAccessManager());
+
+ self->setPage(wp);
+
+ return wp;
+ }
+
+ return d->page;
+}
+
+
+// The QObject interface to settings().
+/*!
+ \qmlproperty bool WebView::settings.autoLoadImages
+ \qmlproperty bool WebView::settings.javascriptEnabled
+ \qmlproperty bool WebView::settings.javaEnabled
+ \qmlproperty bool WebView::settings.pluginsEnabled
+ \qmlproperty bool WebView::settings.privateBrowsingEnabled
+ \qmlproperty bool WebView::settings.javascriptCanOpenWindows
+ \qmlproperty bool WebView::settings.javascriptCanAccessClipboard
+ \qmlproperty bool WebView::settings.developerExtrasEnabled
+ \qmlproperty bool WebView::settings.linksIncludedInFocusChain
+ \qmlproperty bool WebView::settings.zoomTextOnly
+ \qmlproperty bool WebView::settings.printElementBackgrounds
+ \qmlproperty bool WebView::settings.offlineStorageDatabaseEnabled
+ \qmlproperty bool WebView::settings.offlineWebApplicationCacheEnabled
+ \qmlproperty bool WebView::settings.localStorageDatabaseEnabled
+
+ These properties give access to the settings controlling the web view.
+
+ See QWebSettings for the list of sub-properties.
+
+ \qml
+ WebView {
+ settings.pluginsEnabled: true
+ ...
+ }
+ \endqml
+*/
+QObject *QFxWebView::settingsObject() const
+{
+ Q_D(const QFxWebView);
+ d->settings.s = page()->settings();
+ return &d->settings;
+}
+
+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.
+
+ \qml
+ WebView {
+ html: "<p>This is <b>HTML</b>."
+ }
+ \endqml
+*/
+void QFxWebView::setHtml(const QString &html, const QUrl &baseUrl)
+{
+ Q_D(QFxWebView);
+ page()->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+ if (isComponentComplete())
+ page()->mainFrame()->setHtml(html, qmlContext(this)->resolvedUrl(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);
+ page()->setViewportSize(QSize(
+ d->idealwidth>0 ? d->idealwidth : width(),
+ d->idealheight>0 ? d->idealheight : height()));
+
+ if (isComponentComplete())
+ page()->mainFrame()->setContent(data,mimeType,qmlContext(this)->resolvedUrl(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 = qmlEngine(webview);
+ component = new QmlComponent(engine, url, this);
+ item = 0;
+ if (component->isReady())
+ qmlLoaded();
+ else
+ connect(component, SIGNAL(statusChanged(QmlComponent::Status)), this, SLOT(qmlLoaded()));
+ }
+
+public Q_SLOTS:
+ void qmlLoaded()
+ {
+ item = qobject_cast<QFxItem*>(component->create(qmlContext(webview)));
+ 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 = qmlContext(view())->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..28ef6c3
--- /dev/null
+++ b/src/declarative/fx/qfxwebview.h
@@ -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$
+**
+****************************************************************************/
+
+#ifndef QFXWEBVIEW_H
+#define QFXWEBVIEW_H
+
+#include <QtGui/QAction>
+#include <QtCore/QUrl>
+#include <QtDeclarative/qfxglobal.h>
+#include <QtDeclarative/qfxpainteditem.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtWebKit/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 QFxPaintedItem
+{
+ 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(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)
+
+ Q_PROPERTY(QObject* settings READ settingsObject)
+
+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;
+
+ 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;
+
+ 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;
+ QObject *settingsObject() 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 drawContents(QPainter *, const QRect &);
+
+ 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..421c2f7
--- /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;
+}
+
+/*!
+ \qmlproperty 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..cc36010
--- /dev/null
+++ b/src/declarative/fx/qfxwidgetcontainer.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 QFXWIDGETCONTAINER_H
+#define QFXWIDGETCONTAINER_H
+
+#include <QtDeclarative/qfxitem.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Declarative)
+
+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