/**************************************************************************** ** ** 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 #include #include #include #include #include #include #include #include #include "qmlengine.h" #include "qmlstate.h" #include "qlistmodelinterface.h" #include "qfxtransform.h" #include "qfxscalegrid.h" #include "qfxview.h" #include "qmlstategroup.h" #include "qfxitem_p.h" #include "qfxitem.h" #include #include QT_BEGIN_NAMESPACE #ifndef INT_MAX #define INT_MAX 2147483647 #endif QML_DEFINE_NOCREATE_TYPE(QFxContents); QML_DEFINE_TYPE(QFxItem,Item); QML_DEFINE_NOCREATE_TYPE(QSimpleCanvasFilter); /*! \defgroup animation Animation \defgroup coreitems Basic Items \defgroup effects Effects \defgroup layouts Layouts \defgroup states States and Transitions \defgroup utility Utility \defgroup views Views \defgroup widgets Widgets */ /*! \internal \class QFxContents \ingroup utility \brief The QFxContents class gives access to the height and width of an item's contents. */ QFxContents::QFxContents() : _height(0), _width(0) { } /*! \property QFxContents::height \brief The height of the contents. */ int QFxContents::height() const { return _height; } /*! \property QFxContents::width \brief The width of the contents. */ int QFxContents::width() const { return _width; } //TODO: optimization: only check sender(), if there is one void QFxContents::calcHeight() { int oldheight = _height; int top = INT_MAX; int bottom = 0; foreach(const QSimpleCanvasItem *child, _item->QSimpleCanvasItem::children()) { if (child->y() + child->height() > bottom) bottom = (int)child->y() + child->height(); if (child->y() < top) top = (int)child->y(); } _height = bottom - top; if (_height != oldheight) emit heightChanged(); } //TODO: optimization: only check sender(), if there is one void QFxContents::calcWidth() { int oldwidth = _width; int left = INT_MAX; int right = 0; foreach(const QSimpleCanvasItem *child, _item->QSimpleCanvasItem::children()) { if (child->x() + child->width() > right) right = (int)child->x() + child->width(); if (child->x() < left) left = (int)child->x(); } _width = right - left; if (_width != oldwidth) emit widthChanged(); } void QFxContents::setItem(QFxItem *item) { _item = item; foreach(const QSimpleCanvasItem *child, _item->QSimpleCanvasItem::children()) { connect(child, SIGNAL(bottomChanged()), this, SLOT(calcHeight())); connect(child, SIGNAL(rightChanged()), this, SLOT(calcWidth())); } calcHeight(); calcWidth(); } /*! \qmlclass Item QFxItem \brief The Item element is the most basic of all visual canvas members. */ /*! \class QFxItem Item \brief The QFxItem class is a generic QFxView item. It is the base class for all other view items. \qmltext All visual elements in Qt Declarative inherit from QFxItem. Although QFxItem has no visual appearance, it defines all the properties that are common across visual elements - like the x and y position, and the width and height. QFxItem is also useful for grouping elements together. \qml \endqml \endqmltext \ingroup coreitems */ /*! \fn void QFxItem::activeFocusChanged() This signal is emitted when this item gains active focus. */ /*! \fn void QFxItem::baselineChanged() This signal is emitted when the baseline of the item changes. The baseline may change in response to a call to setBaselineOffset() or due to the geometry of the item changing. \sa baselineOffset(), setBaselineOffset() */ /*! \fn void QFxItem::baselineOffsetChanged() This signal is emitted when the baseline of the item is changed via setBaselineOffset(). The baseline corresponds to the baseline of the text contained in the element. It is useful for aligning the text in items placed beside each other. The default baseline is positioned at 2/3 of the height of the item. \sa baselineOffset(), setBaselineOffset() */ /*! \fn void QFxItem::leftChanged() This signal is emitted when the left coordinate of the item changes. */ /*! \fn void QFxItem::rightChanged() This signal is emitted when the right coordinate of the item changes. */ /*! \fn void QFxItem::topChanged() This signal is emitted when the top coordinate of the item changes. */ /*! \fn void QFxItem::bottomChanged() This signal is emitted when the bottom coordinate of the item changes. */ /*! \fn void QFxItem::widthChanged() This signal is emitted when the width of the item changes. */ /*! \fn void QFxItem::heightChanged() This signal is emitted when the height of the item changes. */ /*! \fn void QFxItem::hcenterChanged() This signal is emitted when the horizontal center coordinate of the item changes. */ /*! \fn void QFxItem::vcenterChanged() This signal is emitted when the vertical center coordinate of the item changes. */ /*! \fn void QFxItem::scaleChanged() This signal is emitted when the scale of the item changes. */ /*! \fn void QFxItem::stateChanged(const QString &state) This signal is emitted when the \a state of the item changes. \sa states-transitions */ /*! \fn void QFxItem::keyPress() This signal is emitted when a key is pressed. The key event is available in QML via the QFxKeyEvent \c event property. \qml \endqml \sa keyRelease() */ /*! \fn void QFxItem::keyRelease() This signal is emitted when a key is released. The key event is available in QML via the QFxKeyEvent \c event property. \qml \endqml \sa keyPress() */ /*! \fn void QFxItem::visibleChanged() This signal is emitted when the visibility of the item changes. \sa setVisible() */ /*! \fn void QFxItem::opacityChanged() This signal is emitted when the opacity of the item changes. \sa opacity(), setOpacity() */ /*! \fn void QFxItem::parentChanged() This signal is emitted when the parent of the item changes. \sa setItemParent() */ /*! \fn void QFxItem::focusChanged() This signal is emitted when the item's focus state changes. \sa setFocus() */ /*! \fn QFxItem::QFxItem(QFxItem *parent) Constructs a QFxItem with the given \a parent. */ QFxItem::QFxItem(QFxItem* parent) : QSimpleCanvasItem(*(new QFxItemPrivate), parent) { Q_D(QFxItem); d->init(parent); } /*! \internal */ QFxItem::QFxItem(QFxItemPrivate &dd, QFxItem *parent) : QSimpleCanvasItem(dd, parent) { Q_D(QFxItem); d->init(parent); } /*! \internal */ void QFxItem::doUpdate() { update(); } /*! Destroys the QFxItem. */ QFxItem::~QFxItem() { Q_D(QFxItem); delete d->_anchorLines; d->_anchorLines = 0; } /*! \qmlproperty enum Item::transformOrigin This property holds the origin point around which scale and rotation transform. Nine transform origins are available, as shown in the image below. \image declarative-transformorigin.png This example scales an image about its center. \code \endcode The default transform origin is \c TopLeft. */ /*! \qmlproperty Item Item::parent This property holds the parent of the item. */ void QFxItem::setItemParent(QFxItem *parent) { setParent(parent); } /*! XXX Playing around with view2view transitions. */ void QFxItem::moveToParent(QFxItem *parent) { if(parent && itemParent()) { QPointF me = itemParent()->mapToScene(QPointF(0,0)); QPointF them = parent->mapToScene(QPointF(0,0)); QPointF themx = parent->mapToScene(QPointF(1,0)); QPointF themy = parent->mapToScene(QPointF(0,1)); themx -= them; themy -= them; setItemParent(parent); // XXX - this is silly and will only work in a few cases /* xDiff = rx * themx_x + ry * themy_x yDiff = rx * themx_y + ry * themy_y */ qreal rx = 0; qreal ry = 0; qreal xDiff = them.x() - me.x(); qreal yDiff = them.y() - me.y(); if(themx.x() == 0.) { ry = xDiff / themy.x(); rx = (yDiff - ry * themy.y()) / themx.y(); } else if(themy.x() == 0.) { rx = xDiff / themx.x(); ry = (yDiff - rx * themx.y()) / themy.y(); } else if(themx.y() == 0.) { ry = yDiff / themy.y(); rx = (xDiff - ry * themy.x()) / themx.x(); } else if(themy.y() == 0.) { rx = yDiff / themx.y(); ry = (xDiff - rx * themx.x()) / themy.x(); } else { qreal div = (themy.x() * themx.y() - themy.y() * themx.x()); if(div != 0.) rx = (themx.y() * xDiff - themx.x() * yDiff) / div; if(themy.y() != 0.) ry = (yDiff - rx * themx.y()) / themy.y(); } setX(x() - rx); setY(y() - ry); } else { setItemParent(parent); } } /*! Returns the QFxItem parent of this item. */ QFxItem *QFxItem::itemParent() const { return qobject_cast(QObject::parent()); } /*! \qmlproperty list Item::children \qmlproperty list Item::resources The children property contains the list of visual children of this element. The resources property contains non-visual resources that you want to reference by name. Generally you can rely on Item's default property to handle all this for you, but it can come in handy in some cases. \qml \endqml */ /*! Returns true if all of the attributes set via QML have been set; otherwise returns false. \sa classComplete() */ bool QFxItem::isClassComplete() const { Q_D(const QFxItem); return d->_classComplete; } /*! Returns true if construction of the QML component is complete; otherwise returns false. It is often desireable to delay some processing until the component is completed. \sa componentComplete(). */ bool QFxItem::isComponentComplete() const { Q_D(const QFxItem); return d->_componentComplete; } /*! \property QFxItem::anchors \brief The anchors (alignments) used by the item. */ QFxAnchors *QFxItem::anchors() { Q_D(QFxItem); return d->anchors(); } void QFxItemPrivate::data_removeAt(int) { // ### } int QFxItemPrivate::data_count() const { // ### return 0; } void QFxItemPrivate::data_append(QObject *o) { Q_Q(QFxItem); QFxItem *i = qobject_cast(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 Item::data \default The data property is allows you to freely mix visual children and resources of an element. If you assign a visual element to the data list it becomes a child and if you assign any other object type, it is added as a resource. So you can write: \qml \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 Item::transform This property holds the list of transformations to apply. For more information see \l Transform. */ QList *QFxItem::transform() { Q_D(QFxItem); return &(d->_transform); } /*! Returns true if the item is visible; otherwise returns false. An item is considered visible if its opacity is not 0. */ bool QFxItem::isVisible() const { Q_D(const QFxItem); return d->visible; } /*! Sets the visibility of the item to \a visible. Setting visibility to false sets opacity to 0. Setting the visibility to true restores the opacity to its previous value. */ void QFxItem::setVisible(bool visible) { Q_D(QFxItem); if(visible == d->visible) return; d->visible = visible; if(visible) setOpacity(d->visibleOp); else { d->visibleOp = opacity(); setOpacity(0); } emit visibleChanged(); } /*! \internal */ void QFxItem::dump(int depth) { Q_D(QFxItem); QByteArray ba(depth * 4, ' '); qWarning() << ba.constData() << metaObject()->className() << "(" << (void *)static_cast(this) << ", " << (void *)static_cast(this) << "):" << x() << y() << width() << height() << (void *) itemParent(); } /*! \internal */ QString QFxItem::propertyInfo() const { return QString(); } /*! Creates a new child of the given component \a type. The newChildCreated() signal will be emitted when and if the child is successfully created. \preliminary */ void QFxItem::newChild(const QString &type) { Q_D(QFxItem); QUrl url = itemContext()->resolvedUri(type); if (url.isEmpty()) return; d->_qmlnewloading.append(url); d->_qmlnewcomp.append(new QmlComponent(itemContext()->engine(), url, this)); if(d->_qmlnewcomp.last()->isReady()) qmlLoaded(); else connect(d->_qmlnewcomp.last(), SIGNAL(readyChanged()), this, SLOT(qmlLoaded())); } /*! classBegin() is called when the item is constructed, but its properties have not yet been set. \sa classComplete(), componentComplete(), isClassComplete(), isComponentComplete() */ void QFxItem::classBegin() { Q_D(QFxItem); d->_classComplete = false; d->_componentComplete = false; if(d->_stateGroup) d->_stateGroup->classBegin(); } /*! classComplete() is called when all properties specified in QML have been assigned. It is sometimes desireable to delay some processing until all property assignments are complete. */ void QFxItem::classComplete() { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer cc; #endif Q_D(QFxItem); d->_classComplete = true; if(d->_stateGroup) d->_stateGroup->classComplete(); } /*! componentComplete() is called when all elements in the component have been constructed. It is often desireable to delay some processing until the component is complete an all bindings in the component have been resolved. */ void QFxItem::componentComplete() { Q_D(QFxItem); d->_componentComplete = true; if(d->_stateGroup) d->_stateGroup->componentComplete(); if(d->_anchors) { d->anchors()->connectHAnchors(); d->anchors()->connectVAnchors(); } if(!d->_transform.isEmpty()) updateTransform(); } /*! \internal */ void QFxItem::parentChanged(QSimpleCanvasItem *, QSimpleCanvasItem *) { emit parentChanged(); } /*! \internal */ void QFxItem::reparentItems() { qFatal("EEK"); } void QFxItem::updateTransform() { Q_D(QFxItem); QSimpleCanvas::Matrix trans; for(int ii = d->_transform.count() - 1; ii >= 0; --ii) { QFxTransform *a = d->_transform.at(ii); if(!a->isIdentity()) trans = a->transform() * trans; } setTransform(trans); transformChanged(trans); } void QFxItem::transformChanged(const QSimpleCanvas::Matrix &) { } /*! Returns the current QML context for this item. */ QmlContext *QFxItem::itemContext() const { Q_D(const QFxItem); return d->_ctxt; } QmlStateGroup *QFxItemPrivate::states() { Q_Q(QFxItem); if(!_stateGroup) { _stateGroup = new QmlStateGroup(q); if(!_classComplete) _stateGroup->classBegin(); QObject::connect(_stateGroup, SIGNAL(stateChanged(QString)), q, SIGNAL(stateChanged(QString))); } return _stateGroup; } QFxItemPrivate::AnchorLines::AnchorLines(QFxItem *q) { left.item = q; left.anchorLine = QFxAnchorLine::Left; right.item = q; right.anchorLine = QFxAnchorLine::Right; hCenter.item = q; hCenter.anchorLine = QFxAnchorLine::HCenter; top.item = q; top.anchorLine = QFxAnchorLine::Top; bottom.item = q; bottom.anchorLine = QFxAnchorLine::Bottom; vCenter.item = q; vCenter.anchorLine = QFxAnchorLine::VCenter; } #include "qfxitem.moc" QT_END_NAMESPACE