From a08546507fe0ce356e4183e557d9408295c80610 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 21 Feb 2012 13:31:19 +1000 Subject: Reduce QQuickTextEdit memory usage. Remove unnecessary members from QQuickTextEditPrivate and QQuickTextControlPrivate and re-order and pack to reduce padding for alignment. Change-Id: I14f5e3fc01646d02745f095c2a4b168cd675745d Reviewed-by: Yann Bodson --- src/quick/items/qquicktextcontrol.cpp | 94 +++------------------------------ src/quick/items/qquicktextcontrol_p.h | 12 ----- src/quick/items/qquicktextcontrol_p_p.h | 55 ++++++++----------- src/quick/items/qquicktextedit.cpp | 43 ++++----------- src/quick/items/qquicktextedit_p_p.h | 79 ++++++++++++++------------- 5 files changed, 84 insertions(+), 199 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index a763626410..9a61312910 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -97,13 +97,17 @@ static QTextLine currentTextLine(const QTextCursor &cursor) } QQuickTextControlPrivate::QQuickTextControlPrivate() - : doc(0), cursorOn(false), cursorIsFocusIndicator(false), + : doc(0), + preeditCursor(0), interactionFlags(Qt::TextEditorInteraction), + cursorOn(false), + cursorIsFocusIndicator(false), mousePressed(false), - lastSelectionState(false), ignoreAutomaticScrollbarAdjustement(false), + lastSelectionState(false), + ignoreAutomaticScrollbarAdjustement(false), overwriteMode(false), acceptRichText(true), - preeditCursor(0), hideCursor(false), + hideCursor(false), hasFocus(false), isEnabled(true), hadSelectionOnMousePress(false), @@ -298,7 +302,6 @@ void QQuickTextControlPrivate::setContent(Qt::TextFormat format, const QString & doc = document; clearDocument = false; } else { - palette = QGuiApplication::palette(); doc = new QTextDocument(q); } _q_documentLayoutChanged(); @@ -631,18 +634,6 @@ QQuickTextControl::~QQuickTextControl() { } -void QQuickTextControl::setView(QObject *view) -{ - Q_D(QQuickTextControl); - d->contextObject = view; -} - -QObject *QQuickTextControl::view() const -{ - Q_D(const QQuickTextControl); - return d->contextObject; -} - QTextDocument *QQuickTextControl::document() const { Q_D(const QQuickTextControl); @@ -1418,7 +1409,7 @@ bool QQuickTextControlPrivate::sendMouseEventToInputContext(QMouseEvent *e, cons Q_UNUSED(e); - if (contextObject && isPreediting()) { + if (isPreediting()) { QTextLayout *layout = cursor.block().layout(); int cursorPos = q->hitTest(pos, Qt::FuzzyHit) - cursor.position(); @@ -1908,81 +1899,12 @@ QString QQuickTextControl::toHtml() const } #endif -QPalette QQuickTextControl::palette() const -{ - Q_D(const QQuickTextControl); - return d->palette; -} - -void QQuickTextControl::setPalette(const QPalette &pal) -{ - Q_D(QQuickTextControl); - d->palette = pal; -} - bool QQuickTextControl::cursorOn() const { Q_D(const QQuickTextControl); return d->cursorOn; } -QAbstractTextDocumentLayout::PaintContext QQuickTextControl::getPaintContext() const -{ - Q_D(const QQuickTextControl); - - QAbstractTextDocumentLayout::PaintContext ctx; - - ctx.palette = d->palette; - if (d->cursorOn && d->isEnabled) { - if (d->hideCursor) - ctx.cursorPosition = -1; - else if (d->preeditCursor != 0) - ctx.cursorPosition = - (d->preeditCursor + 2); - else - ctx.cursorPosition = d->cursor.position(); - } - - if (d->cursor.hasSelection()) { - QAbstractTextDocumentLayout::Selection selection; - selection.cursor = d->cursor; - if (0 && d->cursorIsFocusIndicator) { -#if 0 - // ### - QStyleOption opt; - opt.palette = ctx.palette; - QStyleHintReturnVariant ret; - QStyle *style = QGuiApplication::style(); - if (widget) - style = widget->style(); - style->styleHint(QStyle::SH_TextControl_FocusIndicatorTextCharFormat, &opt, widget, &ret); - selection.format = qvariant_cast(ret.variant).toCharFormat(); -#endif - } else { - QPalette::ColorGroup cg = d->hasFocus ? QPalette::Active : QPalette::Inactive; - selection.format.setBackground(ctx.palette.brush(cg, QPalette::Highlight)); - selection.format.setForeground(ctx.palette.brush(cg, QPalette::HighlightedText)); - if (fullWidthSelection) - selection.format.setProperty(QTextFormat::FullWidthSelection, true); - } - ctx.selections.append(selection); - } - - return ctx; -} - -void QQuickTextControl::drawContents(QPainter *p, const QRectF &rect) -{ - Q_D(QQuickTextControl); - p->save(); - QAbstractTextDocumentLayout::PaintContext ctx = getPaintContext(); - if (rect.isValid()) - p->setClipRect(rect, Qt::IntersectClip); - ctx.clip = rect; - - d->doc->documentLayout()->draw(p, ctx); - p->restore(); -} - int QQuickTextControl::hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const { Q_D(const QQuickTextControl); diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index e7beefdaa3..97ecdc4c6e 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -90,9 +90,6 @@ public: explicit QQuickTextControl(QTextDocument *doc, QObject *parent = 0); virtual ~QQuickTextControl(); - void setView(QObject *view); - QObject *view() const; - QTextDocument *document() const; void setTextCursor(const QTextCursor &cursor); @@ -127,9 +124,6 @@ public: qreal textWidth() const; QSizeF size() const; - void setIgnoreUnusedNavigationEvents(bool ignore); - bool ignoreUnusedNavigationEvents() const; - void moveCursor(QTextCursor::MoveOperation op, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor); bool canPaste() const; @@ -178,16 +172,10 @@ Q_SIGNALS: void linkHovered(const QString &); public: - // control properties - QPalette palette() const; - void setPalette(const QPalette &pal); - virtual void processEvent(QEvent *e, const QMatrix &matrix); void processEvent(QEvent *e, const QPointF &coordinateOffset = QPointF()); // control methods - void drawContents(QPainter *painter, const QRectF &rect = QRectF()); - void setFocus(bool focus, Qt::FocusReason = Qt::OtherFocusReason); virtual QVariant inputMethodQuery(Qt::InputMethodQuery property) const; diff --git a/src/quick/items/qquicktextcontrol_p_p.h b/src/quick/items/qquicktextcontrol_p_p.h index daf2f8ca82..44bc00221b 100644 --- a/src/quick/items/qquicktextcontrol_p_p.h +++ b/src/quick/items/qquicktextcontrol_p_p.h @@ -132,49 +132,40 @@ public: bool isPreediting() const; void commitPreedit(); - QTextDocument *doc; - bool cursorOn; - QTextCursor cursor; - bool cursorIsFocusIndicator; - QTextCharFormat lastCharFormat; - - Qt::TextInteractionFlags interactionFlags; - - QBasicTimer cursorBlinkTimer; - QBasicTimer trippleClickTimer; QPointF trippleClickPoint; + QPointF mousePressPos; - bool mousePressed; - - QPoint mousePressPos; - - QPointer contextObject; - - bool lastSelectionState; - - bool ignoreAutomaticScrollbarAdjustement; + QTextCharFormat lastCharFormat; + QTextDocument *doc; + QTextCursor cursor; QTextCursor selectedWordOnDoubleClick; QTextCursor selectedBlockOnTrippleClick; + QString tentativeCommit; + QString highlightedAnchor; // Anchor below cursor + QString anchorOnMousePress; + QString linkToCopy; - bool overwriteMode; - bool acceptRichText; + QBasicTimer cursorBlinkTimer; + QBasicTimer trippleClickTimer; int preeditCursor; - bool hideCursor; // used to hide the cursor in the preedit area - QString tentativeCommit; - - QPalette palette; - bool hasFocus; - bool isEnabled; - QString highlightedAnchor; // Anchor below cursor - QString anchorOnMousePress; - bool hadSelectionOnMousePress; + Qt::TextInteractionFlags interactionFlags; - bool wordSelectionEnabled; + bool cursorOn : 1; + bool cursorIsFocusIndicator : 1; + bool mousePressed : 1; + bool lastSelectionState : 1; + bool ignoreAutomaticScrollbarAdjustement : 1; + bool overwriteMode : 1; + bool acceptRichText : 1; + bool hideCursor : 1; // used to hide the cursor in the preedit area + bool hasFocus : 1; + bool isEnabled : 1; + bool hadSelectionOnMousePress : 1; + bool wordSelectionEnabled : 1; - QString linkToCopy; void _q_copyLink(); void _q_updateBlock(const QTextBlock &); void _q_documentLayoutChanged(); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 6f3c32db7d..06264715a1 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -399,9 +399,6 @@ void QQuickTextEdit::setColor(const QColor &color) return; d->color = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::Text, color); - d->control->setPalette(pal); updateDocument(); emit colorChanged(d->color); } @@ -424,9 +421,6 @@ void QQuickTextEdit::setSelectionColor(const QColor &color) return; d->selectionColor = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::Highlight, color); - d->control->setPalette(pal); updateDocument(); emit selectionColorChanged(d->selectionColor); } @@ -449,9 +443,6 @@ void QQuickTextEdit::setSelectedTextColor(const QColor &color) return; d->selectedTextColor = color; - QPalette pal = d->control->palette(); - pal.setColor(QPalette::HighlightedText, color); - d->control->setPalette(pal); updateDocument(); emit selectedTextColorChanged(d->selectedTextColor); } @@ -1634,10 +1625,8 @@ QSGNode *QQuickTextEdit::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * QRectF bounds = boundingRect(); - QColor selectionColor = d->control->palette().color(QPalette::Highlight); - QColor selectedTextColor = d->control->palette().color(QPalette::HighlightedText); node->addTextDocument(bounds.topLeft(), d->document, d->color, QQuickText::Normal, QColor(), - selectionColor, selectedTextColor, selectionStart(), + d->selectionColor, d->selectedTextColor, selectionStart(), selectionEnd() - 1); // selectionEnd() returns first char after // selection @@ -1756,31 +1745,21 @@ void QQuickTextEditPrivate::init() document = new QQuickTextDocumentWithImageResources(q); control = new QQuickTextControl(document, q); - control->setView(q); control->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard | Qt::TextEditable); control->setAcceptRichText(false); control->setCursorIsFocusIndicator(true); - // QQuickTextControl follows the default text color - // defined by the platform, declarative text - // should be black by default - QPalette pal = control->palette(); - if (pal.color(QPalette::Text) != color) { - pal.setColor(QPalette::Text, color); - control->setPalette(pal); - } - - QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument())); - QObject::connect(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor())); - QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); - QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); - QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); - QObject::connect(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate())); - QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); + FAST_CONNECT(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateDocument())); + FAST_CONNECT(control, SIGNAL(updateCursorRequest()), q, SLOT(updateCursor())); + FAST_CONNECT(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); + FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); + FAST_CONNECT(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); + FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); + FAST_CONNECT(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); + FAST_CONNECT(control, SIGNAL(cursorRectangleChanged()), q, SLOT(moveCursorDelegate())); + FAST_CONNECT(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); #ifndef QT_NO_CLIPBOARD - QObject::connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged())); + FAST_CONNECT(QGuiApplication::clipboard(), SIGNAL(dataChanged()), q, SLOT(q_canPasteChanged())); #endif FAST_CONNECT(document, SIGNAL(undoAvailable(bool)), q, SIGNAL(canUndoChanged())); FAST_CONNECT(document, SIGNAL(redoAvailable(bool)), q, SIGNAL(canRedoChanged())); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index d69e24f6bc..1497c207ee 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -68,15 +68,17 @@ class QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate public: QQuickTextEditPrivate() - : color("black"), hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop), - documentDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true), - persistentSelection(false), requireImplicitWidth(false), selectByMouse(false), canPaste(false), - canPasteValid(false), hAlignImplicit(true), rightToLeftText(false), - textCached(false), - textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0), - format(QQuickTextEdit::PlainText), document(0), wrapMode(QQuickTextEdit::NoWrap), - mouseSelectionMode(QQuickTextEdit::SelectCharacters), - lineCount(0), yoff(0), inputMethodHints(Qt::ImhNone), updateType(UpdatePaintNode) + : color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF)) + , textMargin(0.0), font(sourceFont), cursorComponent(0), cursor(0), document(0), control(0) + , lastSelectionStart(0), lastSelectionEnd(0), lineCount(0), yoff(0) + , hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop) + , format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap) + , mouseSelectionMode(QQuickTextEdit::SelectCharacters), inputMethodHints(Qt::ImhNone) + , updateType(UpdatePaintNode) + , documentDirty(true), dirty(false), richText(false), cursorVisible(false) + , focusOnPress(true), persistentSelection(false), requireImplicitWidth(false) + , selectByMouse(false), canPaste(false), canPasteValid(false), hAlignImplicit(true) + , rightToLeftText(false), textCached(false) { } @@ -92,17 +94,42 @@ public: void mirrorChange(); qreal getImplicitWidth() const; + QColor color; + QColor selectionColor; + QColor selectedTextColor; + + QSize contentSize; + + qreal textMargin; + QString text; QUrl baseUrl; - QFont font; QFont sourceFont; - QColor color; - QColor selectionColor; - QColor selectedTextColor; - QString style; - QColor styleColor; + QFont font; + + QDeclarativeComponent* cursorComponent; + QQuickItem* cursor; + QQuickTextDocumentWithImageResources *document; + QQuickTextControl *control; + + int lastSelectionStart; + int lastSelectionEnd; + int lineCount; + int yoff; + + enum UpdateType { + UpdateNone, + UpdateOnlyPreprocess, + UpdatePaintNode + }; + QQuickTextEdit::HAlignment hAlign; QQuickTextEdit::VAlignment vAlign; + QQuickTextEdit::TextFormat format; + QQuickTextEdit::WrapMode wrapMode; + QQuickTextEdit::SelectionMode mouseSelectionMode; + Qt::InputMethodHints inputMethodHints; + UpdateType updateType; bool documentDirty : 1; bool dirty : 1; @@ -117,28 +144,6 @@ public: bool hAlignImplicit:1; bool rightToLeftText:1; bool textCached:1; - - qreal textMargin; - int lastSelectionStart; - int lastSelectionEnd; - QDeclarativeComponent* cursorComponent; - QQuickItem* cursor; - QQuickTextEdit::TextFormat format; - QQuickTextDocumentWithImageResources *document; - QQuickTextControl *control; - QQuickTextEdit::WrapMode wrapMode; - QQuickTextEdit::SelectionMode mouseSelectionMode; - int lineCount; - int yoff; - QSize contentSize; - Qt::InputMethodHints inputMethodHints; - - enum UpdateType { - UpdateNone, - UpdateOnlyPreprocess, - UpdatePaintNode - }; - UpdateType updateType; }; QT_END_NAMESPACE -- cgit v1.2.3 From 12f0663dbda6ae56d3307493ca34212f601dd3aa Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Tue, 21 Feb 2012 14:11:04 +1000 Subject: Fix font size calculation in headings in StyledText. Calculate the font size correctly even when the size is specified in pixels and update this size when the font changes. Also make sure that the text layout's font is set before parsing. Task-number: QTBUG-24458 Change-Id: Ida7723f6e4f4b9fd3a6878076f4beaf5bda8f7f7 Reviewed-by: Andrew den Exter --- src/quick/items/qquicktext.cpp | 15 ++++++++++++--- src/quick/items/qquicktext_p_p.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 6f8aa383cd..44735c1895 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -85,7 +85,7 @@ QQuickTextPrivate::QQuickTextPrivate() , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false) , styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false) , truncated(false), hAlignImplicit(true), rightToLeftText(false) - , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false) + , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false) { } @@ -298,7 +298,11 @@ void QQuickTextPrivate::updateLayout() if (!richText) { if (textHasChanged) { if (styledText && !text.isEmpty()) { - QDeclarativeStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid); + layout.setFont(font); + // needs temporary bool because formatModifiesFontSize is in a bit-field + bool fontSizeModified = false; + QDeclarativeStyledText::parse(text, layout, imgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified); + formatModifiesFontSize = fontSizeModified; } else { layout.clearAdditionalFormats(); multilengthEos = text.indexOf(QLatin1Char('\x9c')); @@ -1252,8 +1256,13 @@ void QQuickText::setFont(const QFont &font) d->font.setPointSizeF(size/2.0); } - if (oldFont != d->font) + if (oldFont != d->font) { + // if the format changes the size of the text + // with headings or tag, we need to re-parse + if (d->formatModifiesFontSize) + d->textHasChanged = true; d->updateLayout(); + } emit fontChanged(d->sourceFont); } diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index 555f41ff94..e060cc1cd2 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -148,6 +148,7 @@ public: bool layoutTextElided:1; bool textHasChanged:1; bool needToUpdateLayout:1; + bool formatModifiesFontSize:1; static const QChar elideChar; -- cgit v1.2.3 From 924a9620d528da85dc19df7573d33ba4132e5a3a Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Fri, 17 Feb 2012 12:26:21 +1000 Subject: Fix Text eliding with implicit height and maximumLineCount. Ignore the height of the text if the element height is invalid. Task-number: QTBUG-24293 Change-Id: I1646c3f64583da40e6166aeea24c2c4af42cb279 Reviewed-by: Yann Bodson --- src/quick/items/qquicktext.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 44735c1895..28491d8f75 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -666,6 +666,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) } const int lineWidth = q->widthValid() ? q->width() : INT_MAX; + const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX; const bool customLayout = isLineLaidOutConnected(); const bool wasTruncated = truncated; @@ -715,6 +716,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) } layout.beginLayout(); + bool wrapped = false; bool truncateHeight = false; truncated = false; @@ -735,7 +737,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) // Elide the previous line if the accumulated height of the text exceeds the height // of the element. - if (multilineElide && height > q->height() && visibleCount > 1) { + if (multilineElide && height > maxHeight && visibleCount > 1) { elide = true; if (eos != -1) // There's an abbreviated string available, skip the rest as it's break; // all going to be discarded. @@ -873,7 +875,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) } if (verticalFit) { - if (truncateHeight || (q->heightValid() && unelidedRect.height() > q->height())) { + if (truncateHeight || unelidedRect.height() > maxHeight) { largeFont = scaledFontSize - 1; scaledFontSize = (smallFont + largeFont + 1) / 2; if (smallFont > largeFont) -- cgit v1.2.3 From 09ea9cace4286c639044aef79f2deb107c2a5376 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Thu, 23 Feb 2012 11:57:18 +1000 Subject: Fix for bad operator precedence causing right mouse button issues Binary or (|) has higher operator precedence than a ternary in C, causing the original expression here to function quite incorrectly for anything other than the common left-mouse-button-only case. I just added brackets -- feel free to change this to "if"s if you think that would more clearly avoid this issue in future. Change-Id: Ie20bd7e805b89a393794d3240fb0ae680b29ff64 Reviewed-by: Andrew den Exter --- src/quick/items/qquickitem_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index c2cc7d000b..fd02334ab3 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -830,8 +830,8 @@ private: Qt::MouseButtons QQuickItemPrivate::acceptedMouseButtons() const { - return extra.flag()?Qt::LeftButton:Qt::MouseButton(0) | - (extra.isAllocated()?extra->acceptedMouseButtons:Qt::MouseButtons(0)); + return ((extra.flag() ? Qt::LeftButton : Qt::MouseButton(0)) | + (extra.isAllocated() ? extra->acceptedMouseButtons : Qt::MouseButtons(0))); } QSGContext *QQuickItemPrivate::sceneGraphContext() const -- cgit v1.2.3 From bbbc44c45d9a6b7381b775413fcfcc1a72c14317 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 23 Feb 2012 11:51:31 +1000 Subject: Clean up some of the view transition docs Fix some of the wording in the docs. Change-Id: I07892bec06c78b73bdd93926719d609405e263b3 Reviewed-by: Bea Lam --- src/quick/items/qquickgridview.cpp | 69 ++++++++++++++++++++------------------ src/quick/items/qquicklistview.cpp | 69 ++++++++++++++++++++------------------ 2 files changed, 72 insertions(+), 66 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index d7f4b808f2..a7e0af487f 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -1586,10 +1586,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::populate - This property holds the transition to apply to items that are initially created for a - view. - This transition is applied to all the items that are created when: + This property holds the transition to apply to the items that are initially created + for a view. + + It is applied to all items that are created when: \list \o The view is first created @@ -1619,10 +1620,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::add - This property holds the transition to apply to items that are added within the view. - The transition is applied to items that have been added to the visible area of the view. For - example, here is a view that specifies such a transition: + This property holds the transition to apply to items that are added to the view. + + For example, here is a view that specifies such a transition: \code GridView { @@ -1651,11 +1652,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::addDisplaced - This property holds the transition to apply to items in the view that are displaced by other - items that have been added to the view. - The transition is applied to items that are currently visible and have been displaced by newly - added items. For example, here is a view that specifies such a transition: + This property holds the transition to apply to items within the view that are displaced by + the addition of other items to the view. + + For example, here is a view that specifies such a transition: \code GridView { @@ -1684,11 +1685,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) */ /*! \qmlproperty Transition QtQuick2::GridView::move - This property holds the transition to apply to items in the view that are moved by a move - operation. - The transition is applied to items that are moving within the view or are moving - into the view as a result of a move operation in the view's model. For example: + This property holds the transition to apply to items in the view that are being moved due + to a move operation in the view's \l model. + + For example, here is a view that specifies such a transition: \code GridView { @@ -1699,10 +1700,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) } \endcode - Whenever an item is moved within the above view, the item will be animated to its new position in - the view over one second. The transition only applies to the items that are the subject of the - move operation in the model; it does not apply to the items below them that are displaced by - the move operation. To animate the displaced items, set the \l moveDisplaced property. + Whenever the \l model performs a move operation to move a particular set of indexes, the + respective items in the view will be animated to their new positions in the view over one + second. The transition only applies to the items that are the subject of the move operation + in the model; it does not apply to items below them that are displaced by the move operation. + To animate the displaced items, set the \l moveDisplaced property. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1712,11 +1714,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::moveDisplaced - This property holds the transition to apply to items in the view that are displaced by a - move operation in the view. - The transition is applied to items that are currently visible and have been displaced following - a move operation in the view's model. For example, here is a view that specifies such a transition: + This property holds the transition to apply to items that are displaced by a move operation in + the view's \l model. + + For example, here is a view that specifies such a transition: \code GridView { @@ -1727,12 +1729,13 @@ void QQuickGridView::setSnapMode(SnapMode mode) } \endcode - Whenever an item moves within (or moves into) the above view, all items beneath it are - displaced, causing them to move upwards (or sideways, if horizontally orientated) within the - view. As this displacement occurs, the items' movement to their new x,y positions within the - view will be animated by a NumberAnimation over one second, as specified. This transition is - not applied to the item that are actually the subject of the move operation; to animate the - moved items, set the \l move property. + Whenever the \l model performs a move operation to move a particular set of indexes, the items + between the source and destination indexes of the move operation are displaced, causing them + to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this + displacement occurs, the items' movement to their new x,y positions within the view will be + animated by a NumberAnimation over one second, as specified. This transition is not applied to + the items that are the actual subjects of the move operation; to animate the moved items, set + the \l move property. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1742,10 +1745,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::remove + This property holds the transition to apply to items that are removed from the view. - The transition is applied to items that have been removed from the visible area of the view. For - example: + For example, here is a view that specifies such a transition: \code GridView { @@ -1762,7 +1765,7 @@ void QQuickGridView::setSnapMode(SnapMode mode) Whenever an item is removed from the above view, the item will be animated to the position (100,100) over one second, and in parallel will also change its opacity to 0. The transition only applies to the items that are removed from the view; it does not apply to the items below - them that are displaced by the removal of the items. To animate the displaced items, set the \l + them that are displaced by the removal of the items. To animate the displaced items, set the \l removeDisplaced property. Note that by the time the transition is applied, the item has already been removed from the @@ -1779,11 +1782,11 @@ void QQuickGridView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::GridView::removeDisplaced + This property holds the transition to apply to items in the view that are displaced by the removal of other items in the view. - The transition is applied to items that are currently visible and have been displaced by - the removal of items. For example, here is a view that specifies such a transition: + For example, here is a view that specifies such a transition: \code GridView { diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 906b9b3781..6324c7d2ff 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -2245,10 +2245,11 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::populate - This property holds the transition to apply to items that are initially created for a - view. - This transition is applied to all the items that are created when: + This property holds the transition to apply to the items that are initially created + for a view. + + It is applied to all items that are created when: \list \o The view is first created @@ -2278,10 +2279,10 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::add - This property holds the transition to apply to items that are added within the view. - The transition is applied to items that have been added to the visible area of the view. For - example, here is a view that specifies such a transition: + This property holds the transition to apply to items that are added to the view. + + For example, here is a view that specifies such a transition: \code ListView { @@ -2310,11 +2311,11 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::addDisplaced - This property holds the transition to apply to items in the view that are displaced by other - items that have been added to the view. - The transition is applied to items that are currently visible and have been displaced by newly - added items. For example, here is a view that specifies such a transition: + This property holds the transition to apply to items within the view that are displaced by + the addition of other items to the view. + + For example, here is a view that specifies such a transition: \code ListView { @@ -2344,11 +2345,11 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::move - This property holds the transition to apply to items in the view that are moved by a move - operation. - The transition is applied to items that are moving within the view or are moving - into the view as a result of a move operation in the view's model. For example: + This property holds the transition to apply to items in the view that are being moved due + to a move operation in the view's \l model. + + For example, here is a view that specifies such a transition: \code ListView { @@ -2359,10 +2360,11 @@ void QQuickListView::setSnapMode(SnapMode mode) } \endcode - Whenever an item is moved within the above view, the item will be animated to its new position in - the view over one second. The transition only applies to the items that are the subject of the - move operation in the model; it does not apply to the items below them that are displaced by - the move operation. To animate the displaced items, set the \l moveDisplaced property. + Whenever the \l model performs a move operation to move a particular set of indexes, the + respective items in the view will be animated to their new positions in the view over one + second. The transition only applies to the items that are the subject of the move operation + in the model; it does not apply to items below them that are displaced by the move operation. + To animate the displaced items, set the \l moveDisplaced property. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2372,11 +2374,11 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::moveDisplaced - This property holds the transition to apply to items in the view that are displaced by a - move operation in the view. - The transition is applied to items that are currently visible and have been displaced following - a move operation in the view's model. For example, here is a view that specifies such a transition: + This property holds the transition to apply to items that are displaced by a move operation in + the view's \l model. + + For example, here is a view that specifies such a transition: \code ListView { @@ -2387,12 +2389,13 @@ void QQuickListView::setSnapMode(SnapMode mode) } \endcode - Whenever an item moves within (or moves into) the above view, all items beneath it are - displaced, causing them to move upwards (or sideways, if horizontally orientated) within the - view. As this displacement occurs, the items' movement to their new x,y positions within the - view will be animated by a NumberAnimation over one second, as specified. This transition is - not applied to the item that are actually the subject of the move operation; to animate the - moved items, set the \l move property. + Whenever the \l model performs a move operation to move a particular set of indexes, the items + between the source and destination indexes of the move operation are displaced, causing them + to move upwards or downwards (or sideways, if horizontally orientated) within the view. As this + displacement occurs, the items' movement to their new x,y positions within the view will be + animated by a NumberAnimation over one second, as specified. This transition is not applied to + the items that are the actual subjects of the move operation; to animate the moved items, set + the \l move property. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2402,10 +2405,10 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::remove + This property holds the transition to apply to items that are removed from the view. - The transition is applied to items that have been removed from the visible area of the view. For - example: + For example, here is a view that specifies such a transition: \code ListView { @@ -2422,7 +2425,7 @@ void QQuickListView::setSnapMode(SnapMode mode) Whenever an item is removed from the above view, the item will be animated to the position (100,100) over one second, and in parallel will also change its opacity to 0. The transition only applies to the items that are removed from the view; it does not apply to the items below - them that are displaced by the removal of the items. To animate the displaced items, set the \l + them that are displaced by the removal of the items. To animate the displaced items, set the \l removeDisplaced property. Note that by the time the transition is applied, the item has already been removed from the @@ -2439,11 +2442,11 @@ void QQuickListView::setSnapMode(SnapMode mode) /*! \qmlproperty Transition QtQuick2::ListView::removeDisplaced + This property holds the transition to apply to items in the view that are displaced by the removal of other items in the view. - The transition is applied to items that are currently visible and have been displaced by - the removal of items. For example, here is a view that specifies such a transition: + For example, here is a view that specifies such a transition: \code ListView { -- cgit v1.2.3 From fb3889a423365b1736cae8850cdb2b3ac77b14a8 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 21 Feb 2012 10:55:34 +0100 Subject: Use new plugin system in QtDeclarative. - Use prefix "org.qt-project" for interfaces. - Use new macros, add json files. Change-Id: I53df83f95153c5c9c462098584606284470a5ae0 Reviewed-by: Martin Jones --- src/quick/items/qquickvisualadaptormodel_p.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickvisualadaptormodel_p.h b/src/quick/items/qquickvisualadaptormodel_p.h index 9ae8325450..e431f3aa26 100644 --- a/src/quick/items/qquickvisualadaptormodel_p.h +++ b/src/quick/items/qquickvisualadaptormodel_p.h @@ -121,7 +121,9 @@ public: virtual QObject *proxiedObject() = 0; }; -Q_DECLARE_INTERFACE(QQuickVisualAdaptorModelProxyInterface, "com.trolltech.qml.QQuickVisualAdaptorModelProxyInterface") +#define QQuickVisualAdaptorModelProxyInterface_iid "org.qt-project.Qt.QQuickVisualAdaptorModelProxyInterface" + +Q_DECLARE_INTERFACE(QQuickVisualAdaptorModelProxyInterface, QQuickVisualAdaptorModelProxyInterface_iid) QT_END_NAMESPACE -- cgit v1.2.3 From 5fee1e79cc1c18acf58f9171a73a7525154a65cd Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 23 Feb 2012 14:11:48 +1000 Subject: Use floating point types for position offsets and cursorRectangle. Rounding to align painting to pixel boundaries is no longer necessary are largely removed. Correct the few instances remaining in TextEdit and TextInput. Change-Id: Ic6ec57092d74ec43b23d85cd8868e0190acc3e09 Reviewed-by: Yann Bodson --- src/quick/items/qquicktextedit.cpp | 22 +++++++++--------- src/quick/items/qquicktextedit_p.h | 6 ++--- src/quick/items/qquicktextedit_p_p.h | 8 +++---- src/quick/items/qquicktextinput.cpp | 42 ++++++++++++++++------------------- src/quick/items/qquicktextinput_p.h | 4 ++-- src/quick/items/qquicktextinput_p_p.h | 13 ++++++----- 6 files changed, 46 insertions(+), 49 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index 06264715a1..66285fcd2b 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -732,10 +732,10 @@ QRectF QQuickTextEdit::positionToRectangle(int pos) const Position 0 is before the first character, position 1 is after the first character but before the second, and so on until position \l {text}.length, which is after all characters. */ -int QQuickTextEdit::positionAt(int x, int y) const +int QQuickTextEdit::positionAt(qreal x, qreal y) const { Q_D(const QQuickTextEdit); - int r = d->document->documentLayout()->hitTest(QPoint(x,y-d->yoff), Qt::FuzzyHit); + int r = d->document->documentLayout()->hitTest(QPointF(x,y-d->yoff), Qt::FuzzyHit); QTextCursor cursor = d->control->textCursor(); if (r > cursor.position()) { // The cursor position includes positions within the preedit text, but only positions in the @@ -1290,10 +1290,10 @@ Qt::TextInteractionFlags QQuickTextEdit::textInteractionFlags() const automatically when it changes. The width of the delegate is unaffected by changes in the cursor rectangle. */ -QRect QQuickTextEdit::cursorRectangle() const +QRectF QQuickTextEdit::cursorRectangle() const { Q_D(const QQuickTextEdit); - return d->control->cursorRect().toRect().translated(0,d->yoff); + return d->control->cursorRect().translated(0, d->yoff); } bool QQuickTextEdit::event(QEvent *event) @@ -1863,11 +1863,11 @@ void QQuickTextEdit::updateSize() } else { d->document->setTextWidth(-1); } - QFontMetrics fm = QFontMetrics(d->font); - int dy = height(); - dy -= (int)d->document->size().height(); + QFontMetricsF fm(d->font); + qreal dy = height(); + dy -= d->document->size().height(); - int nyoff; + qreal nyoff; if (heightValid()) { if (d->vAlign == AlignBottom) nyoff = dy; @@ -1883,7 +1883,7 @@ void QQuickTextEdit::updateSize() setBaselineOffset(fm.ascent() + d->yoff + d->textMargin); //### need to comfirm cost of always setting these - int newWidth = qCeil(d->document->idealWidth()); + qreal newWidth = d->document->idealWidth(); if (!widthValid() && d->document->textWidth() != newWidth) d->document->setTextWidth(newWidth); // ### Text does not align if width is not set (QTextDoc bug) // ### Setting the implicitWidth triggers another updateSize(), and unless there are bindings nothing has changed. @@ -1892,13 +1892,13 @@ void QQuickTextEdit::updateSize() iWidth = newWidth; else if (d->requireImplicitWidth) iWidth = naturalWidth; - qreal newHeight = d->document->isEmpty() ? fm.height() : (int)d->document->size().height(); + qreal newHeight = d->document->isEmpty() ? fm.height() : d->document->size().height(); if (iWidth > -1) setImplicitSize(iWidth, newHeight); else setImplicitHeight(newHeight); - QSize size(newWidth, newHeight); + QSizeF size(newWidth, newHeight); if (d->contentSize != size) { d->contentSize = size; emit contentSizeChanged(); diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index 5f6317ab09..b3fd32af69 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -79,7 +79,7 @@ class Q_AUTOTEST_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged) Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) - Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) + Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QDeclarativeComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) @@ -212,7 +212,7 @@ public: void setTextInteractionFlags(Qt::TextInteractionFlags flags); Qt::TextInteractionFlags textInteractionFlags() const; - QRect cursorRectangle() const; + QRectF cursorRectangle() const; QVariant inputMethodQuery(Qt::InputMethodQuery property) const; @@ -224,7 +224,7 @@ public: void resetBaseUrl(); Q_INVOKABLE QRectF positionToRectangle(int) const; - Q_INVOKABLE int positionAt(int x, int y) const; + Q_INVOKABLE int positionAt(qreal x, qreal y) const; Q_INVOKABLE void moveCursorSelection(int pos); Q_INVOKABLE void moveCursorSelection(int pos, SelectionMode mode); diff --git a/src/quick/items/qquicktextedit_p_p.h b/src/quick/items/qquicktextedit_p_p.h index 1497c207ee..8ec589da29 100644 --- a/src/quick/items/qquicktextedit_p_p.h +++ b/src/quick/items/qquicktextedit_p_p.h @@ -69,8 +69,8 @@ class QQuickTextEditPrivate : public QQuickImplicitSizeItemPrivate public: QQuickTextEditPrivate() : color(QRgb(0xFF000000)), selectionColor(QRgb(0xFF000080)), selectedTextColor(QRgb(0xFFFFFFFF)) - , textMargin(0.0), font(sourceFont), cursorComponent(0), cursor(0), document(0), control(0) - , lastSelectionStart(0), lastSelectionEnd(0), lineCount(0), yoff(0) + , textMargin(0.0), yoff(0), font(sourceFont), cursorComponent(0), cursor(0), document(0), control(0) + , lastSelectionStart(0), lastSelectionEnd(0), lineCount(0) , hAlign(QQuickTextEdit::AlignLeft), vAlign(QQuickTextEdit::AlignTop) , format(QQuickTextEdit::PlainText), wrapMode(QQuickTextEdit::NoWrap) , mouseSelectionMode(QQuickTextEdit::SelectCharacters), inputMethodHints(Qt::ImhNone) @@ -98,9 +98,10 @@ public: QColor selectionColor; QColor selectedTextColor; - QSize contentSize; + QSizeF contentSize; qreal textMargin; + qreal yoff; QString text; QUrl baseUrl; @@ -115,7 +116,6 @@ public: int lastSelectionStart; int lastSelectionEnd; int lineCount; - int yoff; enum UpdateType { UpdateNone, diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 9b11e2e43a..6f079dc045 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -677,7 +677,7 @@ void QQuickTextInput::setCursorPosition(int cp) cursor rectangle. */ -QRect QQuickTextInput::cursorRectangle() const +QRectF QQuickTextInput::cursorRectangle() const { Q_D(const QQuickTextInput); @@ -688,12 +688,8 @@ QRect QQuickTextInput::cursorRectangle() const c = 0; QTextLine l = d->m_textLayout.lineForTextPosition(c); if (!l.isValid()) - return QRect(); - return QRect( - qRound(l.cursorToX(c) - d->hscroll), - qRound(l.y() - d->vscroll), - 1, - qCeil(l.height())); + return QRectF(); + return QRectF(l.cursorToX(c) - d->hscroll, l.y() - d->vscroll, 1, l.height()); } /*! @@ -1368,7 +1364,7 @@ void QQuickTextInput::positionAt(QDeclarativeV8Function *args) const args->returnValue(v8::Int32::New(pos)); } -int QQuickTextInputPrivate::positionAt(int x, int y, QTextLine::CursorPosition position) const +int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const { x += hscroll; y += vscroll; @@ -1432,7 +1428,7 @@ void QQuickTextInput::mouseDoubleClickEvent(QMouseEvent *event) d->selectWordAtPos(cursor); event->setAccepted(true); if (!d->hasPendingTripleClick()) { - d->tripleClickStartPoint = event->localPos().toPoint(); + d->tripleClickStartPoint = event->localPos(); d->tripleClickTimer.start(); } } else { @@ -1617,15 +1613,15 @@ void QQuickTextInputPrivate::updateHorizontalScroll() Q_Q(QQuickTextInput); QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + m_preeditCursor); const int preeditLength = m_textLayout.preeditAreaText().length(); - const int width = qMax(0, qFloor(q->width())); - int widthUsed = currentLine.isValid() ? qRound(currentLine.naturalTextWidth()) : 0; + const qreal width = qMax(0, q->width()); + qreal widthUsed = currentLine.isValid() ? currentLine.naturalTextWidth() : 0; int previousScroll = hscroll; if (!autoScroll || widthUsed <= width || m_echoMode == QQuickTextInput::NoEcho) { hscroll = 0; } else { Q_ASSERT(currentLine.isValid()); - int cix = qRound(currentLine.cursorToX(m_cursor + preeditLength)); + qreal cix = currentLine.cursorToX(m_cursor + preeditLength); if (cix - hscroll >= width) { // text doesn't fit, cursor is to the right of br (scroll right) hscroll = cix - width; @@ -1640,7 +1636,7 @@ void QQuickTextInputPrivate::updateHorizontalScroll() if (preeditLength > 0) { // check to ensure long pre-edit text doesn't push the cursor // off to the left - cix = qRound(currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1))); + cix = currentLine.cursorToX(m_cursor + qMax(0, m_preeditCursor - 1)); if (cix < hscroll) hscroll = cix; } @@ -1653,9 +1649,9 @@ void QQuickTextInputPrivate::updateVerticalScroll() { Q_Q(QQuickTextInput); const int preeditLength = m_textLayout.preeditAreaText().length(); - const int height = qMax(0, qFloor(q->height())); - int heightUsed = boundingRect.height(); - int previousScroll = vscroll; + const qreal height = qMax(0, q->height()); + qreal heightUsed = boundingRect.height(); + qreal previousScroll = vscroll; if (!autoScroll || heightUsed <= height) { // text fits in br; use vscroll for alignment @@ -1674,8 +1670,8 @@ void QQuickTextInputPrivate::updateVerticalScroll() } else { QTextLine currentLine = m_textLayout.lineForTextPosition(m_cursor + preeditLength); QRectF r = currentLine.isValid() ? currentLine.rect() : QRectF(); - int top = qFloor(r.top()); - int bottom = qCeil(r.bottom()); + qreal top = r.top(); + int bottom = r.bottom(); if (bottom - vscroll >= height) { // text doesn't fit, cursor is to the below the br (scroll down) @@ -1692,7 +1688,7 @@ void QQuickTextInputPrivate::updateVerticalScroll() // check to ensure long pre-edit text doesn't push the cursor // off the top currentLine = m_textLayout.lineForTextPosition(m_cursor + qMax(0, m_preeditCursor - 1)); - top = currentLine.isValid() ? qRound(currentLine.rect().top()) : 0; + top = currentLine.isValid() ? currentLine.rect().top() : 0; if (top < vscroll) vscroll = top; } @@ -1742,11 +1738,11 @@ QSGNode *QQuickTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData node->deleteContent(); node->setMatrix(QMatrix4x4()); - QPoint offset = QPoint(0,0); + QPointF offset(0, 0); if (d->autoScroll && d->m_textLayout.lineCount() > 0) { - QFontMetrics fm = QFontMetrics(d->font); + QFontMetricsF fm(d->font); // the y offset is there to keep the baseline constant in case we have script changes in the text. - offset = -QPoint(d->hscroll, d->vscroll + qRound(d->m_textLayout.lineAt(0).ascent()) - fm.ascent()); + offset = -QPoint(d->hscroll, d->vscroll + d->m_textLayout.lineAt(0).ascent() - fm.ascent()); } else { offset = -QPoint(d->hscroll, d->vscroll); } @@ -2732,7 +2728,7 @@ void QQuickTextInputPrivate::updateLayout() updateType = UpdatePaintNode; q->update(); - q->setImplicitSize(qCeil(boundingRect.width()), qCeil(boundingRect.height())); + q->setImplicitSize(boundingRect.width(), boundingRect.height()); if (previousRect != boundingRect) emit q->contentSizeChanged(); diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 0e60cf6ce4..ebd3d58957 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -76,7 +76,7 @@ class Q_AUTOTEST_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged) Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) - Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) + Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QDeclarativeComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) @@ -195,7 +195,7 @@ public: int cursorPosition() const; void setCursorPosition(int cp); - QRect cursorRectangle() const; + QRectF cursorRectangle() const; int selectionStart() const; int selectionEnd() const; diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index e48b000e5c..1921451f88 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -77,14 +77,14 @@ class Q_AUTOTEST_EXPORT QQuickTextInputPrivate : public QQuickImplicitSizeItemPr Q_DECLARE_PUBLIC(QQuickTextInput) public: QQuickTextInputPrivate() - : cursorItem(0) + : hscroll(0) + , vscroll(0) + , cursorItem(0) , textNode(0) , m_maskData(0) , color(QRgb(0xFF000000)) , selectionColor(QRgb(0xFF000080)) , selectedTextColor(QRgb(0xFFFFFFFF)) - , hscroll(0) - , vscroll(0) , m_cursor(0) , m_preeditCursor(0) , m_blinkPeriod(0) @@ -179,6 +179,9 @@ public: QDeclarativeGuard m_validator; #endif + qreal hscroll; + qreal vscroll; + QTextLayout m_textLayout; QString m_text; QString m_inputMask; @@ -203,8 +206,6 @@ public: #endif int lastSelectionStart; int lastSelectionEnd; - int hscroll; - int vscroll; int m_cursor; int m_preeditCursor; int m_blinkPeriod; // 0 for non-blinking cursor @@ -295,7 +296,7 @@ public: int selectionStart() const { return hasSelectedText() ? m_selstart : -1; } int selectionEnd() const { return hasSelectedText() ? m_selend : -1; } - int positionAt(int x, int y, QTextLine::CursorPosition position) const; + int positionAt(qreal x, qreal y, QTextLine::CursorPosition position) const; int positionAt(const QPointF &point, QTextLine::CursorPosition position = QTextLine::CursorBetweenCharacters) const { return positionAt(point.x(), point.y(), position); } -- cgit v1.2.3 From 5cc9b79675c9d1e17e0153ca2ddf42771a09cfe3 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Fri, 24 Feb 2012 07:28:54 +0100 Subject: Revert resource releasing logic inside window managers. This was based on the assumption that exposure and visibility would take similar code paths, but this is not the case and the fallout of this change (like not releasing resources at all) is not worth it. This reverts ef6318ae38322b5a4a0619b581924290f114fa74 and most of 5f0013ee76605b9c7ceab168702b57e797b698e0 Change-Id: Ib2e29972502a8ec956cd6bd294a2a2bb50d8e76e Reviewed-by: Alan Alpert --- src/quick/items/qquickwindowmanager.cpp | 154 ++++++++------------------------ src/quick/items/qquickwindowmanager_p.h | 2 + 2 files changed, 39 insertions(+), 117 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index b999e6f85d..16b6d92e22 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -48,8 +48,8 @@ #include #include -#include #include +#include #include @@ -145,6 +145,10 @@ DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP); //#define THREAD_DEBUG +QQuickWindowManager::~QQuickWindowManager() +{ +} + class QQuickRenderThreadSingleContextWindowManager : public QThread, public QQuickWindowManager { Q_OBJECT @@ -165,7 +169,6 @@ public: , shouldExit(false) , hasExited(false) , isDeferredUpdatePosted(false) - , runToReleaseResources(false) , canvasToGrab(0) { sg->moveToThread(this); @@ -176,13 +179,10 @@ public: connect(animationDriver, SIGNAL(stopped()), this, SLOT(animationStopped())); } - ~QQuickRenderThreadSingleContextWindowManager() - { - releaseResources(); - } - QSGContext *sceneGraphContext() const { return sg; } + void releaseResources() { } + void show(QQuickCanvas *canvas); void hide(QQuickCanvas *canvas); @@ -201,8 +201,6 @@ public: void sync(bool guiAlreadyLocked); void initialize(); - void releaseResources(); - void releaseResourcesInThread(); bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; } @@ -258,7 +256,6 @@ private: uint shouldExit : 1; uint hasExited : 1; uint isDeferredUpdatePosted : 1; - uint runToReleaseResources : 1; QQuickCanvas *canvasToGrab; QImage grabContent; @@ -291,17 +288,12 @@ class QQuickTrivialWindowManager : public QObject, public QQuickWindowManager { public: QQuickTrivialWindowManager(); - ~QQuickTrivialWindowManager() - { - releaseResources(); - } void show(QQuickCanvas *canvas); void hide(QQuickCanvas *canvas); void canvasDestroyed(QQuickCanvas *canvas); - void releaseResources(); void initializeGL(); void renderCanvas(QQuickCanvas *canvas); void paint(QQuickCanvas *canvas); @@ -310,10 +302,11 @@ public: void maybeUpdate(QQuickCanvas *canvas); + void releaseResources() { } + bool *allowMainThreadProcessing(); QSGContext *sceneGraphContext() const; - QQuickCanvas *masterCanvas() const; bool event(QEvent *); @@ -564,18 +557,10 @@ void QQuickRenderThreadSingleContextWindowManager::run() #ifdef THREAD_DEBUG printf("QML Rendering Thread Started\n"); #endif - lock(); - - if (runToReleaseResources) { - releaseResourcesInThread(); - runToReleaseResources = false; - unlock(); - return; - } - - if (!gl) - initialize(); + lock(); + Q_ASSERT(!gl); + initialize(); // Wake GUI as it is waiting for the GL context to have appeared, as // an indication that the render thread is now running. wake(); @@ -772,6 +757,12 @@ void QQuickRenderThreadSingleContextWindowManager::run() m_removed_windows << m_rendered_windows.keys(); handleRemovedWindows(); + sg->invalidate(); + + gl->doneCurrent(); + delete gl; + gl = 0; + #ifdef THREAD_DEBUG printf(" RenderThread: render loop exited... Good Night!\n"); #endif @@ -790,59 +781,6 @@ void QQuickRenderThreadSingleContextWindowManager::run() #endif } -void QQuickRenderThreadSingleContextWindowManager::releaseResourcesInThread() -{ -#ifdef THREAD_DEBUG - printf(" RenderThread: releasing resources...\n"); -#endif - QQuickCanvas *canvas = masterCanvas(); - QWindow *tmpSurface = 0; - - if (canvas) { - gl->makeCurrent(canvas); - } else { - tmpSurface = new QWindow(); - tmpSurface->setSurfaceType(QSurface::OpenGLSurface); - tmpSurface->resize(4, 4); - tmpSurface->create(); - gl->makeCurrent(tmpSurface); - } - - sg->invalidate(); - gl->doneCurrent(); - delete gl; - gl = 0; - - if (tmpSurface) - delete tmpSurface; - - wake(); -} - -void QQuickRenderThreadSingleContextWindowManager::releaseResources() -{ -#ifdef THREAD_DEBUG - printf("GUI: releasing resources\n"); -#endif - - lockInGui(); - if (!isRunning() && gl) { - runToReleaseResources = true; - start(); - - while (isRunning()) { - wait(); - } - } -#ifdef THREAD_DEBUG - else { - printf("GUI: render thread running not releasing resources...\n"); - } -#endif - unlockInGui(); - -} - bool QQuickRenderThreadSingleContextWindowManager::event(QEvent *e) { Q_ASSERT(QThread::currentThread() == qApp->thread()); @@ -1074,6 +1012,7 @@ void QQuickRenderThreadSingleContextWindowManager::startRendering() animationTimer = -1; } + } @@ -1216,46 +1155,17 @@ void QQuickTrivialWindowManager::hide(QQuickCanvas *canvas) m_windows.remove(canvas); QQuickCanvasPrivate *cd = QQuickCanvasPrivate::get(canvas); cd->cleanupNodesOnShutdown(); -} - -void QQuickTrivialWindowManager::canvasDestroyed(QQuickCanvas *canvas) -{ - hide(canvas); -} - -void QQuickTrivialWindowManager::releaseResources() -{ - if (m_windows.size() == 0 && gl) { - QQuickCanvas *canvas = masterCanvas(); - QWindow *tmpSurface = 0; - - if (canvas) { - gl->makeCurrent(canvas); - } else { - tmpSurface = new QWindow(); - tmpSurface->setSurfaceType(QSurface::OpenGLSurface); - tmpSurface->resize(4, 4); - tmpSurface->create(); - gl->makeCurrent(tmpSurface); - } + if (m_windows.size() == 0) { sg->invalidate(); delete gl; gl = 0; - - delete tmpSurface; } } -QQuickCanvas *QQuickTrivialWindowManager::masterCanvas() const +void QQuickTrivialWindowManager::canvasDestroyed(QQuickCanvas *canvas) { - // Find a "proper surface" to bind... - for (QHash::const_iterator it = m_windows.constBegin(); - it != m_windows.constEnd(); ++it) { - if (it.key()->visible()) - return it.key(); - } - return 0; + hide(canvas); } void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) @@ -1265,20 +1175,30 @@ void QQuickTrivialWindowManager::renderCanvas(QQuickCanvas *canvas) CanvasData &data = const_cast(m_windows[canvas]); - QQuickCanvas *window = canvas->visible() ? canvas : masterCanvas(); + QQuickCanvas *masterCanvas = 0; + if (!canvas->visible()) { + // Find a "proper surface" to bind... + for (QHash::const_iterator it = m_windows.constBegin(); + it != m_windows.constEnd() && !masterCanvas; ++it) { + if (it.key()->visible()) + masterCanvas = it.key(); + } + } else { + masterCanvas = canvas; + } - if (!window) + if (!masterCanvas) return; if (!gl) { gl = new QOpenGLContext(); - gl->setFormat(window->requestedFormat()); + gl->setFormat(masterCanvas->requestedFormat()); gl->create(); - if (!gl->makeCurrent(window)) + if (!gl->makeCurrent(masterCanvas)) qWarning("QQuickCanvas: makeCurrent() failed..."); sg->initialize(gl); } else { - gl->makeCurrent(window); + gl->makeCurrent(masterCanvas); } bool alsoSwap = data.updatePending; diff --git a/src/quick/items/qquickwindowmanager_p.h b/src/quick/items/qquickwindowmanager_p.h index 014b38132e..86312655b3 100644 --- a/src/quick/items/qquickwindowmanager_p.h +++ b/src/quick/items/qquickwindowmanager_p.h @@ -52,6 +52,8 @@ class QSGContext; class QQuickWindowManager { public: + virtual ~QQuickWindowManager(); + virtual void show(QQuickCanvas *canvas) = 0; virtual void hide(QQuickCanvas *canvas) = 0; -- cgit v1.2.3 From 15dac112df4f44ba8b15047720e1570fd4096f26 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 23 Feb 2012 16:57:06 +1000 Subject: Don't create a separate section header for currentItem The currentItem FxViewItem contained it's own section item, which when created would cause the current item delegate to be repositioned. This change associates the section item with the delegate item, via the attached object. Change-Id: Ie675d545539b56d0f1cf5a9b4ea26668978a5e72 Reviewed-by: Bea Lam --- src/quick/items/qquickitemview.cpp | 15 +++-- src/quick/items/qquickitemview_p_p.h | 8 +-- src/quick/items/qquicklistview.cpp | 112 +++++++++++++++++++---------------- src/quick/items/qquicklistview_p.h | 3 +- 4 files changed, 75 insertions(+), 63 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 533e1f6852..f62fa94f5e 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -46,11 +46,12 @@ QT_BEGIN_NAMESPACE FxViewItem::FxViewItem(QQuickItem *i, bool own) - : item(i), ownItem(own), index(-1), releaseAfterTransition(false) - , transition(0) - , nextTransitionType(FxViewItemTransitionManager::NoTransition) + : item(i), ownItem(own), releaseAfterTransition(false) , isTransitionTarget(false) , nextTransitionToSet(false) + , index(-1) + , transition(0) + , nextTransitionType(FxViewItemTransitionManager::NoTransition) { } @@ -2768,21 +2769,23 @@ void QQuickItemView::destroyingItem(QQuickItem *item) d->unrequestedItems.remove(item); } -void QQuickItemViewPrivate::releaseItem(FxViewItem *item) +bool QQuickItemViewPrivate::releaseItem(FxViewItem *item) { Q_Q(QQuickItemView); if (!item || !model) - return; + return true; if (trackedItem == item) trackedItem = 0; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item->item); itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry); - if (model->release(item->item) == 0) { + QQuickVisualModel::ReleaseFlags flags = model->release(item->item); + if (flags == 0) { // item was not destroyed, and we no longer reference it. item->item->setVisible(false); unrequestedItems.insert(item->item, model->indexOf(item->item, q)); } delete item; + return flags != QQuickVisualModel::Referenced; } QQuickItem *QQuickItemViewPrivate::createHighlightItem() diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index 05927c0d68..fce6e4eba5 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -117,15 +117,15 @@ public: QQuickItem *item; bool ownItem; - int index; bool releaseAfterTransition; + bool isTransitionTarget; + bool nextTransitionToSet; + int index; QQuickItemViewAttached *attached; FxViewItemTransitionManager *transition; QPointF nextTransitionTo; FxViewItemTransitionManager::TransitionType nextTransitionType; - bool isTransitionTarget; - bool nextTransitionToSet; protected: void moveTo(const QPointF &pos); @@ -225,7 +225,7 @@ public: void mirrorChange(); FxViewItem *createItem(int modelIndex, bool asynchronous = false); - virtual void releaseItem(FxViewItem *item); + virtual bool releaseItem(FxViewItem *item); QQuickItem *createHighlightItem(); QQuickItem *createComponentItem(QDeclarativeComponent *component, bool receiveItemGeometryChanges, bool createDefault = false); diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 6324c7d2ff..0e643a13e3 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -93,7 +93,7 @@ public: virtual FxViewItem *newViewItem(int index, QQuickItem *item); virtual void initializeViewItem(FxViewItem *item); - virtual void releaseItem(FxViewItem *item); + virtual bool releaseItem(FxViewItem *item); virtual void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer); virtual void repositionPackageItemAt(QQuickItem *item, int index); virtual void resetFirstItemPosition(qreal pos = 0.0); @@ -236,7 +236,7 @@ void QQuickViewSection::setLabelPositioning(int l) class FxListItemSG : public FxViewItem { public: - FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), section(0), view(v) { + FxListItemSG(QQuickItem *i, QQuickListView *v, bool own) : FxViewItem(i, own), view(v) { attached = static_cast(qmlAttachedPropertiesObject(item)); if (attached) static_cast(attached)->setView(view); @@ -244,12 +244,21 @@ public: ~FxListItemSG() {} + inline QQuickItem *section() const { + return attached ? static_cast(attached)->m_sectionItem : 0; + } + void setSection(QQuickItem *s) { + if (!attached) + attached = static_cast(qmlAttachedPropertiesObject(item)); + static_cast(attached)->m_sectionItem = s; + } + qreal position() const { - if (section) { + if (section()) { if (view->orientation() == QQuickListView::Vertical) - return section->y(); + return section()->y(); else - return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x()); + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section()->width()-section()->x() : section()->x()); } else { return itemPosition(); } @@ -261,8 +270,8 @@ public: return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-itemX() : itemX()); } qreal size() const { - if (section) - return (view->orientation() == QQuickListView::Vertical ? item->height()+section->height() : item->width()+section->width()); + if (section()) + return (view->orientation() == QQuickListView::Vertical ? item->height()+section()->height() : item->width()+section()->width()); else return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); } @@ -270,8 +279,8 @@ public: return (view->orientation() == QQuickListView::Vertical ? item->height() : item->width()); } qreal sectionSize() const { - if (section) - return (view->orientation() == QQuickListView::Vertical ? section->height() : section->width()); + if (section()) + return (view->orientation() == QQuickListView::Vertical ? section()->height() : section()->width()); return 0.0; } qreal endPosition() const { @@ -285,14 +294,14 @@ public: } void setPosition(qreal pos) { // position the section immediately even if there is a transition - if (section) { + if (section()) { if (view->orientation() == QQuickListView::Vertical) { - section->setY(pos); + section()->setY(pos); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) - section->setX(-section->width()-pos); + section()->setX(-section()->width()-pos); else - section->setX(pos); + section()->setX(pos); } } moveTo(pointForPosition(pos)); @@ -311,23 +320,22 @@ public: return view; } - QQuickItem *section; QQuickListView *view; private: QPointF pointForPosition(qreal pos) const { if (view->orientation() == QQuickListView::Vertical) { - if (section) - pos += section->height(); + if (section()) + pos += section()->height(); return QPointF(itemX(), pos); } else { if (view->effectiveLayoutDirection() == Qt::RightToLeft) { - if (section) - pos += section->width(); + if (section()) + pos += section()->width(); return QPointF(-item->width() - pos, itemY()); } else { - if (section) - pos += section->width(); + if (section()) + pos += section()->width(); return QPointF(pos, itemY()); } } @@ -566,25 +574,31 @@ void QQuickListViewPrivate::initializeViewItem(FxViewItem *item) } } -void QQuickListViewPrivate::releaseItem(FxViewItem *item) +bool QQuickListViewPrivate::releaseItem(FxViewItem *item) { - if (item) { - FxListItemSG* listItem = static_cast(item); - if (listItem->section) { - int i = 0; - do { - if (!sectionCache[i]) { - sectionCache[i] = listItem->section; - sectionCache[i]->setVisible(false); - listItem->section = 0; - break; - } - ++i; - } while (i < sectionCacheSize); - delete listItem->section; - } + if (!item || !model) + return true; + + QQuickListViewAttached *att = static_cast(item->attached); + + bool released = QQuickItemViewPrivate::releaseItem(item); + if (released && att && att->m_sectionItem) { + // We hold no more references to this item + int i = 0; + do { + if (!sectionCache[i]) { + sectionCache[i] = att->m_sectionItem; + sectionCache[i]->setVisible(false); + att->m_sectionItem = 0; + break; + } + ++i; + } while (i < sectionCacheSize); + delete att->m_sectionItem; + att->m_sectionItem = 0; } - QQuickItemViewPrivate::releaseItem(item); + + return released; } bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool doBuffer) @@ -944,18 +958,18 @@ void QQuickListViewPrivate::updateInlineSection(FxListItemSG *listItem) if (listItem->attached->m_prevSection != listItem->attached->m_section && (sectionCriteria->labelPositioning() & QQuickViewSection::InlineLabels || (listItem->index == 0 && sectionCriteria->labelPositioning() & QQuickViewSection::CurrentLabelAtStart))) { - if (!listItem->section) { + if (!listItem->section()) { qreal pos = listItem->position(); - listItem->section = getSectionItem(listItem->attached->m_section); + listItem->setSection(getSectionItem(listItem->attached->m_section)); listItem->setPosition(pos); } else { - QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section)->parentContext(); + QDeclarativeContext *context = QDeclarativeEngine::contextForObject(listItem->section())->parentContext(); context->setContextProperty(QLatin1String("section"), listItem->attached->m_section); } - } else if (listItem->section) { + } else if (listItem->section()) { qreal pos = listItem->position(); - releaseSectionItem(listItem->section); - listItem->section = 0; + releaseSectionItem(listItem->section()); + listItem->setSection(0); listItem->setPosition(pos); } } @@ -972,7 +986,7 @@ void QQuickListViewPrivate::updateStickySections() QQuickItem *lastSectionItem = 0; int index = 0; while (index < visibleItems.count()) { - if (QQuickItem *section = static_cast(visibleItems.at(index))->section) { + if (QQuickItem *section = static_cast(visibleItems.at(index))->section()) { // Find the current section header and last visible section header // and hide them if they will overlap a static section header. qreal sectionPos = orient == QQuickListView::Vertical ? section->y() : section->x(); @@ -1173,9 +1187,9 @@ void QQuickListViewPrivate::initializeCurrentItem() if (currentItem) { FxListItemSG *listItem = static_cast(currentItem); - // don't reposition the item if it's about to be transitioned to another position + // don't reposition the item if it is already in the visibleItems list FxViewItem *actualItem = visibleItem(currentIndex); - if ((!actualItem || !actualItem->transitionScheduledOrRunning())) { + if (!actualItem) { if (currentIndex == visibleIndex - 1 && visibleItems.count()) { // We can calculate exact postion in this case listItem->setPosition(visibleItems.first()->position() - currentItem->size() - spacing); @@ -1186,12 +1200,6 @@ void QQuickListViewPrivate::initializeCurrentItem() } } - // Avoid showing section delegate twice. We still need the section heading so that - // currentItem positioning works correctly. - // This is slightly sub-optimal, but section heading caching minimizes the impact. - if (listItem->section) - listItem->section->setVisible(false); - if (visibleItems.isEmpty()) averageSize = listItem->size(); } diff --git a/src/quick/items/qquicklistview_p.h b/src/quick/items/qquicklistview_p.h index bffd935616..058c50f4d7 100644 --- a/src/quick/items/qquicklistview_p.h +++ b/src/quick/items/qquicklistview_p.h @@ -181,7 +181,7 @@ class QQuickListViewAttached : public QQuickItemViewAttached public: QQuickListViewAttached(QObject *parent) - : QQuickItemViewAttached(parent), m_view(0) {} + : QQuickItemViewAttached(parent), m_view(0), m_sectionItem(0) {} ~QQuickListViewAttached() {} Q_PROPERTY(QQuickListView *view READ view NOTIFY viewChanged) @@ -198,6 +198,7 @@ Q_SIGNALS: public: QDeclarativeGuard m_view; + QQuickItem *m_sectionItem; }; -- cgit v1.2.3 From 4fc0df58b8458052a818e3e970a97457882808e6 Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Fri, 24 Feb 2012 13:33:59 +1000 Subject: Force to send defer deletion events before deleting QQuickCanvas Also change the assert in QDeclarativeEnginePrivate::~QDeclarativeEnginePrivate() to a warning message. Change-Id: Ic1fb7e0b7ffe4a54458a0f3a65127b1afd6dda53 Reviewed-by: Michael Brasser --- src/quick/items/qquickcanvas.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index a9df484a98..6b0eb5b96b 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -746,6 +746,7 @@ QQuickCanvas::~QQuickCanvas() QQuickItemPrivate *rootItemPrivate = QQuickItemPrivate::get(d->rootItem); rootItemPrivate->removeFromDirtyList(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); delete d->incubationController; d->incubationController = 0; delete d->rootItem; d->rootItem = 0; -- cgit v1.2.3 From 0bf62c44ab5bc53162ef0d7efea38764e2df8318 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 28 Feb 2012 09:48:27 +1000 Subject: Correctly set duration and easing for AnchorAnimation. Task-number: QTBUG-24532 Change-Id: I3aad9cd8281b954896c2c1d44b2dcae68f913928 Reviewed-by: Yunqiao Yin --- src/quick/items/qquickanimation.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickanimation.cpp b/src/quick/items/qquickanimation.cpp index 4880190697..641fbb2d37 100644 --- a/src/quick/items/qquickanimation.cpp +++ b/src/quick/items/qquickanimation.cpp @@ -551,6 +551,8 @@ QAbstractAnimationJob* QQuickAnchorAnimation::transition(QDeclarativeStateAction delete data; } + animator->setDuration(d->duration); + animator->setEasingCurve(d->easing); return initInstance(animator); } -- cgit v1.2.3 From f2c5c77777b61c8fe54a1107e67283d576301a69 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 27 Feb 2012 15:54:16 +1000 Subject: Incubators are not async with the threaded renderer. The threaded incubator relies on the event loop spinning to signal item updates. This change ensures that the event loop is processed while items are being created and that the render loop is woken if it is sleeping. Also cancel delegate incubation correctly during destruction. Change-Id: Ib5bb55c788411490e0959c75933da587fdfd4b8c Reviewed-by: Yunqiao Yin Reviewed-by: Michael Brasser --- src/quick/items/qquickcanvas.cpp | 7 ++++--- src/quick/items/qquickitemview.cpp | 6 ++++++ src/quick/items/qquickvisualdatamodel.cpp | 21 +++++++++++++++++++-- src/quick/items/qquickvisualdatamodel_p.h | 1 + src/quick/items/qquickvisualitemmodel_p.h | 1 + src/quick/items/qquickwindowmanager.cpp | 22 +++++++++++++++++----- src/quick/items/qquickwindowmanager_p.h | 3 ++- 7 files changed, 50 insertions(+), 11 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index 6b0eb5b96b..e6a3e87401 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -94,11 +94,10 @@ protected: { if (e->type() == QEvent::User) { Q_ASSERT(m_eventSent); - - bool *amtp = m_canvas->windowManager->allowMainThreadProcessing(); + volatile bool *amtp = m_canvas->windowManager->allowMainThreadProcessing(); while (incubatingObjectCount()) { if (amtp) - incubateWhile(amtp); + incubateWhile(amtp, 2); else incubateFor(5); QCoreApplication::processEvents(); @@ -115,6 +114,8 @@ protected: m_eventSent = true; QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } + // If no animations are running, the renderer may be waiting + m_canvas->windowManager->wakeup(); } private: diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index f62fa94f5e..d5ce567590 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2162,6 +2162,12 @@ void QQuickItemViewPrivate::clear() createHighlight(); trackedItem = 0; + if (requestedIndex >= 0 && requestedAsync) { + if (model) + model->cancel(requestedIndex); + requestedIndex = -1; + } + markExtentsDirty(); itemCount = 0; } diff --git a/src/quick/items/qquickvisualdatamodel.cpp b/src/quick/items/qquickvisualdatamodel.cpp index 4fdcc98602..0bdf0cb5af 100644 --- a/src/quick/items/qquickvisualdatamodel.cpp +++ b/src/quick/items/qquickvisualdatamodel.cpp @@ -450,6 +450,21 @@ QQuickVisualDataModel::ReleaseFlags QQuickVisualDataModel::release(QQuickItem *i return stat; } +// Cancel a requested async item +void QQuickVisualDataModel::cancel(int index) +{ + Q_D(QQuickVisualDataModel); + if (!d->m_delegate || index < 0 || index >= d->m_compositor.count(d->m_compositorGroup)) { + qWarning() << "VisualDataModel::cancel: index out range" << index << d->m_compositor.count(d->m_compositorGroup); + return; + } + + Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index); + QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0; + if (cacheItem && cacheItem->incubationTask) + d->releaseIncubator(cacheItem->incubationTask); +} + void QQuickVisualDataModelPrivate::group_append( QDeclarativeListProperty *property, QQuickVisualDataGroup *group) { @@ -708,8 +723,10 @@ void QQuickVisualDataModelPrivate::incubatorStatusChanged(QVDMIncubationTask *in incubationTask->incubatingContext = 0; if (!cacheItem->isReferenced()) { int cidx = m_cache.indexOf(cacheItem); - m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag); - m_cache.removeAt(cidx); + if (cidx >= 0) { + m_compositor.clearFlags(Compositor::Cache, cidx, 1, Compositor::CacheFlag); + m_cache.removeAt(cidx); + } delete cacheItem; Q_ASSERT(m_cache.count() == m_compositor.count(Compositor::Cache)); } diff --git a/src/quick/items/qquickvisualdatamodel_p.h b/src/quick/items/qquickvisualdatamodel_p.h index 54cc16d660..043fcfd8a9 100644 --- a/src/quick/items/qquickvisualdatamodel_p.h +++ b/src/quick/items/qquickvisualdatamodel_p.h @@ -106,6 +106,7 @@ public: bool isValid() const { return delegate() != 0; } QQuickItem *item(int index, bool asynchronous=false); ReleaseFlags release(QQuickItem *item); + void cancel(int index); virtual QString stringValue(int index, const QString &role); virtual void setWatchedRoles(QList roles); diff --git a/src/quick/items/qquickvisualitemmodel_p.h b/src/quick/items/qquickvisualitemmodel_p.h index f1c9d066be..7d2b79f718 100644 --- a/src/quick/items/qquickvisualitemmodel_p.h +++ b/src/quick/items/qquickvisualitemmodel_p.h @@ -69,6 +69,7 @@ public: virtual bool isValid() const = 0; virtual QQuickItem *item(int index, bool asynchronous=false) = 0; virtual ReleaseFlags release(QQuickItem *item) = 0; + virtual void cancel(int) {} virtual QString stringValue(int, const QString &) = 0; virtual void setWatchedRoles(QList roles) = 0; diff --git a/src/quick/items/qquickwindowmanager.cpp b/src/quick/items/qquickwindowmanager.cpp index 16b6d92e22..79fd266e1e 100644 --- a/src/quick/items/qquickwindowmanager.cpp +++ b/src/quick/items/qquickwindowmanager.cpp @@ -193,6 +193,7 @@ public: void resize(QQuickCanvas *canvas, const QSize &size); void handleDeferredUpdate(); void maybeUpdate(QQuickCanvas *canvas); + void wakeup(); void startRendering(); void stopRendering(); @@ -202,7 +203,7 @@ public: void initialize(); - bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; } + volatile bool *allowMainThreadProcessing() { return &allowMainThreadProcessingFlag; } bool event(QEvent *); @@ -243,7 +244,7 @@ private: QMutex mutex; QWaitCondition condition; - bool allowMainThreadProcessingFlag; + volatile bool allowMainThreadProcessingFlag; int isGuiLocked; uint animationRunning: 1; @@ -299,12 +300,13 @@ public: void paint(QQuickCanvas *canvas); QImage grab(QQuickCanvas *canvas); void resize(QQuickCanvas *canvas, const QSize &size); + void wakeup(); void maybeUpdate(QQuickCanvas *canvas); void releaseResources() { } - bool *allowMainThreadProcessing(); + volatile bool *allowMainThreadProcessing(); QSGContext *sceneGraphContext() const; @@ -1129,6 +1131,14 @@ void QQuickRenderThreadSingleContextWindowManager::maybeUpdate(QQuickCanvas *) } +void QQuickRenderThreadSingleContextWindowManager::wakeup() +{ + lockInGui(); + if (isRenderBlocked) + wake(); + unlockInGui(); +} + QQuickTrivialWindowManager::QQuickTrivialWindowManager() : gl(0) , eventPending(false) @@ -1268,9 +1278,11 @@ void QQuickTrivialWindowManager::maybeUpdate(QQuickCanvas *canvas) } } +void QQuickTrivialWindowManager::wakeup() +{ +} - -bool *QQuickTrivialWindowManager::allowMainThreadProcessing() +volatile bool *QQuickTrivialWindowManager::allowMainThreadProcessing() { return 0; } diff --git a/src/quick/items/qquickwindowmanager_p.h b/src/quick/items/qquickwindowmanager_p.h index 86312655b3..a0bdf08a91 100644 --- a/src/quick/items/qquickwindowmanager_p.h +++ b/src/quick/items/qquickwindowmanager_p.h @@ -64,8 +64,9 @@ public: virtual void resize(QQuickCanvas *canvas, const QSize &size) = 0; virtual void maybeUpdate(QQuickCanvas *canvas) = 0; + virtual void wakeup() = 0; - virtual bool *allowMainThreadProcessing() = 0; + virtual volatile bool *allowMainThreadProcessing() = 0; virtual QSGContext *sceneGraphContext() const = 0; -- cgit v1.2.3 From f7dae3960b2ab6f5db3a79e3ea701f2531b909d7 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Feb 2012 09:33:42 +1000 Subject: Add AnimatedSprite A simpler sprite image element for the simple usecase. Because sometimes an engine with stochastic capabilities is overkill. Change-Id: I2b76c5d417719e92a548f6266bffd563dc016983 Reviewed-by: Alan Alpert --- src/quick/items/items.pri | 2 + src/quick/items/qquickanimatedsprite.cpp | 613 +++++++++++++++++++++++++++++++ src/quick/items/qquickanimatedsprite_p.h | 373 +++++++++++++++++++ src/quick/items/qquickitemsmodule.cpp | 2 + src/quick/items/qquicksprite_p.h | 1 + 5 files changed, 991 insertions(+) create mode 100644 src/quick/items/qquickanimatedsprite.cpp create mode 100644 src/quick/items/qquickanimatedsprite_p.h (limited to 'src/quick/items') diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index f02c769c3a..bdd1692e85 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -66,6 +66,7 @@ HEADERS += \ $$PWD/qquickspriteengine_p.h \ $$PWD/qquicksprite_p.h \ $$PWD/qquickspriteimage_p.h \ + $$PWD/qquickanimatedsprite_p.h \ $$PWD/qquickdrag_p.h \ $$PWD/qquickdroparea_p.h \ $$PWD/qquickmultipointtoucharea_p.h \ @@ -117,6 +118,7 @@ SOURCES += \ $$PWD/qquickspriteengine.cpp \ $$PWD/qquicksprite.cpp \ $$PWD/qquickspriteimage.cpp \ + $$PWD/qquickanimatedsprite.cpp \ $$PWD/qquickaccessibleattached.cpp \ $$PWD/qquickdrag.cpp \ $$PWD/qquickdroparea.cpp \ diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp new file mode 100644 index 0000000000..ef79d052a8 --- /dev/null +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -0,0 +1,613 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickanimatedsprite_p.h" +#include "qquicksprite_p.h" +#include "qquickspriteengine_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char vertexShaderCode[] = + "attribute highp vec2 vTex;\n" + "uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress\n" + "uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)\n" + "uniform highp vec2 size;//w,h of element\n" + "\n" + "uniform highp mat4 qt_Matrix;\n" + "\n" + "varying highp vec4 fTexS;\n" + "varying lowp float progress;\n" + "\n" + "\n" + "void main() {\n" + " progress = animData.z;\n" + " //Calculate frame location in texture\n" + " fTexS.xy = animPos.xy + vTex.xy * animData.xy;\n" + " //Next frame is also passed, for interpolation\n" + " fTexS.zw = animPos.zw + vTex.xy * animData.xy;\n" + "\n" + " gl_Position = qt_Matrix * vec4(size.x * vTex.x, size.y * vTex.y, 0, 1);\n" + "}\n"; + +static const char fragmentShaderCode[] = + "uniform sampler2D texture;\n" + "uniform lowp float qt_Opacity;\n" + "\n" + "varying highp vec4 fTexS;\n" + "varying lowp float progress;\n" + "\n" + "void main() {\n" + " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), progress) * qt_Opacity;\n" + "}\n"; + +class QQuickAnimatedSpriteMaterial : public QSGMaterial +{ +public: + QQuickAnimatedSpriteMaterial(); + ~QQuickAnimatedSpriteMaterial(); + virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; } + virtual QSGMaterialShader *createShader() const; + virtual int compare(const QSGMaterial *other) const + { + return this - static_cast(other); + } + + QSGTexture *texture; + + float animT; + float animX1; + float animY1; + float animX2; + float animY2; + float animW; + float animH; + float elementWidth; + float elementHeight; +}; + +QQuickAnimatedSpriteMaterial::QQuickAnimatedSpriteMaterial() + : texture(0) + , animT(0.0f) + , animX1(0.0f) + , animY1(0.0f) + , animX2(0.0f) + , animY2(0.0f) + , animW(1.0f) + , animH(1.0f) + , elementWidth(1.0f) + , elementHeight(1.0f) +{ + setFlag(Blending, true); +} + +QQuickAnimatedSpriteMaterial::~QQuickAnimatedSpriteMaterial() +{ + delete texture; +} + +class AnimatedSpriteMaterialData : public QSGMaterialShader +{ +public: + AnimatedSpriteMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0) + { + } + + void deactivate() { + QSGMaterialShader::deactivate(); + + for (int i=0; i<8; ++i) { + program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0); + } + } + + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) + { + QQuickAnimatedSpriteMaterial *m = static_cast(newEffect); + m->texture->bind(); + + program()->setUniformValue(m_opacity_id, state.opacity()); + program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); + program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); + program()->setUniformValue(m_size_id, m->elementWidth, m->elementHeight); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_animData_id = program()->uniformLocation("animData"); + m_animPos_id = program()->uniformLocation("animPos"); + m_size_id = program()->uniformLocation("size"); + } + + virtual const char *vertexShader() const { return vertexShaderCode; } + virtual const char *fragmentShader() const { return fragmentShaderCode; } + + virtual char const *const *attributeNames() const { + static const char *attr[] = { + "vTex", + 0 + }; + return attr; + } + + int m_matrix_id; + int m_opacity_id; + int m_animData_id; + int m_animPos_id; + int m_size_id; + + static float chunkOfBytes[1024]; +}; + +float AnimatedSpriteMaterialData::chunkOfBytes[1024]; + +QSGMaterialShader *QQuickAnimatedSpriteMaterial::createShader() const +{ + return new AnimatedSpriteMaterialData; +} + +struct AnimatedSpriteVertex { + float tx; + float ty; +}; + +struct AnimatedSpriteVertices { + AnimatedSpriteVertex v1; + AnimatedSpriteVertex v2; + AnimatedSpriteVertex v3; + AnimatedSpriteVertex v4; +}; + +/*! + \qmlclass AnimatedSprite QQuickAnimatedSprite + \inqmlmodule QtQuick 2 + \inherits Item + \brief The AnimatedSprite element draws a sprite animation +*/ + +/*! + \qmlproperty bool QtQuick2::AnimatedSprite::running + + Whether the sprite is animating or not. + + Default is true +*/ + +/*! + \qmlproperty bool QtQuick2::AnimatedSprite::interpolate + + If true, interpolation will occur between sprite frames to make the + animation appear smoother. + + Default is true. +*/ + +/*! + \qmlproperty qreal QtQuick2::AnimatedSprite::frameRate + + Frames per second to show in the animation. Values below 0 are invalid. + + If frameRate is valid then it will be used to calculate the duration of the frames. + If not, and frameDuration is valid , then frameDuration will be used. +*/ + +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameDuration + + Duration of each frame of the animation. Values below 0 are invalid. + + If frameRate is valid then it will be used to calculate the duration of the frames. + If not, and frameDuration is valid, then frameDuration will be used. +*/ + +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameCount + + Number of frames in this AnimatedSprite. +*/ +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameHeight + + Height of a single frame in this AnimatedSprite. + + May be omitted if it is the only sprite in the file. +*/ +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameWidth + + Width of a single frame in this AnimatedSprite. + + May be omitted if it is the only sprite in the file. +*/ +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameX + + The X coordinate in the image file of the first frame of the AnimatedSprite. + + May be omitted if the first frame starts in the upper left corner of the file. +*/ +/*! + \qmlproperty int QtQuick2::AnimatedSprite::frameY + + The Y coordinate in the image file of the first frame of the AnimatedSprite. + + May be omitted if the first frame starts in the upper left corner of the file. +*/ +/*! + \qmlproperty url QtQuick2::AnimatedSprite::source + + The image source for the animation. + + If frameHeight and frameWidth are not specified, it is assumed to be a single long row of square frames. + Otherwise, it can be multiple contiguous rows or rectangluar frames, when one row runs out the next will be used. + + If frameX and frameY are specified, the row of frames will be taken with that x/y coordinate as the upper left corner. +*/ + +/*! + \qmlproperty bool QtQuick2::AnimatedSprite::reverse + + If true, then the animation will be played in reverse. + + Default is false. +*/ + +/*! + \qmlproperty bool QtQuick2::AnimatedSprite::frameSync + + If true, then the animation will have no duration. Instead, the animation will advance + one frame each time a frame is rendered to the screen. This syncronizes it with the painting + rate as opposed to elapsed time. + + If frameSync is set to true, it overrides both frameRate and frameDuration. + + Default is false. +*/ + +/*! + \qmlproperty int QtQuick2::AnimatedSprite::loops + + After playing the animation this many times, the animation will automatically stop. Negative values are invalid. + + If this is set to AnimatedSprite.Infinite the animation will not stop playing on its own. + + Default is AnimatedSprite.Infinite +*/ + +/*! + \qmlproperty bool QtQuick2::AnimatedSprite::paused + + When paused, the current frame can be advanced manually. + + Default is false. +*/ + +/*! + \qmlproperty int QtQuick2::AnimatedSprite::currentFrame + + When paused, the current frame can be advanced manually by setting this property or calling advance(). + +*/ + +//TODO: Implicitly size element to size of sprite +QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : + QQuickItem(parent) + , m_node(0) + , m_material(0) + , m_sprite(new QQuickSprite) + , m_spriteEngine(0) + , m_curFrame(0) + , m_pleaseReset(false) + , m_running(true) + , m_paused(false) + , m_interpolate(true) + , m_loops(-1) + , m_curLoop(0) + , m_pauseOffset(0) +{ + setFlag(ItemHasContents); + connect(this, SIGNAL(runningChanged(bool)), + this, SLOT(update())); +} + +void QQuickAnimatedSprite::reloadImage() +{ + if (!isComponentComplete()) + return; + createEngine();//### It's not as inefficient as it sounds, but it still sucks having to recreate the engine +} + +void QQuickAnimatedSprite::componentComplete() +{ + createEngine(); + QQuickItem::componentComplete(); + if (m_running) + start(); +} + +void QQuickAnimatedSprite::start() +{ + if (m_running) + return; + m_curLoop = 0; + m_timestamp.start(); + m_running = true; + emit runningChanged(true); + update(); +} + +void QQuickAnimatedSprite::stop() +{ + if (!m_running) + return; + m_running = false; + emit runningChanged(false); +} + +void QQuickAnimatedSprite::advance(int frames) +{ + if (!frames) + return; + //TODO-C: May not work when running - only when paused + m_curFrame += frames; + while (m_curFrame < 0) + m_curFrame += m_sprite->frames(); + m_curFrame = m_curFrame % m_sprite->frames(); + emit currentFrameChanged(m_curFrame); +} + +void QQuickAnimatedSprite::pause() +{ + if (m_paused) + return; + m_pauseOffset = m_timestamp.elapsed(); + m_paused = true; + emit pausedChanged(true); +} + +void QQuickAnimatedSprite::resume() +{ + if (!m_paused) + return; + m_pauseOffset = m_pauseOffset - m_timestamp.elapsed(); + m_paused = false; + emit pausedChanged(false); +} + +void QQuickAnimatedSprite::createEngine() +{ + if (m_spriteEngine) + delete m_spriteEngine; + QList spriteList; + spriteList << m_sprite; + m_spriteEngine = new QQuickSpriteEngine(QList(spriteList), this); + m_spriteEngine->startAssemblingImage(); + reset(); +} + +static QSGGeometry::Attribute AnimatedSprite_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, GL_FLOAT), // tex +}; + +static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet = +{ + 1, // Attribute Count + 2 * sizeof(float), + AnimatedSprite_Attributes +}; + +QSGGeometryNode* QQuickAnimatedSprite::buildNode() +{ + if (!m_spriteEngine) { + qmlInfo(this) << "No sprite engine..."; + return 0; + } else if (m_spriteEngine->status() == QDeclarativePixmap::Null) { + m_spriteEngine->startAssemblingImage(); + update();//Schedule another update, where we will check again + return 0; + } else if (m_spriteEngine->status() == QDeclarativePixmap::Loading) { + update();//Schedule another update, where we will check again + return 0; + } + + m_material = new QQuickAnimatedSpriteMaterial(); + + QImage image = m_spriteEngine->assembledImage(); + if (image.isNull()) + return 0; + m_sheetSize = QSizeF(image.size()); + m_material->texture = canvas()->createTextureFromImage(image); + m_material->texture->setFiltering(QSGTexture::Linear); + m_spriteEngine->start(0); + m_material->animT = 0; + m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + m_material->animX2 = m_material->animX1; + m_material->animY2 = m_material->animY1; + m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + m_material->elementWidth = width(); + m_material->elementHeight = height(); + + int vCount = 4; + int iCount = 6; + QSGGeometry *g = new QSGGeometry(AnimatedSprite_AttributeSet, vCount, iCount); + g->setDrawingMode(GL_TRIANGLES); + + AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData(); + + p->v1.tx = 0; + p->v1.ty = 0; + + p->v2.tx = 1.0; + p->v2.ty = 0; + + p->v3.tx = 0; + p->v3.ty = 1.0; + + p->v4.tx = 1.0; + p->v4.ty = 1.0; + + quint16 *indices = g->indexDataAsUShort(); + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + indices[3] = 1; + indices[4] = 3; + indices[5] = 2; + + + m_timestamp.start(); + m_node = new QSGGeometryNode(); + m_node->setGeometry(g); + m_node->setMaterial(m_material); + m_node->setFlag(QSGGeometryNode::OwnsMaterial); + return m_node; +} + +void QQuickAnimatedSprite::reset() +{ + m_pleaseReset = true; +} + +QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +{ + if (m_pleaseReset) { + delete m_node; + + m_node = 0; + m_material = 0; + m_pleaseReset = false; + } + + prepareNextFrame(); + + if (m_running) { + update(); + if (m_node) + m_node->markDirty(QSGNode::DirtyMaterial); + } + + return m_node; +} + +void QQuickAnimatedSprite::prepareNextFrame() +{ + if (m_node == 0) + m_node = buildNode(); + if (m_node == 0) //error creating node + return; + + uint timeInt = m_timestamp.elapsed() + m_pauseOffset; + qreal time = timeInt / 1000.; + m_material->elementHeight = height(); + m_material->elementWidth = width(); + + double frameAt; //double just for modf + qreal progress; + if (!m_paused) { + //Advance State (keeps time for psuedostates) + m_spriteEngine->updateSprites(timeInt); + + //Advance AnimatedSprite + qreal animT = m_spriteEngine->spriteStart()/1000.0; + qreal frameCount = m_spriteEngine->spriteFrames(); + qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount; + if (frameDuration > 0) { + qreal frame = (time - animT)/(frameDuration / 1000.0); + frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation + progress = modf(frame,&frameAt); + if (m_curFrame > frameAt) //went around + m_curLoop++; + m_curFrame = frameAt; + } else { + m_curFrame++; + if (m_curFrame >= frameCount){ + m_curFrame = 0; + m_curLoop++; + m_spriteEngine->advance(); + } + frameAt = m_curFrame; + progress = 0; + } + if (m_loops > 0 && m_curLoop >= m_loops) { + frameAt = 0; + m_running = false; + } + } else { + frameAt = m_curFrame; + } + if (m_spriteEngine->sprite()->reverse()) + frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt; + qreal y = m_spriteEngine->spriteY() / m_sheetSize.height(); + qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + x1 += frameAt * w; + qreal x2 = x1; + if (frameAt < (m_spriteEngine->spriteFrames()-1)) + x2 += w; + + m_material->animX1 = x1; + m_material->animY1 = y; + m_material->animX2 = x2; + m_material->animY2 = y; + m_material->animW = w; + m_material->animH = h; + m_material->animT = m_interpolate ? progress : 0.0; +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h new file mode 100644 index 0000000000..062b191621 --- /dev/null +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKANIMATEDSPRITE_P_H +#define QQUICKANIMATEDSPRITE_P_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSGContext; +class QQuickSprite; +class QQuickSpriteEngine; +class QSGGeometryNode; +class QQuickAnimatedSpriteMaterial; +class Q_AUTOTEST_EXPORT QQuickAnimatedSprite : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(bool interpolate READ interpolate WRITE setInterpolate NOTIFY interpolateChanged) + //###try to share similar spriteEngines for less overhead? + //These properties come out of QQuickSprite, since a SimpleSpriteImage is a renderer for a single sprite + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool reverse READ reverse WRITE setReverse NOTIFY reverseChanged) + Q_PROPERTY(bool frameSync READ frameSync WRITE setFrameSync NOTIFY frameSyncChanged) + Q_PROPERTY(int frameCount READ frameCount WRITE setFrameCount NOTIFY frameCountChanged) + //If frame height or width is not specified, it is assumed to be a single long row of square frames. + //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used. + Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged) + Q_PROPERTY(int frameWidth READ frameWidth WRITE setFrameWidth NOTIFY frameWidthChanged) + Q_PROPERTY(int frameX READ frameX WRITE setFrameX NOTIFY frameXChanged) + Q_PROPERTY(int frameY READ frameY WRITE setFrameY NOTIFY frameYChanged) + //Precedence order: frameRate, frameDuration + Q_PROPERTY(qreal frameRate READ frameRate WRITE setFrameRate NOTIFY frameRateChanged RESET resetFrameRate) + Q_PROPERTY(int frameDuration READ frameDuration WRITE setFrameDuration NOTIFY frameDurationChanged RESET resetFrameDuration) + //Extra Simple Sprite Stuff + Q_PROPERTY(int loops READ loops WRITE setLoops NOTIFY loopsChanged) + Q_PROPERTY(bool paused READ paused WRITE setPaused NOTIFY pausedChanged) + Q_PROPERTY(int currentFrame READ currentFrame WRITE setCurrentFrame NOTIFY currentFrameChanged) + + Q_ENUMS(LoopParameters) +public: + explicit QQuickAnimatedSprite(QQuickItem *parent = 0); + enum LoopParameters { + Infinite = -1 + }; + + bool running() const + { + return m_running; + } + + bool interpolate() const + { + return m_interpolate; + } + + QUrl source() const + { + return m_sprite->source(); + } + + bool reverse() const + { + return m_sprite->reverse(); + } + + bool frameSync() const + { + return m_sprite->frameSync(); + } + + int frameCount() const + { + return m_sprite->frames(); + } + + int frameHeight() const + { + return m_sprite->frameHeight(); + } + + int frameWidth() const + { + return m_sprite->frameWidth(); + } + + int frameX() const + { + return m_sprite->frameX(); + } + + int frameY() const + { + return m_sprite->frameY(); + } + + qreal frameRate() const + { + return m_sprite->frameRate(); + } + + int frameDuration() const + { + return m_sprite->frameDuration(); + } + + int loops() const + { + return m_loops; + } + + bool paused() const + { + return m_paused; + } + + int currentFrame() const + { + return m_curFrame; + } + +signals: + + void pausedChanged(bool arg); + void runningChanged(bool arg); + void interpolateChanged(bool arg); + + void sourceChanged(QUrl arg); + + void reverseChanged(bool arg); + + void frameSyncChanged(bool arg); + + void frameCountChanged(int arg); + + void frameHeightChanged(int arg); + + void frameWidthChanged(int arg); + + void frameXChanged(int arg); + + void frameYChanged(int arg); + + void frameRateChanged(qreal arg); + + void frameDurationChanged(int arg); + + void loopsChanged(int arg); + + void currentFrameChanged(int arg); + +public slots: + void start(); + void stop(); + void restart() {stop(); start();} + void advance(int frames=1); + void pause(); + void resume(); + + void setRunning(bool arg) + { + if (m_running != arg) { + if (m_running) + stop(); + else + start(); + } + } + + void setPaused(bool arg) + { + if (m_paused != arg) { + if (m_paused) + resume(); + else + pause(); + } + } + + void setInterpolate(bool arg) + { + if (m_interpolate != arg) { + m_interpolate = arg; + emit interpolateChanged(arg); + } + } + + void setSource(QUrl arg) + { + if (m_sprite->m_source != arg) { + m_sprite->setSource(arg); + emit sourceChanged(arg); + } + } + + void setReverse(bool arg) + { + if (m_sprite->m_reverse != arg) { + m_sprite->setReverse(arg); + emit reverseChanged(arg); + } + } + + void setFrameSync(bool arg) + { + if (m_sprite->m_frameSync != arg) { + m_sprite->setFrameSync(arg); + emit frameSyncChanged(arg); + } + } + + void setFrameCount(int arg) + { + if (m_sprite->m_frames != arg) { + m_sprite->setFrameCount(arg); + emit frameCountChanged(arg); + reloadImage(); + } + } + + void setFrameHeight(int arg) + { + if (m_sprite->m_frameHeight != arg) { + m_sprite->setFrameHeight(arg); + emit frameHeightChanged(arg); + reloadImage(); + } + } + + void setFrameWidth(int arg) + { + if (m_sprite->m_frameWidth != arg) { + m_sprite->setFrameWidth(arg); + emit frameWidthChanged(arg); + reloadImage(); + } + } + + void setFrameX(int arg) + { + if (m_sprite->m_frameX != arg) { + m_sprite->setFrameX(arg); + emit frameXChanged(arg); + reloadImage(); + } + } + + void setFrameY(int arg) + { + if (m_sprite->m_frameY != arg) { + m_sprite->setFrameY(arg); + emit frameYChanged(arg); + reloadImage(); + } + } + + void setFrameRate(qreal arg) + { + if (m_sprite->m_frameRate != arg) { + m_sprite->setFrameRate(arg); + emit frameRateChanged(arg); + } + } + + void setFrameDuration(int arg) + { + if (m_sprite->m_frameDuration != arg) { + m_sprite->setFrameDuration(arg); + emit frameDurationChanged(arg); + } + } + + void resetFrameRate() + { + setFrameRate(-1.0); + } + + void resetFrameDuration() + { + setFrameDuration(-1); + } + + void setLoops(int arg) + { + if (m_loops != arg) { + m_loops = arg; + emit loopsChanged(arg); + } + } + + void setCurrentFrame(int arg) //TODO-C: Probably only works when paused + { + if (m_curFrame != arg) { + m_curFrame = arg; + emit currentFrameChanged(arg); //TODO-C Only emitted on manual advance! + } + } + + +private slots: + void createEngine(); +protected: + void reset(); + void componentComplete(); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); +private: + void prepareNextFrame(); + void reloadImage(); + QSGGeometryNode* buildNode(); + QSGGeometryNode *m_node; + QQuickAnimatedSpriteMaterial *m_material; + QQuickSprite* m_sprite; + QQuickSpriteEngine* m_spriteEngine; + QTime m_timestamp; + int m_curFrame; + bool m_pleaseReset; + bool m_running; + bool m_paused; + bool m_interpolate; + QSizeF m_sheetSize; + int m_loops; + int m_curLoop; + int m_pauseOffset; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQUICKANIMATEDSPRITE_P_H diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index a4cfa26205..2c74e3c91c 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -78,6 +78,7 @@ #include #include "qquicksprite_p.h" #include "qquickspriteimage_p.h" +#include "qquickanimatedsprite_p.h" #include "qquickdrag_p.h" #include "qquickdroparea_p.h" #include "qquickmultipointtoucharea_p.h" @@ -200,6 +201,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType("QtQuick", 2, 0, "Canvas"); qmlRegisterType("QtQuick", 2, 0, "Sprite"); + qmlRegisterType("QtQuick", 2, 0, "AnimatedSprite"); qmlRegisterType("QtQuick", 2, 0, "SpriteImage"); qmlRegisterType(uri, major, minor,"ParentChange"); diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 4c5e5ff58e..98cc90ad8c 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -279,6 +279,7 @@ private slots: private: friend class QQuickImageParticle; friend class QQuickSpriteImage; + friend class QQuickAnimatedSprite; friend class QQuickSpriteEngine; friend class QQuickStochasticEngine; int m_generatedCount; -- cgit v1.2.3 From 75a0d33d250a97d5ee0314f5b7aad876d9ee2fa8 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 14 Feb 2012 18:16:21 +1000 Subject: Rename SpriteImage to SpriteSequence Also rename Sprite::frames->Sprite::frameCount Change-Id: I2e7a71adc37044fd696ffda2a5da4835725ba3a8 Reviewed-by: Alan Alpert --- src/quick/items/items.pri | 4 +- src/quick/items/qquickitemsmodule.cpp | 5 +- src/quick/items/qquicksprite.cpp | 2 +- src/quick/items/qquicksprite_p.h | 21 +- src/quick/items/qquickspriteimage.cpp | 482 ------------------------------- src/quick/items/qquickspriteimage_p.h | 148 ---------- src/quick/items/qquickspritesequence.cpp | 482 +++++++++++++++++++++++++++++++ src/quick/items/qquickspritesequence_p.h | 148 ++++++++++ 8 files changed, 653 insertions(+), 639 deletions(-) delete mode 100644 src/quick/items/qquickspriteimage.cpp delete mode 100644 src/quick/items/qquickspriteimage_p.h create mode 100644 src/quick/items/qquickspritesequence.cpp create mode 100644 src/quick/items/qquickspritesequence_p.h (limited to 'src/quick/items') diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index bdd1692e85..21bf7cc8c1 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -65,7 +65,7 @@ HEADERS += \ $$PWD/qquickimplicitsizeitem_p_p.h \ $$PWD/qquickspriteengine_p.h \ $$PWD/qquicksprite_p.h \ - $$PWD/qquickspriteimage_p.h \ + $$PWD/qquickspritesequence_p.h \ $$PWD/qquickanimatedsprite_p.h \ $$PWD/qquickdrag_p.h \ $$PWD/qquickdroparea_p.h \ @@ -117,7 +117,7 @@ SOURCES += \ $$PWD/qquickimplicitsizeitem.cpp \ $$PWD/qquickspriteengine.cpp \ $$PWD/qquicksprite.cpp \ - $$PWD/qquickspriteimage.cpp \ + $$PWD/qquickspritesequence.cpp \ $$PWD/qquickanimatedsprite.cpp \ $$PWD/qquickaccessibleattached.cpp \ $$PWD/qquickdrag.cpp \ diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 2c74e3c91c..b9e401a231 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -77,7 +77,7 @@ #include #include #include "qquicksprite_p.h" -#include "qquickspriteimage_p.h" +#include "qquickspritesequence_p.h" #include "qquickanimatedsprite_p.h" #include "qquickdrag_p.h" #include "qquickdroparea_p.h" @@ -202,7 +202,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType("QtQuick", 2, 0, "Sprite"); qmlRegisterType("QtQuick", 2, 0, "AnimatedSprite"); - qmlRegisterType("QtQuick", 2, 0, "SpriteImage"); + qmlRegisterType("QtQuick", 2, 0, "SpriteSequence"); + qmlRegisterType("QtQuick", 2, 0, "SpriteImage");//Deprecation in progress qmlRegisterType(uri, major, minor,"ParentChange"); qmlRegisterType(uri, major, minor,"AnchorChanges"); diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index 4de7880916..2a1bd08d59 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -145,7 +145,7 @@ QT_BEGIN_NAMESPACE will repeat itself after completing. */ /*! - \qmlproperty int QtQuick2::Sprite::frames + \qmlproperty int QtQuick2::Sprite::frameCount Number of frames in this sprite. */ diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 98cc90ad8c..dd6560f5ab 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -48,6 +48,7 @@ #include #include #include "qquickspriteengine_p.h" +#include QT_BEGIN_HEADER @@ -60,7 +61,8 @@ class QQuickSprite : public QQuickStochasticState //Renderers have to query this hint when advancing frames Q_PROPERTY(bool reverse READ reverse WRITE setReverse NOTIFY reverseChanged) Q_PROPERTY(bool frameSync READ frameSync WRITE setFrameSync NOTIFY frameSyncChanged) - Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY framesChanged) + Q_PROPERTY(int frames READ frames WRITE setFrames NOTIFY frameCountChanged) + Q_PROPERTY(int frameCount READ frameCount WRITE setFrameCount NOTIFY frameCountChanged) //If frame height or width is not specified, it is assumed to be a single long row of square frames. //Otherwise, it can be multiple contiguous rows, when one row runs out the next will be used. Q_PROPERTY(int frameHeight READ frameHeight WRITE setFrameHeight NOTIFY frameHeightChanged) @@ -101,6 +103,11 @@ public: return m_frames; } + int frameCount() const + { + return m_frames; + } + int frameX() const { return m_frameX; @@ -158,7 +165,7 @@ signals: void reverseChanged(bool arg); - void framesChanged(int arg); + void frameCountChanged(int arg); void frameXChanged(int arg); @@ -210,10 +217,16 @@ public slots: } void setFrames(int arg) + { + qWarning() << "Sprite::frames has been renamed Sprite::frameCount"; + setFrameCount(arg); + } + + void setFrameCount(int arg) { if (m_frames != arg) { m_frames = arg; - emit framesChanged(arg); + emit frameCountChanged(arg); } } @@ -278,7 +291,7 @@ private slots: private: friend class QQuickImageParticle; - friend class QQuickSpriteImage; + friend class QQuickSpriteSequence; friend class QQuickAnimatedSprite; friend class QQuickSpriteEngine; friend class QQuickStochasticEngine; diff --git a/src/quick/items/qquickspriteimage.cpp b/src/quick/items/qquickspriteimage.cpp deleted file mode 100644 index 1b3b57710a..0000000000 --- a/src/quick/items/qquickspriteimage.cpp +++ /dev/null @@ -1,482 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the Declarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickspriteimage_p.h" -#include "qquicksprite_p.h" -#include "qquickspriteengine_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -static const char vertexShaderCode[] = - "attribute highp vec2 vTex;\n" - "uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress\n" - "uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)\n" - "uniform highp vec2 size;//w,h of element\n" - "\n" - "uniform highp mat4 qt_Matrix;\n" - "\n" - "varying highp vec4 fTexS;\n" - "varying lowp float progress;\n" - "\n" - "\n" - "void main() {\n" - " progress = animData.z;\n" - " //Calculate frame location in texture\n" - " fTexS.xy = animPos.xy + vTex.xy * animData.xy;\n" - " //Next frame is also passed, for interpolation\n" - " fTexS.zw = animPos.zw + vTex.xy * animData.xy;\n" - "\n" - " gl_Position = qt_Matrix * vec4(size.x * vTex.x, size.y * vTex.y, 0, 1);\n" - "}\n"; - -static const char fragmentShaderCode[] = - "uniform sampler2D texture;\n" - "uniform lowp float qt_Opacity;\n" - "\n" - "varying highp vec4 fTexS;\n" - "varying lowp float progress;\n" - "\n" - "void main() {\n" - " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), progress) * qt_Opacity;\n" - "}\n"; - -class QQuickSpriteImageMaterial : public QSGMaterial -{ -public: - QQuickSpriteImageMaterial(); - ~QQuickSpriteImageMaterial(); - virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; } - virtual QSGMaterialShader *createShader() const; - virtual int compare(const QSGMaterial *other) const - { - return this - static_cast(other); - } - - QSGTexture *texture; - - float animT; - float animX1; - float animY1; - float animX2; - float animY2; - float animW; - float animH; - float elementWidth; - float elementHeight; -}; - -QQuickSpriteImageMaterial::QQuickSpriteImageMaterial() - : animT(0.0f) - , animX1(0.0f) - , animY1(0.0f) - , animX2(0.0f) - , animY2(0.0f) - , animW(1.0f) - , animH(1.0f) - , elementWidth(1.0f) - , elementHeight(1.0f) -{ - setFlag(Blending, true); -} - -QQuickSpriteImageMaterial::~QQuickSpriteImageMaterial() -{ - delete texture; -} - -class SpriteImageMaterialData : public QSGMaterialShader -{ -public: - SpriteImageMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0) - { - } - - void deactivate() { - QSGMaterialShader::deactivate(); - - for (int i=0; i<8; ++i) { - program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0); - } - } - - virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) - { - QQuickSpriteImageMaterial *m = static_cast(newEffect); - m->texture->bind(); - - program()->setUniformValue(m_opacity_id, state.opacity()); - program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); - program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); - program()->setUniformValue(m_size_id, m->elementWidth, m->elementHeight); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); - } - - virtual void initialize() { - m_matrix_id = program()->uniformLocation("qt_Matrix"); - m_opacity_id = program()->uniformLocation("qt_Opacity"); - m_animData_id = program()->uniformLocation("animData"); - m_animPos_id = program()->uniformLocation("animPos"); - m_size_id = program()->uniformLocation("size"); - } - - virtual const char *vertexShader() const { return vertexShaderCode; } - virtual const char *fragmentShader() const { return fragmentShaderCode; } - - virtual char const *const *attributeNames() const { - static const char *attr[] = { - "vTex", - 0 - }; - return attr; - } - - int m_matrix_id; - int m_opacity_id; - int m_animData_id; - int m_animPos_id; - int m_size_id; - - static float chunkOfBytes[1024]; -}; - -float SpriteImageMaterialData::chunkOfBytes[1024]; - -QSGMaterialShader *QQuickSpriteImageMaterial::createShader() const -{ - return new SpriteImageMaterialData; -} - -struct SpriteVertex { - float tx; - float ty; -}; - -struct SpriteVertices { - SpriteVertex v1; - SpriteVertex v2; - SpriteVertex v3; - SpriteVertex v4; -}; - -/*! - \qmlclass SpriteImage QQuickSpriteImage - \inqmlmodule QtQuick 2 - \inherits Item - \brief The SpriteImage element draws a sprite animation - -*/ -/*! - \qmlproperty bool QtQuick2::SpriteImage::running - - Whether the sprite is animating or not. - - Default is true -*/ -/*! - \qmlproperty bool QtQuick2::SpriteImage::interpolate - - If true, interpolation will occur between sprite frames to make the - animation appear smoother. - - Default is true. -*/ -/*! - \qmlproperty string QtQuick2::SpriteImage::goalSprite - - The name of the Sprite which is currently animating. -*/ -/*! - \qmlproperty string QtQuick2::SpriteImage::goalSprite - - The name of the Sprite which the animation should move to. - - Sprite states have defined durations and transitions between them, setting goalState - will cause it to disregard any path weightings (including 0) and head down the path - which will reach the goalState quickest (fewest animations). It will pass through - intermediate states on that path, and animate them for their duration. - - If it is possible to return to the goalState from the starting point of the goalState - it will continue to do so until goalState is set to "" or an unreachable state. -*/ -/*! \qmlmethod void QtQuick2::SpriteImage::jumpTo(string sprite) - - This function causes the sprite to jump to the specified state immediately, intermediate - states are not played. -*/ -/*! - \qmlproperty list QtQuick2::SpriteImage::sprites - - The sprite or sprites to draw. Sprites will be scaled to the size of this element. -*/ - -//TODO: Implicitly size element to size of first sprite? -QQuickSpriteImage::QQuickSpriteImage(QQuickItem *parent) : - QQuickItem(parent) - , m_node(0) - , m_material(0) - , m_spriteEngine(0) - , m_curFrame(0) - , m_pleaseReset(false) - , m_running(true) - , m_interpolate(true) - , m_curStateIdx(0) -{ - setFlag(ItemHasContents); - connect(this, SIGNAL(runningChanged(bool)), - this, SLOT(update())); -} - -void QQuickSpriteImage::jumpTo(const QString &sprite) -{ - if (!m_spriteEngine) - return; - m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite), 0, true); -} - -void QQuickSpriteImage::setGoalSprite(const QString &sprite) -{ - if (m_goalState != sprite){ - m_goalState = sprite; - emit goalSpriteChanged(sprite); - m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite)); - } -} - -QDeclarativeListProperty QQuickSpriteImage::sprites() -{ - return QDeclarativeListProperty(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); -} - -void QQuickSpriteImage::createEngine() -{ - //TODO: delay until component complete - if (m_spriteEngine) - delete m_spriteEngine; - if (m_sprites.count()) - m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); - else - m_spriteEngine = 0; - reset(); -} - -static QSGGeometry::Attribute SpriteImage_Attributes[] = { - QSGGeometry::Attribute::create(0, 2, GL_FLOAT), // tex -}; - -static QSGGeometry::AttributeSet SpriteImage_AttributeSet = -{ - 1, // Attribute Count - 2 * sizeof(float), - SpriteImage_Attributes -}; - -QSGGeometryNode* QQuickSpriteImage::buildNode() -{ - if (!m_spriteEngine) { - qmlInfo(this) << "No sprite engine..."; - return 0; - } else if (m_spriteEngine->status() == QDeclarativePixmap::Null) { - m_spriteEngine->startAssemblingImage(); - update();//Schedule another update, where we will check again - return 0; - } else if (m_spriteEngine->status() == QDeclarativePixmap::Loading) { - update();//Schedule another update, where we will check again - return 0; - } - - m_material = new QQuickSpriteImageMaterial(); - - QImage image = m_spriteEngine->assembledImage(); - if (image.isNull()) - return 0; - m_sheetSize = QSizeF(image.size()); - m_material->texture = canvas()->createTextureFromImage(image); - m_material->texture->setFiltering(QSGTexture::Linear); - m_spriteEngine->start(0); - m_material->animT = 0; - m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); - m_material->animX2 = m_material->animX1; - m_material->animY2 = m_material->animY1; - m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - m_material->elementWidth = width(); - m_material->elementHeight = height(); - m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); - emit currentSpriteChanged(m_curState); - - int vCount = 4; - int iCount = 6; - QSGGeometry *g = new QSGGeometry(SpriteImage_AttributeSet, vCount, iCount); - g->setDrawingMode(GL_TRIANGLES); - - SpriteVertices *p = (SpriteVertices *) g->vertexData(); - - p->v1.tx = 0; - p->v1.ty = 0; - - p->v2.tx = 1.0; - p->v2.ty = 0; - - p->v3.tx = 0; - p->v3.ty = 1.0; - - p->v4.tx = 1.0; - p->v4.ty = 1.0; - - quint16 *indices = g->indexDataAsUShort(); - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 1; - indices[4] = 3; - indices[5] = 2; - - - m_timestamp.start(); - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); - m_node->setMaterial(m_material); - m_node->setFlag(QSGGeometryNode::OwnsMaterial); - return m_node; -} - -void QQuickSpriteImage::reset() -{ - m_pleaseReset = true; -} - -QSGNode *QQuickSpriteImage::updatePaintNode(QSGNode *, UpdatePaintNodeData *) -{ - if (m_pleaseReset) { - delete m_node; - - m_node = 0; - m_material = 0; - m_pleaseReset = false; - } - - prepareNextFrame(); - - if (m_running) { - update(); - if (m_node) - m_node->markDirty(QSGNode::DirtyMaterial); - } - - return m_node; -} - -void QQuickSpriteImage::prepareNextFrame() -{ - if (m_node == 0) - m_node = buildNode(); - if (m_node == 0) //error creating node - return; - - uint timeInt = m_timestamp.elapsed(); - qreal time = timeInt / 1000.; - m_material->elementHeight = height(); - m_material->elementWidth = width(); - - //Advance State - m_spriteEngine->updateSprites(timeInt); - if (m_curStateIdx != m_spriteEngine->curState()) { - m_curStateIdx = m_spriteEngine->curState(); - m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); - emit currentSpriteChanged(m_curState); - m_curFrame= -1; - } - - //Advance Sprite - qreal animT = m_spriteEngine->spriteStart()/1000.0; - qreal frameCount = m_spriteEngine->spriteFrames(); - qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount; - double frameAt; - qreal progress; - if (frameDuration > 0) { - qreal frame = (time - animT)/(frameDuration / 1000.0); - frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation - progress = modf(frame,&frameAt); - } else { - m_curFrame++; - if (m_curFrame >= frameCount){ - m_curFrame = 0; - m_spriteEngine->advance(); - } - frameAt = m_curFrame; - progress = 0; - } - if (m_spriteEngine->sprite()->reverse()) - frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt; - qreal y = m_spriteEngine->spriteY() / m_sheetSize.height(); - qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); - qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - x1 += frameAt * w; - qreal x2 = x1; - if (frameAt < (frameCount-1)) - x2 += w; - - m_material->animX1 = x1; - m_material->animY1 = y; - m_material->animX2 = x2; - m_material->animY2 = y; - m_material->animW = w; - m_material->animH = h; - m_material->animT = m_interpolate ? progress : 0.0; -} - -QT_END_NAMESPACE diff --git a/src/quick/items/qquickspriteimage_p.h b/src/quick/items/qquickspriteimage_p.h deleted file mode 100644 index 8017263bb1..0000000000 --- a/src/quick/items/qquickspriteimage_p.h +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the Declarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKSPRITEIMAGE_P_H -#define QQUICKSPRITEIMAGE_P_H - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QSGContext; -class QQuickSprite; -class QQuickSpriteEngine; -class QSGGeometryNode; -class QQuickSpriteImageMaterial; -class Q_AUTOTEST_EXPORT QQuickSpriteImage : public QQuickItem -{ - Q_OBJECT - Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) - Q_PROPERTY(bool interpolate READ interpolate WRITE setInterpolate NOTIFY interpolateChanged) - Q_PROPERTY(QString goalSprite READ goalSprite WRITE setGoalSprite NOTIFY goalSpriteChanged) - Q_PROPERTY(QString currentSprite READ currentSprite NOTIFY currentSpriteChanged) - //###try to share similar spriteEngines for less overhead? - Q_PROPERTY(QDeclarativeListProperty sprites READ sprites) - Q_CLASSINFO("DefaultProperty", "sprites") - -public: - explicit QQuickSpriteImage(QQuickItem *parent = 0); - - QDeclarativeListProperty sprites(); - - bool running() const - { - return m_running; - } - - bool interpolate() const - { - return m_interpolate; - } - - QString goalSprite() const - { - return m_goalState; - } - - QString currentSprite() const - { - return m_curState; - } - -signals: - - void runningChanged(bool arg); - void interpolateChanged(bool arg); - void goalSpriteChanged(QString arg); - void currentSpriteChanged(QString arg); - -public slots: - - void jumpTo(const QString &sprite); - void setGoalSprite(const QString &sprite); - - void setRunning(bool arg) - { - if (m_running != arg) { - m_running = arg; - emit runningChanged(arg); - } - } - - void setInterpolate(bool arg) - { - if (m_interpolate != arg) { - m_interpolate = arg; - emit interpolateChanged(arg); - } - } - -private slots: - void createEngine(); -protected: - void reset(); - QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); -private: - void prepareNextFrame(); - QSGGeometryNode* buildNode(); - QSGGeometryNode *m_node; - QQuickSpriteImageMaterial *m_material; - QList m_sprites; - QQuickSpriteEngine* m_spriteEngine; - QTime m_timestamp; - int m_curFrame; - bool m_pleaseReset; - bool m_running; - bool m_interpolate; - QString m_goalState; - QString m_curState; - int m_curStateIdx; - QSizeF m_sheetSize; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QQUICKSPRITEIMAGE_P_H diff --git a/src/quick/items/qquickspritesequence.cpp b/src/quick/items/qquickspritesequence.cpp new file mode 100644 index 0000000000..a3a8a6ee8c --- /dev/null +++ b/src/quick/items/qquickspritesequence.cpp @@ -0,0 +1,482 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickspritesequence_p.h" +#include "qquicksprite_p.h" +#include "qquickspriteengine_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char vertexShaderCode[] = + "attribute highp vec2 vTex;\n" + "uniform highp vec3 animData;// w,h(premultiplied of anim), interpolation progress\n" + "uniform highp vec4 animPos;//x,y, x,y (two frames for interpolation)\n" + "uniform highp vec2 size;//w,h of element\n" + "\n" + "uniform highp mat4 qt_Matrix;\n" + "\n" + "varying highp vec4 fTexS;\n" + "varying lowp float progress;\n" + "\n" + "\n" + "void main() {\n" + " progress = animData.z;\n" + " //Calculate frame location in texture\n" + " fTexS.xy = animPos.xy + vTex.xy * animData.xy;\n" + " //Next frame is also passed, for interpolation\n" + " fTexS.zw = animPos.zw + vTex.xy * animData.xy;\n" + "\n" + " gl_Position = qt_Matrix * vec4(size.x * vTex.x, size.y * vTex.y, 0, 1);\n" + "}\n"; + +static const char fragmentShaderCode[] = + "uniform sampler2D texture;\n" + "uniform lowp float qt_Opacity;\n" + "\n" + "varying highp vec4 fTexS;\n" + "varying lowp float progress;\n" + "\n" + "void main() {\n" + " gl_FragColor = mix(texture2D(texture, fTexS.xy), texture2D(texture, fTexS.zw), progress) * qt_Opacity;\n" + "}\n"; + +class QQuickSpriteSequenceMaterial : public QSGMaterial +{ +public: + QQuickSpriteSequenceMaterial(); + ~QQuickSpriteSequenceMaterial(); + virtual QSGMaterialType *type() const { static QSGMaterialType type; return &type; } + virtual QSGMaterialShader *createShader() const; + virtual int compare(const QSGMaterial *other) const + { + return this - static_cast(other); + } + + QSGTexture *texture; + + float animT; + float animX1; + float animY1; + float animX2; + float animY2; + float animW; + float animH; + float elementWidth; + float elementHeight; +}; + +QQuickSpriteSequenceMaterial::QQuickSpriteSequenceMaterial() + : animT(0.0f) + , animX1(0.0f) + , animY1(0.0f) + , animX2(0.0f) + , animY2(0.0f) + , animW(1.0f) + , animH(1.0f) + , elementWidth(1.0f) + , elementHeight(1.0f) +{ + setFlag(Blending, true); +} + +QQuickSpriteSequenceMaterial::~QQuickSpriteSequenceMaterial() +{ + delete texture; +} + +class SpriteSequenceMaterialData : public QSGMaterialShader +{ +public: + SpriteSequenceMaterialData(const char * /* vertexFile */ = 0, const char * /* fragmentFile */ = 0) + { + } + + void deactivate() { + QSGMaterialShader::deactivate(); + + for (int i=0; i<8; ++i) { + program()->setAttributeArray(i, GL_FLOAT, chunkOfBytes, 1, 0); + } + } + + virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *) + { + QQuickSpriteSequenceMaterial *m = static_cast(newEffect); + m->texture->bind(); + + program()->setUniformValue(m_opacity_id, state.opacity()); + program()->setUniformValue(m_animData_id, m->animW, m->animH, m->animT); + program()->setUniformValue(m_animPos_id, m->animX1, m->animY1, m->animX2, m->animY2); + program()->setUniformValue(m_size_id, m->elementWidth, m->elementHeight); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, state.combinedMatrix()); + } + + virtual void initialize() { + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_animData_id = program()->uniformLocation("animData"); + m_animPos_id = program()->uniformLocation("animPos"); + m_size_id = program()->uniformLocation("size"); + } + + virtual const char *vertexShader() const { return vertexShaderCode; } + virtual const char *fragmentShader() const { return fragmentShaderCode; } + + virtual char const *const *attributeNames() const { + static const char *attr[] = { + "vTex", + 0 + }; + return attr; + } + + int m_matrix_id; + int m_opacity_id; + int m_animData_id; + int m_animPos_id; + int m_size_id; + + static float chunkOfBytes[1024]; +}; + +float SpriteSequenceMaterialData::chunkOfBytes[1024]; + +QSGMaterialShader *QQuickSpriteSequenceMaterial::createShader() const +{ + return new SpriteSequenceMaterialData; +} + +struct SpriteVertex { + float tx; + float ty; +}; + +struct SpriteVertices { + SpriteVertex v1; + SpriteVertex v2; + SpriteVertex v3; + SpriteVertex v4; +}; + +/*! + \qmlclass SpriteSequence QQuickSpriteSequence + \inqmlmodule QtQuick 2 + \inherits Item + \brief The SpriteSequence element draws a sprite animation + +*/ +/*! + \qmlproperty bool QtQuick2::SpriteSequence::running + + Whether the sprite is animating or not. + + Default is true +*/ +/*! + \qmlproperty bool QtQuick2::SpriteSequence::interpolate + + If true, interpolation will occur between sprite frames to make the + animation appear smoother. + + Default is true. +*/ +/*! + \qmlproperty string QtQuick2::SpriteSequence::goalSprite + + The name of the Sprite which is currently animating. +*/ +/*! + \qmlproperty string QtQuick2::SpriteSequence::goalSprite + + The name of the Sprite which the animation should move to. + + Sprite states have defined durations and transitions between them, setting goalState + will cause it to disregard any path weightings (including 0) and head down the path + which will reach the goalState quickest (fewest animations). It will pass through + intermediate states on that path, and animate them for their duration. + + If it is possible to return to the goalState from the starting point of the goalState + it will continue to do so until goalState is set to "" or an unreachable state. +*/ +/*! \qmlmethod void QtQuick2::SpriteSequence::jumpTo(string sprite) + + This function causes the sprite to jump to the specified state immediately, intermediate + states are not played. +*/ +/*! + \qmlproperty list QtQuick2::SpriteSequence::sprites + + The sprite or sprites to draw. Sprites will be scaled to the size of this element. +*/ + +//TODO: Implicitly size element to size of first sprite? +QQuickSpriteSequence::QQuickSpriteSequence(QQuickItem *parent) : + QQuickItem(parent) + , m_node(0) + , m_material(0) + , m_spriteEngine(0) + , m_curFrame(0) + , m_pleaseReset(false) + , m_running(true) + , m_interpolate(true) + , m_curStateIdx(0) +{ + setFlag(ItemHasContents); + connect(this, SIGNAL(runningChanged(bool)), + this, SLOT(update())); +} + +void QQuickSpriteSequence::jumpTo(const QString &sprite) +{ + if (!m_spriteEngine) + return; + m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite), 0, true); +} + +void QQuickSpriteSequence::setGoalSprite(const QString &sprite) +{ + if (m_goalState != sprite){ + m_goalState = sprite; + emit goalSpriteChanged(sprite); + m_spriteEngine->setGoal(m_spriteEngine->stateIndex(sprite)); + } +} + +QDeclarativeListProperty QQuickSpriteSequence::sprites() +{ + return QDeclarativeListProperty(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); +} + +void QQuickSpriteSequence::createEngine() +{ + //TODO: delay until component complete + if (m_spriteEngine) + delete m_spriteEngine; + if (m_sprites.count()) + m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); + else + m_spriteEngine = 0; + reset(); +} + +static QSGGeometry::Attribute SpriteSequence_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, GL_FLOAT), // tex +}; + +static QSGGeometry::AttributeSet SpriteSequence_AttributeSet = +{ + 1, // Attribute Count + 2 * sizeof(float), + SpriteSequence_Attributes +}; + +QSGGeometryNode* QQuickSpriteSequence::buildNode() +{ + if (!m_spriteEngine) { + qmlInfo(this) << "No sprite engine..."; + return 0; + } else if (m_spriteEngine->status() == QDeclarativePixmap::Null) { + m_spriteEngine->startAssemblingImage(); + update();//Schedule another update, where we will check again + return 0; + } else if (m_spriteEngine->status() == QDeclarativePixmap::Loading) { + update();//Schedule another update, where we will check again + return 0; + } + + m_material = new QQuickSpriteSequenceMaterial(); + + QImage image = m_spriteEngine->assembledImage(); + if (image.isNull()) + return 0; + m_sheetSize = QSizeF(image.size()); + m_material->texture = canvas()->createTextureFromImage(image); + m_material->texture->setFiltering(QSGTexture::Linear); + m_spriteEngine->start(0); + m_material->animT = 0; + m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + m_material->animX2 = m_material->animX1; + m_material->animY2 = m_material->animY1; + m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + m_material->elementWidth = width(); + m_material->elementHeight = height(); + m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); + emit currentSpriteChanged(m_curState); + + int vCount = 4; + int iCount = 6; + QSGGeometry *g = new QSGGeometry(SpriteSequence_AttributeSet, vCount, iCount); + g->setDrawingMode(GL_TRIANGLES); + + SpriteVertices *p = (SpriteVertices *) g->vertexData(); + + p->v1.tx = 0; + p->v1.ty = 0; + + p->v2.tx = 1.0; + p->v2.ty = 0; + + p->v3.tx = 0; + p->v3.ty = 1.0; + + p->v4.tx = 1.0; + p->v4.ty = 1.0; + + quint16 *indices = g->indexDataAsUShort(); + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + indices[3] = 1; + indices[4] = 3; + indices[5] = 2; + + + m_timestamp.start(); + m_node = new QSGGeometryNode(); + m_node->setGeometry(g); + m_node->setMaterial(m_material); + m_node->setFlag(QSGGeometryNode::OwnsMaterial); + return m_node; +} + +void QQuickSpriteSequence::reset() +{ + m_pleaseReset = true; +} + +QSGNode *QQuickSpriteSequence::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +{ + if (m_pleaseReset) { + delete m_node; + + m_node = 0; + m_material = 0; + m_pleaseReset = false; + } + + prepareNextFrame(); + + if (m_running) { + update(); + if (m_node) + m_node->markDirty(QSGNode::DirtyMaterial); + } + + return m_node; +} + +void QQuickSpriteSequence::prepareNextFrame() +{ + if (m_node == 0) + m_node = buildNode(); + if (m_node == 0) //error creating node + return; + + uint timeInt = m_timestamp.elapsed(); + qreal time = timeInt / 1000.; + m_material->elementHeight = height(); + m_material->elementWidth = width(); + + //Advance State + m_spriteEngine->updateSprites(timeInt); + if (m_curStateIdx != m_spriteEngine->curState()) { + m_curStateIdx = m_spriteEngine->curState(); + m_curState = m_spriteEngine->state(m_spriteEngine->curState())->name(); + emit currentSpriteChanged(m_curState); + m_curFrame= -1; + } + + //Advance Sprite + qreal animT = m_spriteEngine->spriteStart()/1000.0; + qreal frameCount = m_spriteEngine->spriteFrames(); + qreal frameDuration = m_spriteEngine->spriteDuration()/frameCount; + double frameAt; + qreal progress; + if (frameDuration > 0) { + qreal frame = (time - animT)/(frameDuration / 1000.0); + frame = qBound(qreal(0.0), frame, frameCount - qreal(1.0));//Stop at count-1 frames until we have between anim interpolation + progress = modf(frame,&frameAt); + } else { + m_curFrame++; + if (m_curFrame >= frameCount){ + m_curFrame = 0; + m_spriteEngine->advance(); + } + frameAt = m_curFrame; + progress = 0; + } + if (m_spriteEngine->sprite()->reverse()) + frameAt = (m_spriteEngine->spriteFrames() - 1) - frameAt; + qreal y = m_spriteEngine->spriteY() / m_sheetSize.height(); + qreal w = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + qreal h = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + qreal x1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + x1 += frameAt * w; + qreal x2 = x1; + if (frameAt < (frameCount-1)) + x2 += w; + + m_material->animX1 = x1; + m_material->animY1 = y; + m_material->animX2 = x2; + m_material->animY2 = y; + m_material->animW = w; + m_material->animH = h; + m_material->animT = m_interpolate ? progress : 0.0; +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickspritesequence_p.h b/src/quick/items/qquickspritesequence_p.h new file mode 100644 index 0000000000..8a95594f61 --- /dev/null +++ b/src/quick/items/qquickspritesequence_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Declarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSPRITESEQUENCE_P_H +#define QQUICKSPRITESEQUENCE_P_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QSGContext; +class QQuickSprite; +class QQuickSpriteEngine; +class QSGGeometryNode; +class QQuickSpriteSequenceMaterial; +class Q_AUTOTEST_EXPORT QQuickSpriteSequence : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) + Q_PROPERTY(bool interpolate READ interpolate WRITE setInterpolate NOTIFY interpolateChanged) + Q_PROPERTY(QString goalSprite READ goalSprite WRITE setGoalSprite NOTIFY goalSpriteChanged) + Q_PROPERTY(QString currentSprite READ currentSprite NOTIFY currentSpriteChanged) + //###try to share similar spriteEngines for less overhead? + Q_PROPERTY(QDeclarativeListProperty sprites READ sprites) + Q_CLASSINFO("DefaultProperty", "sprites") + +public: + explicit QQuickSpriteSequence(QQuickItem *parent = 0); + + QDeclarativeListProperty sprites(); + + bool running() const + { + return m_running; + } + + bool interpolate() const + { + return m_interpolate; + } + + QString goalSprite() const + { + return m_goalState; + } + + QString currentSprite() const + { + return m_curState; + } + +signals: + + void runningChanged(bool arg); + void interpolateChanged(bool arg); + void goalSpriteChanged(QString arg); + void currentSpriteChanged(QString arg); + +public slots: + + void jumpTo(const QString &sprite); + void setGoalSprite(const QString &sprite); + + void setRunning(bool arg) + { + if (m_running != arg) { + m_running = arg; + emit runningChanged(arg); + } + } + + void setInterpolate(bool arg) + { + if (m_interpolate != arg) { + m_interpolate = arg; + emit interpolateChanged(arg); + } + } + +private slots: + void createEngine(); +protected: + void reset(); + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); +private: + void prepareNextFrame(); + QSGGeometryNode* buildNode(); + QSGGeometryNode *m_node; + QQuickSpriteSequenceMaterial *m_material; + QList m_sprites; + QQuickSpriteEngine* m_spriteEngine; + QTime m_timestamp; + int m_curFrame; + bool m_pleaseReset; + bool m_running; + bool m_interpolate; + QString m_goalState; + QString m_curState; + int m_curStateIdx; + QSizeF m_sheetSize; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QQUICKSPRITESEQUENCE_P_H -- cgit v1.2.3 From 328c100ab3fc4d5ddccb0d19af9d7e87bd849f0b Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Tue, 21 Feb 2012 14:44:21 +1000 Subject: Separate view transition functionality into new file Move most of the view transition functionality from qquickitemview* into qquickitemviewtransition*. - Move QQuickViewTransitionAttached - Move QQuickItemViewTransitionManager, rename to QQuickItemViewTransitionJob - Move FxViewItem transition-specific features into new QQuickViewItem - Move transition-specific functions like transitionNextReposition() and canTransition() into QQuickItemViewTransitioner which holds all the transition objects now Also mention in docs that there's no defined order for choosing between multiple matching displaced transitions. Change-Id: I8701c0d40d2af152c5d432a4c8de646854c76ea2 Reviewed-by: Martin Jones --- src/quick/items/items.pri | 2 + src/quick/items/qquickgridview.cpp | 42 +- src/quick/items/qquickitemsmodule.cpp | 1 + src/quick/items/qquickitemview.cpp | 890 ++++----------------------- src/quick/items/qquickitemview_p.h | 44 -- src/quick/items/qquickitemview_p_p.h | 88 +-- src/quick/items/qquickitemviewtransition.cpp | 770 +++++++++++++++++++++++ src/quick/items/qquickitemviewtransition_p.h | 201 ++++++ src/quick/items/qquicklistview.cpp | 42 +- 9 files changed, 1159 insertions(+), 921 deletions(-) create mode 100644 src/quick/items/qquickitemviewtransition.cpp create mode 100644 src/quick/items/qquickitemviewtransition_p.h (limited to 'src/quick/items') diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index 21bf7cc8c1..54220434b4 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -72,6 +72,7 @@ HEADERS += \ $$PWD/qquickmultipointtoucharea_p.h \ $$PWD/qquickitemview_p.h \ $$PWD/qquickitemview_p_p.h \ + $$PWD/qquickitemviewtransition_p.h \ $$PWD/qquickscreen_p.h \ $$PWD/qquickwindowmodule_p.h \ $$PWD/qquickwindowmanager_p.h @@ -124,6 +125,7 @@ SOURCES += \ $$PWD/qquickdroparea.cpp \ $$PWD/qquickmultipointtoucharea.cpp \ $$PWD/qquickitemview.cpp \ + $$PWD/qquickitemviewtransition.cpp \ $$PWD/qquickwindowmodule.cpp \ $$PWD/qquickscreen.cpp \ $$PWD/qquickwindowmanager.cpp diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index a7e0af487f..fbce0af0c3 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -127,9 +127,6 @@ public: return (x >= itemX() && x < itemX() + view->cellWidth() && y >= itemY() && y < itemY() + view->cellHeight()); } - QQuickItemView *itemView() const { - return view; - } QQuickGridView *view; @@ -485,7 +482,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d #endif if (!(item = static_cast(createItem(modelIndex, doBuffer)))) break; - if (!canTransition(FxViewItemTransitionManager::PopulateTransition, true)) // pos will be set by layoutVisibleItems() + if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(colPos, rowPos); item->item->setVisible(!doBuffer); visibleItems.append(item); @@ -523,7 +520,7 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d if (!(item = static_cast(createItem(visibleIndex-1, doBuffer)))) break; --visibleIndex; - if (!canTransition(FxViewItemTransitionManager::PopulateTransition, true)) // pos will be set by layoutVisibleItems() + if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(colPos, rowPos); item->item->setVisible(!doBuffer); visibleItems.prepend(item); @@ -1674,6 +1671,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) the new item that has been added to the view; to animate the added items, set the \l add property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1737,6 +1738,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) the items that are the actual subjects of the move operation; to animate the moved items, set the \l move property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1804,6 +1809,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) the item that has actually been removed from the view; to animate the removed items, set the \l remove property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2112,10 +2121,12 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In FxViewItem *item = visibleItems.at(i); if (item->index != -1 && item->index >= modelIndex) { item->index += count; - if (change.isMove()) - transitionNextReposition(item, FxViewItemTransitionManager::MoveTransition, false); - else - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, false); + if (transitioner) { + if (change.isMove()) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, false); + else + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, false); + } } } @@ -2146,7 +2157,8 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In insertResult->changedFirstItem = true; if (!change.isMove()) { addedItems->append(item); - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, true); + if (transitioner) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true); } insertResult->sizeChangesBeforeVisiblePos += rowSize(); } @@ -2179,11 +2191,12 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In if (change.isMove()) { // we know this is a move target, since move displaced items that are // shuffled into view due to a move would be added in refill() - if (canTransition(FxViewItemTransitionManager::MoveTransition, true) && newItem) + if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)) movingIntoView->append(MovedItem(item, change.moveKey(item->index))); } else { addedItems->append(item); - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, true); + if (transitioner) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true); } insertResult->sizeChangesAfterVisiblePos += rowSize(); @@ -2204,6 +2217,9 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex, const ChangeResult &insertionResult, const ChangeResult &removalResult) { + if (!transitioner) + return; + int markerItemIndex = -1; for (int i=0; iindex == afterModelIndex) { @@ -2231,7 +2247,7 @@ void QQuickGridViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex qreal origColPos = gridItem->rowPos(); int indexDiff = gridItem->index - countItemsRemoved; gridItem->setPosition((indexDiff % columns) * colSize(), (indexDiff / columns) * rowSize()); - transitionNextReposition(gridItem, FxViewItemTransitionManager::RemoveTransition, false); + transitioner->transitionNextReposition(gridItem, QQuickItemViewTransitioner::RemoveTransition, false); gridItem->setPosition(origRowPos, origColPos); } } diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index b9e401a231..f50237427b 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -61,6 +61,7 @@ #include "qquickvisualdatamodel_p.h" #include "qquickgridview_p.h" #include "qquickpathview_p.h" +#include "qquickitemviewtransition_p.h" #include #include #include "qquickpositioners_p.h" diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index d5ce567590..481a0d4360 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -46,21 +46,12 @@ QT_BEGIN_NAMESPACE FxViewItem::FxViewItem(QQuickItem *i, bool own) - : item(i), ownItem(own), releaseAfterTransition(false) - , isTransitionTarget(false) - , nextTransitionToSet(false) - , index(-1) - , transition(0) - , nextTransitionType(FxViewItemTransitionManager::NoTransition) + : QQuickViewItem(i), ownItem(own), releaseAfterTransition(false) { } FxViewItem::~FxViewItem() { - if (transition) - transition->m_item = 0; - delete transition; - if (ownItem && item) { item->setParentItem(0); item->deleteLater(); @@ -68,273 +59,6 @@ FxViewItem::~FxViewItem() } } -qreal FxViewItem::itemX() const -{ - if (nextTransitionType != FxViewItemTransitionManager::NoTransition) - return nextTransitionToSet ? nextTransitionTo.x() : item->x(); - else if (transition && transition->isActive()) - return transition->m_toPos.x(); - else - return item->x(); -} - -qreal FxViewItem::itemY() const -{ - // If item is transitioning to some pos, return that dest pos. - // If item was redirected to some new pos before the current transition finished, - // return that new pos. - if (nextTransitionType != FxViewItemTransitionManager::NoTransition) - return nextTransitionToSet ? nextTransitionTo.y() : item->y(); - else if (transition && transition->isActive()) - return transition->m_toPos.y(); - else - return item->y(); -} - -void FxViewItem::setVisible(bool visible) -{ - if (!visible && transitionScheduledOrRunning()) - return; - item->setVisible(visible); -} - -void FxViewItem::setNextTransition(FxViewItemTransitionManager::TransitionType type, bool isTargetItem) -{ - // Don't reset nextTransitionToSet - once it is set, it cannot be changed - // until the animation finishes since the itemX() and itemY() may be used - // to calculate positions for transitions for other items in the view. - nextTransitionType = type; - isTransitionTarget = isTargetItem; -} - -bool FxViewItem::transitionScheduledOrRunning() const -{ - return (transition && transition->isActive()) - || nextTransitionType != FxViewItemTransitionManager::NoTransition; -} - -bool FxViewItem::prepareTransition(const QRectF &viewBounds) -{ - bool doTransition = false; - - switch (nextTransitionType) { - case FxViewItemTransitionManager::NoTransition: - { - return false; - } - case FxViewItemTransitionManager::PopulateTransition: - { - return true; - } - case FxViewItemTransitionManager::AddTransition: - case FxViewItemTransitionManager::RemoveTransition: - // For Add targets, do transition if item is moving into visible area - // For Remove targets, do transition if item is currently in visible area - if (isTransitionTarget) { - doTransition = (nextTransitionType == FxViewItemTransitionManager::AddTransition) - ? viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())) - : viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())); - if (!doTransition) - item->setPos(nextTransitionTo); - } else { - if (viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) - || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()))) { - doTransition = (nextTransitionTo != item->pos()); - } else { - item->setPos(nextTransitionTo); - } - } - break; - case FxViewItemTransitionManager::MoveTransition: - // do transition if moving from or into visible area - if (nextTransitionTo != item->pos()) { - doTransition = viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) - || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())); - if (!doTransition) - item->setPos(nextTransitionTo); - } - break; - } - - if (!doTransition) - resetTransitionData(); - return doTransition; -} - -void FxViewItem::startTransition() -{ - if (nextTransitionType == FxViewItemTransitionManager::NoTransition) - return; - - if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) { - delete transition; - transition = new FxViewItemTransitionManager; - } - - // if item is not already moving somewhere, set it to not move anywhere - // so that removed items do not move to the default (0,0) - if (!nextTransitionToSet) - moveTo(item->pos()); - - transition->startTransition(this, nextTransitionType, nextTransitionTo, isTransitionTarget); - nextTransitionType = FxViewItemTransitionManager::NoTransition; -} - -void FxViewItem::stopTransition() -{ - if (transition) { - transition->cancel(); - delete transition; - transition = 0; - } - resetTransitionData(); - finishedTransition(); -} - -void FxViewItem::finishedTransition() -{ - nextTransitionToSet = false; - nextTransitionTo = QPointF(); - - if (releaseAfterTransition) { - QQuickItemViewPrivate *vp = static_cast(QObjectPrivate::get(itemView())); - vp->releasePendingTransition.removeOne(this); - vp->releaseItem(this); - } -} - -void FxViewItem::resetTransitionData() -{ - nextTransitionType = FxViewItemTransitionManager::NoTransition; - isTransitionTarget = false; - nextTransitionTo = QPointF(); - nextTransitionToSet = false; -} - -bool FxViewItem::isPendingRemoval() const -{ - if (nextTransitionType == FxViewItemTransitionManager::RemoveTransition) - return isTransitionTarget; - if (transition && transition->isActive() && transition->m_type == FxViewItemTransitionManager::RemoveTransition) - return transition->m_isTarget; - return false; -} - -void FxViewItem::moveTo(const QPointF &pos) -{ - if (transitionScheduledOrRunning()) { - nextTransitionTo = pos; - nextTransitionToSet = true; - } else { - item->setPos(pos); - } -} - - -FxViewItemTransitionManager::FxViewItemTransitionManager() - : m_active(false), m_item(0), m_type(FxViewItemTransitionManager::NoTransition), m_isTarget(false) -{ -} - -FxViewItemTransitionManager::~FxViewItemTransitionManager() -{ -} - -bool FxViewItemTransitionManager::isActive() const -{ - return m_active; -} - -void FxViewItemTransitionManager::startTransition(FxViewItem *item, FxViewItemTransitionManager::TransitionType type, const QPointF &to, bool isTargetItem) -{ - if (!item) { - qWarning("startTransition(): invalid item"); - return; - } - - QQuickItemViewPrivate *vp = static_cast(QObjectPrivate::get(item->itemView())); - - QDeclarativeTransition *trans = 0; - switch (type) { - case NoTransition: - break; - case PopulateTransition: - trans = vp->populateTransition; - break; - case AddTransition: - trans = isTargetItem ? vp->addTransition : vp->addDisplacedTransition; - break; - case MoveTransition: - trans = isTargetItem ? vp->moveTransition : vp->moveDisplacedTransition; - break; - case RemoveTransition: - trans = isTargetItem ? vp->removeTransition : vp->removeDisplacedTransition; - break; - } - - if (!trans) { - qWarning("QQuickItemView: invalid view transition!"); - return; - } - - m_active = true; - m_item = item; - m_toPos = to; - m_type = type; - m_isTarget = isTargetItem; - - QQuickViewTransitionAttached *attached = - static_cast(qmlAttachedPropertiesObject(trans)); - if (attached) { - attached->m_index = item->index; - attached->m_item = item->item; - attached->m_destination = to; - switch (type) { - case NoTransition: - break; - case PopulateTransition: - case AddTransition: - attached->m_targetIndexes = vp->addTransitionIndexes; - attached->m_targetItems = vp->addTransitionTargets; - break; - case MoveTransition: - attached->m_targetIndexes = vp->moveTransitionIndexes; - attached->m_targetItems = vp->moveTransitionTargets; - break; - case RemoveTransition: - attached->m_targetIndexes = vp->removeTransitionIndexes; - attached->m_targetItems = vp->removeTransitionTargets; - break; - } - emit attached->indexChanged(); - emit attached->itemChanged(); - emit attached->destinationChanged(); - emit attached->targetIndexesChanged(); - emit attached->targetItemsChanged(); - } - - QDeclarativeStateOperation::ActionList actions; - actions << QDeclarativeAction(item->item, QLatin1String("x"), QVariant(to.x())); - actions << QDeclarativeAction(item->item, QLatin1String("y"), QVariant(to.y())); - - QDeclarativeTransitionManager::transition(actions, trans, item->item); -} - -void FxViewItemTransitionManager::finished() -{ - QDeclarativeTransitionManager::finished(); - - m_active = false; - - if (m_item) - m_item->finishedTransition(); - m_item = 0; - m_toPos.setX(0); - m_toPos.setY(0); - m_type = NoTransition; - m_isTarget = false; -} - QQuickItemViewChangeSet::QQuickItemViewChangeSet() : active(false) @@ -413,363 +137,6 @@ void QQuickItemViewChangeSet::reset() currentRemoved = false; } - -QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) - : QObject(parent), m_index(-1), m_item(0) -{ -} -/*! - \qmlclass ViewTransition QQuickViewTransitionAttached - \inqmlmodule QtQuick 2 - \ingroup qml-view-elements - \brief The ViewTransition attached property provides details on items under transition in a view. - - With ListView and GridView, it is possible to specify transitions that should be applied whenever - the items in the view change as a result of modifications to the view's model. They both have the - following properties that can be set to the appropriate transitions to be run for various - operations: - - \list - \o \c add and \c addDisplaced - the transitions to run when items are added to the view - \o \c remove and \c removeDisplaced - the transitions to run when items are removed from the view - \o \c move and \c moveDisplaced - the transitions to run when items are moved within the view - (i.e. as a result of a move operation in the model) - \o \c populate - the transition to run when a view is created, or when the model changes - \endlist - - Such view transitions additionally have access to a ViewTransition attached property that - provides details of the items that are under transition and the operation that triggered the - transition. Since view transitions are run once per item, these details can be used to customise - each transition for each individual item. - - The ViewTransition attached property provides the following properties specific to the item to - which the transition is applied: - - \list - \o ViewTransition.item - the item that is under transition - \o ViewTransition.index - the index of this item - \o ViewTransition.destination - the (x,y) point to which this item is moving for the relevant view operation - \endlist - - In addition, ViewTransition provides properties specific to the items which are the target - of the operation that triggered the transition: - - \list - \o ViewTransition.targetIndexes - the indexes of the target items - \o ViewTransition.targetItems - the target items themselves - \endlist - - View transitions can be written without referring to any of the attributes listed - above. These attributes merely provide extra details that are useful for customising view - transitions. - - Following is an introduction to view transitions and the ways in which the ViewTransition - attached property can be used to augment view transitions. - - - \section2 View transitions: a simple example - - Here is a basic example of the use of view transitions. The view below specifies transitions for - the \c add and \c addDisplaced properties, which will be run when items are added to the view: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-basic.qml 0 - - When the space key is pressed, adding an item to the model, the new item will fade in and - increase in scale over 400 milliseconds as it is added to the view. Also, any item that is - displaced by the addition of a new item will animate to its new position in the view over - 400 milliseconds, as specified by the \c addDisplaced transition. - - If five items were inserted in succession at index 0, the effect would be this: - - \image viewtransitions-basic.gif - - Notice that the NumberAnimation objects above do not need to specify a \c target to animate - the appropriate item. Also, the NumberAnimation in the \c addTransition does not need to specify - the \c to value to move the item to its correct position in the view. This is because the view - implicitly sets the \c target and \c to values with the correct item and final item position - values if these properties are not explicitly defined. - - At its simplest, a view transition may just animate an item to its new position following a - view operation, just as the \c addDisplaced transition does above, or animate some item properties, - as in the \c add transition above. Additionally, a view transition may make use of the - ViewTransition attached property to customise animation behavior for different items. Following - are some examples of how this can be achieved. - - - \section2 Using the ViewTransition attached property - - As stated, the various ViewTransition properties provide details specific to the individual item - being transitioned as well as the operation that triggered the transition. In the animation above, - five items are inserted in succession at index 0. When the fifth and final insertion takes place, - adding "Item 4" to the view, the \c add transition is run once (for the inserted item) and the - \c addDisplaced transition is run four times (once for each of the four existing items in the view). - - At this point, if we examined the \c addDisplaced transition that was run for the bottom displaced - item ("Item 0"), the ViewTransition property values provided to this transition would be as follows: - - \table - \header - \o Property - \o Value - \o Explanation - \row - \o ViewTransition.item - \o "Item 0" delegate instance - \o The "Item 0" \l Rectangle object itself - \row - \o ViewTransition.index - \o \c int value of 4 - \o The index of "Item 0" within the model following the add operation - \row - \o ViewTransition.destination - \o \l point value of (0, 120) - \o The position that "Item 0" is moving to - \row - \o ViewTransition.targetIndexes - \o \c int array, just contains the integer "0" (zero) - \o The index of "Item 4", the new item added to the view - \row - \o ViewTransition.targetItems - \o object array, just contains the "Item 4" delegate instance - \o The "Item 4" \l Rectangle object - the new item added to the view - \endtable - - The ViewTransition.targetIndexes and ViewTransition.targetItems lists provide the items and - indexes of all delegate instances that are the targets of the relevant operation. For an add - operation, these are all the items that are added into the view; for a remove, these are all - the items removed from the view, and so on. (Note these lists will only contain references to - items that have been created within the view or its cached items; targets that are not within - the visible area of the view or within the item cache will not be accessible.) - - So, while the ViewTransition.item, ViewTransition.index and ViewTransition.destination values - vary for each individual transition that is run, the ViewTransition.targetIndexes and - ViewTransition.targetItems values are the same for every \c add and \c addDisplaced transition - that is triggered by a particular add operation. - - - \section3 Delaying animations based on index - - Since each view transition is run once for each item affected by the transition, the ViewTransition - properties can be used within a transition to define custom behavior for each item's transition. - For example, the ListView in the previous example could use this information to create a ripple-type - effect on the movement of the displaced items. - - This can be achieved by modifying the \c addDisplaced transition so that it delays the animation of - each displaced item based on the difference between its index (provided by ViewTransition.index) - and the first removed index (provided by ViewTransition.targetIndexes): - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-delayedbyindex.qml 0 - - Each displaced item delays its animation by an additional 100 milliseconds, producing a subtle - ripple-type effect when items are displaced by the add, like this: - - \image viewtransitions-delayedbyindex.gif - - - \section3 Animating items to intermediate positions - - The ViewTransition.item property gives a reference to the item to which the transition is being - applied. This can be used to access any of the item's attributes, custom \c property values, - and so on. - - Below is a modification of the \c addDisplaced transition from the previous example. It adds a - ParallelAnimation with nested NumberAnimation objects that reference ViewTransition.item to access - each item's \c x and \c y values at the start of their transitions. This allows each item to - animate to an intermediate position relative to its starting point for the transition, before - animating to its final position in the view: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-intermediatemove.qml 0 - - Now, a displaced item will first move to a position of (20, 50) relative to its starting - position, and then to its final, correct position in the view: - - \image viewtransitions-intermediatemove.gif - - Since the final NumberAnimation does not specify a \c to value, the view implicitly sets this - value to the item's final position in the view, and so this last animation will move this item - to the correct place. If the transition requires the final position of the item for some calculation, - this is accessible through ViewTransition.destination. - - Instead of using multiple NumberAnimations, you could use a PathAnimation to animate an item over - a curved path. For example, the \c add transition in the previous example could be augmented with - a PathAnimation as follows: to animate newly added items along a path: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-pathanim.qml 0 - - This animates newly added items along a path. Notice that each path is specified relative to - each item's final destination point, so that items inserted at different indexes start their - paths from different positions: - - \image viewtransitions-pathanim.gif - - - \section2 Handling interrupted animations - - A view transition may be interrupted at any time if a different view transition needs to be - applied while the original transition is in progress. For example, say Item A is inserted at index 0 - and undergoes an "add" transition; then, Item B is inserted at index 0 in quick succession before - Item A's transition has finished. Since Item B is inserted before Item A, it will displace Item - A, causing the view to interrupt Item A's "add" transition mid-way and start an "addDisplaced" - transition on Item A instead. - - For simple animations that simply animate an item's movement to its final destination, this - interruption is unlikely to require additional consideration. However, if a transition changes other - properties, this interruption may cause unwanted side effects. Consider the first example on this - page, repeated below for convenience: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-basic.qml 0 - - If multiple items are added in rapid succession, without waiting for a previous transition - to finish, this is the result: - - \image viewtransitions-interruptedbad.gif - - Each newly added item undergoes an \c add transition, but before the transition can finish, - another item is added, displacing the previously added item. Because of this, the \c add - transition on the previously added item is interrupted and an \c addDisplaced transition is - started on the item instead. Due to the interruption, the \c opacity and \c scale animations - have not completed, thus producing items with opacity and scale that are below 1.0. - - To fix this, the \c addDisplaced transition should additionally ensure the item properties are - set to the end values specified in the \c add transition, effectively resetting these values - whenever an item is displaced. In this case, it means setting the item opacity and scale to 1.0: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-interruptedgood.qml 0 - - Now, when an item's \c add transition is interrupted, its opacity and scale are animated to 1.0 - upon displacement, avoiding the erroneous visual effects from before: - - \image viewtransitions-interruptedgood.gif - - The same principle applies to any combination of view transitions. An added item may be moved - before its add transition finishes, or a moved item may be removed before its moved transition - finishes, and so on; so, the rule of thumb is that every transition should handle the same set of - properties. - - - \section2 Restrictions regarding ScriptAction - - When a view transition is initialized, any property bindings that refer to the ViewTransition - attached property are evaluated in preparation for the transition. Due to the nature of the - internal construction of a view transition, the attributes of the ViewTransition attached - property are only valid for the relevant item when the transition is initialized, and may not be - valid when the transition is actually run. - - Therefore, a ScriptAction within a view transition should not refer to the ViewTransition - attached property, as it may not refer to the expected values at the time that the ScriptAction - is actually invoked. Consider the following example: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-scriptactionbad.qml 0 - - When the space key is pressed, three items are moved from index 5 to index 1. For each moved - item, the \c moveTransition sequence presumably animates the item's color to "yellow", then - animates it to its final position, then changes the item color back to "lightsteelblue" using a - ScriptAction. However, when run, the transition does not produce the intended result: - - \image viewtransitions-scriptactionbad.gif - - Only the last moved item is returned to the "lightsteelblue" color; the others remain yellow. This - is because the ScriptAction is not run until after the transition has already been initialized, by - which time the ViewTransition.item value has changed to refer to a different item; the item that - the script had intended to refer to is not the one held by ViewTransition.item at the time the - ScriptAction is actually invoked. - - In this instance, to avoid this issue, the view could set the property using a PropertyAction - instead: - - \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-scriptactiongood.qml 0 - - When the transition is initialized, the PropertyAction \c target will be set to the respective - ViewTransition.item for the transition and will later run with the correct item target as - expected. - */ - -/*! - \qmlattachedproperty list QtQuick2::ViewTransition::index - - This attached property holds the index of the item that is being - transitioned. - - Note that if the item is being moved, this property holds the index that - the item is moving to, not from. -*/ - -/*! - \qmlattachedproperty list QtQuick2::ViewTransition::item - - This attached property holds the the item that is being transitioned. - - \warning This item should not be kept and referred to outside of the transition - as it may become invalid as the view changes. -*/ - -/*! - \qmlattachedproperty list QtQuick2::ViewTransition::destination - - This attached property holds the final destination position for the transitioned - item within the view. - - This property value is a \l point with \c x and \c y properties. -*/ - -/*! - \qmlattachedproperty list QtQuick2::ViewTransition::targetIndexes - - This attached property holds a list of the indexes of the items in view - that are the target of the relevant operation. - - The targets are the items that are the subject of the operation. For - an add operation, these are the items being added; for a remove, these - are the items being removed; for a move, these are the items being - moved. - - For example, if the transition was triggered by an insert operation - that added two items at index 1 and 2, this targetIndexes list would - have the value [1,2]. - - \note The targetIndexes list only contains the indexes of items that are actually - in view, or will be in the view once the relevant operation completes. - - \sa QtQuick2::ViewTransition::targetIndexes -*/ - -/*! - \qmlattachedproperty list QtQuick2::ViewTransition::targetItems - - This attached property holds the list of items in view that are the - target of the relevant operation. - - The targets are the items that are the subject of the operation. For - an add operation, these are the items being added; for a remove, these - are the items being removed; for a move, these are the items being - moved. - - For example, if the transition was triggered by an insert operation - that added two items at index 1 and 2, this targetItems list would - contain these two items. - - \note The targetItems list only contains items that are actually - in view, or will be in the view once the relevant operation completes. - - \warning The objects in this list should not be kept and referred to - outside of the transition as the items may become invalid. The targetItems - are only valid when the Transition is initially created; this also means - they should not be used by ScriptAction objects in the Transition, which are - not evaluated until the transition is run. - - \sa QtQuick2::ViewTransition::targetIndexes -*/ -QDeclarativeListProperty QQuickViewTransitionAttached::targetItems() -{ - return QDeclarativeListProperty(this, m_targetItems); -} - -QQuickViewTransitionAttached *QQuickViewTransitionAttached::qmlAttachedProperties(QObject *obj) -{ - return new QQuickViewTransitionAttached(obj); -} - - //----------------------------------- QQuickItemView::QQuickItemView(QQuickFlickablePrivate &dd, QQuickItem *parent) @@ -868,9 +235,9 @@ void QQuickItemView::setModel(const QVariant &model) } d->updateViewport(); - if (d->populateTransition) { + if (d->transitioner && d->transitioner->populateTransition) { d->forceLayout = true; - d->usePopulateTransition = true; + d->transitioner->setPopulateTransitionEnabled(true); polish(); } } @@ -1229,14 +596,15 @@ void QQuickItemView::setHighlightMoveDuration(int duration) QDeclarativeTransition *QQuickItemView::populateTransition() const { Q_D(const QQuickItemView); - return d->populateTransition; + return d->transitioner ? d->transitioner->populateTransition : 0; } void QQuickItemView::setPopulateTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->populateTransition != transition) { - d->populateTransition = transition; + d->createTransitioner(); + if (d->transitioner->populateTransition != transition) { + d->transitioner->populateTransition = transition; emit populateTransitionChanged(); } } @@ -1244,14 +612,15 @@ void QQuickItemView::setPopulateTransition(QDeclarativeTransition *transition) QDeclarativeTransition *QQuickItemView::addTransition() const { Q_D(const QQuickItemView); - return d->addTransition; + return d->transitioner ? d->transitioner->addTransition : 0; } void QQuickItemView::setAddTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->addTransition != transition) { - d->addTransition = transition; + d->createTransitioner(); + if (d->transitioner->addTransition != transition) { + d->transitioner->addTransition = transition; emit addTransitionChanged(); } } @@ -1259,14 +628,15 @@ void QQuickItemView::setAddTransition(QDeclarativeTransition *transition) QDeclarativeTransition *QQuickItemView::addDisplacedTransition() const { Q_D(const QQuickItemView); - return d->addDisplacedTransition; + return d->transitioner ? d->transitioner->addDisplacedTransition : 0; } void QQuickItemView::setAddDisplacedTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->addDisplacedTransition != transition) { - d->addDisplacedTransition = transition; + d->createTransitioner(); + if (d->transitioner->addDisplacedTransition != transition) { + d->transitioner->addDisplacedTransition = transition; emit addDisplacedTransitionChanged(); } } @@ -1274,14 +644,15 @@ void QQuickItemView::setAddDisplacedTransition(QDeclarativeTransition *transitio QDeclarativeTransition *QQuickItemView::moveTransition() const { Q_D(const QQuickItemView); - return d->moveTransition; + return d->transitioner ? d->transitioner->moveTransition : 0; } void QQuickItemView::setMoveTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->moveTransition != transition) { - d->moveTransition = transition; + d->createTransitioner(); + if (d->transitioner->moveTransition != transition) { + d->transitioner->moveTransition = transition; emit moveTransitionChanged(); } } @@ -1289,14 +660,15 @@ void QQuickItemView::setMoveTransition(QDeclarativeTransition *transition) QDeclarativeTransition *QQuickItemView::moveDisplacedTransition() const { Q_D(const QQuickItemView); - return d->moveDisplacedTransition; + return d->transitioner ? d->transitioner->moveDisplacedTransition : 0; } void QQuickItemView::setMoveDisplacedTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->moveDisplacedTransition != transition) { - d->moveDisplacedTransition = transition; + d->createTransitioner(); + if (d->transitioner->moveDisplacedTransition != transition) { + d->transitioner->moveDisplacedTransition = transition; emit moveDisplacedTransitionChanged(); } } @@ -1304,14 +676,15 @@ void QQuickItemView::setMoveDisplacedTransition(QDeclarativeTransition *transiti QDeclarativeTransition *QQuickItemView::removeTransition() const { Q_D(const QQuickItemView); - return d->removeTransition; + return d->transitioner ? d->transitioner->removeTransition : 0; } void QQuickItemView::setRemoveTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->removeTransition != transition) { - d->removeTransition = transition; + d->createTransitioner(); + if (d->transitioner->removeTransition != transition) { + d->transitioner->removeTransition = transition; emit removeTransitionChanged(); } } @@ -1319,14 +692,15 @@ void QQuickItemView::setRemoveTransition(QDeclarativeTransition *transition) QDeclarativeTransition *QQuickItemView::removeDisplacedTransition() const { Q_D(const QQuickItemView); - return d->removeDisplacedTransition; + return d->transitioner ? d->transitioner->removeDisplacedTransition : 0; } void QQuickItemView::setRemoveDisplacedTransition(QDeclarativeTransition *transition) { Q_D(QQuickItemView); - if (d->removeDisplacedTransition != transition) { - d->removeDisplacedTransition = transition; + d->createTransitioner(); + if (d->transitioner->removeDisplacedTransition != transition) { + d->transitioner->removeDisplacedTransition = transition; emit removeDisplacedTransitionChanged(); } } @@ -1465,64 +839,6 @@ void QQuickItemViewPrivate::applyPendingChanges() layout(); } -bool QQuickItemViewPrivate::canTransition(FxViewItemTransitionManager::TransitionType type, bool asTarget) const -{ - switch (type) { - case FxViewItemTransitionManager::NoTransition: - break; - case FxViewItemTransitionManager::PopulateTransition: - return usePopulateTransition - && populateTransition && populateTransition->enabled(); - case FxViewItemTransitionManager::AddTransition: - if (asTarget) - return addTransition && addTransition->enabled(); - else - return addDisplacedTransition && addDisplacedTransition->enabled(); - case FxViewItemTransitionManager::MoveTransition: - if (asTarget) - return moveTransition && moveTransition->enabled(); - else - return moveDisplacedTransition && moveDisplacedTransition->enabled(); - case FxViewItemTransitionManager::RemoveTransition: - if (asTarget) - return removeTransition && removeTransition->enabled(); - else - return removeDisplacedTransition && removeDisplacedTransition->enabled(); - } - return false; -} - -bool QQuickItemViewPrivate::hasItemTransitions() const -{ - return canTransition(FxViewItemTransitionManager::PopulateTransition, true) - || canTransition(FxViewItemTransitionManager::AddTransition, true) - || canTransition(FxViewItemTransitionManager::AddTransition, false) - || canTransition(FxViewItemTransitionManager::MoveTransition, true) - || canTransition(FxViewItemTransitionManager::MoveTransition, false) - || canTransition(FxViewItemTransitionManager::RemoveTransition, true) - || canTransition(FxViewItemTransitionManager::RemoveTransition, false); -} - -void QQuickItemViewPrivate::transitionNextReposition(FxViewItem *item, FxViewItemTransitionManager::TransitionType type, bool isTarget) -{ - bool matchedTransition = false; - if (type == FxViewItemTransitionManager::AddTransition) { - // don't run add transitions for added items while populating - matchedTransition = !usePopulateTransition && canTransition(type, isTarget); - } else { - matchedTransition = canTransition(type, isTarget); - } - - if (matchedTransition) { - item->setNextTransition(type, isTarget); - } else { - // the requested transition type is not valid, but the item is scheduled/in another - // transition, so cancel it to allow the item to move directly to the correct pos - if (item->transitionScheduledOrRunning()) - item->stopTransition(); - } -} - int QQuickItemViewPrivate::findMoveKeyIndex(QDeclarativeChangeSet::MoveKey key, const QVector &changes) const { for (int i=0; itransition && actualItem->transition->isRunning()) + FxViewItem *actualItem = transitioner ? visibleItem(currentIndex) : 0; + if (actualItem && actualItem->transitionRunning()) disableLayout = true; } updateHighlight(); @@ -1602,7 +918,7 @@ void QQuickItemView::destroyRemoved() it != d->visibleItems.end();) { FxViewItem *item = *it; if (item->index == -1 && item->attached->delayRemove() == false) { - if (d->canTransition(FxViewItemTransitionManager::RemoveTransition, true)) { + if (d->transitioner && d->transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) { // don't remove from visibleItems until next layout() d->runDelayedRemoveTransition = true; QObject::disconnect(item->attached, SIGNAL(delayRemoveChanged()), this, SLOT(destroyRemoved())); @@ -1626,7 +942,8 @@ void QQuickItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r { Q_D(QQuickItemView); if (reset) { - d->usePopulateTransition = true; + if (d->transitioner) + d->transitioner->setPopulateTransitionEnabled(true); d->moveReason = QQuickItemViewPrivate::SetIndex; d->regenerate(); if (d->highlight && d->currentItem) { @@ -1636,7 +953,7 @@ void QQuickItemView::modelUpdated(const QDeclarativeChangeSet &changeSet, bool r } d->moveReason = QQuickItemViewPrivate::Other; emit countChanged(); - if (d->populateTransition) { + if (d->transitioner && d->transitioner->populateTransition) { d->forceLayout = true; polish(); } @@ -1936,7 +1253,8 @@ void QQuickItemView::componentComplete() d->updateFooter(); d->updateViewport(); d->setPosition(d->contentStartOffset()); - d->usePopulateTransition = true; + if (d->transitioner) + d->transitioner->setPopulateTransitionEnabled(true); if (d->isValid()) { d->refill(); @@ -1972,19 +1290,21 @@ QQuickItemViewPrivate::QQuickItemViewPrivate() , highlightRangeStart(0), highlightRangeEnd(0) , highlightMoveDuration(150) , headerComponent(0), header(0), footerComponent(0), footer(0) - , populateTransition(0) - , addTransition(0), addDisplacedTransition(0) - , moveTransition(0), moveDisplacedTransition(0) - , removeTransition(0), removeDisplacedTransition(0) + , transitioner(0) , minExtent(0), maxExtent(0) , ownModel(false), wrap(false) , disableLayout(false), inViewportMoved(false), forceLayout(false), currentIndexCleared(false) , haveHighlightRange(false), autoHighlight(true), highlightRangeStartValid(false), highlightRangeEndValid(false) , fillCacheBuffer(false), inRequest(false), requestedAsync(false) - , usePopulateTransition(false), runDelayedRemoveTransition(false) + , runDelayedRemoveTransition(false) { } +QQuickItemViewPrivate::~QQuickItemViewPrivate() +{ + delete transitioner; +} + bool QQuickItemViewPrivate::isValid() const { return model && model->count() && model->isValid(); @@ -2267,15 +1587,17 @@ void QQuickItemViewPrivate::layout() if (!isValid() && !visibleItems.count()) { clear(); setPosition(contentStartOffset()); - usePopulateTransition = false; + if (transitioner) + transitioner->setPopulateTransitionEnabled(false); return; } - if (runDelayedRemoveTransition && canTransition(FxViewItemTransitionManager::RemoveTransition, false)) { + if (runDelayedRemoveTransition && transitioner + && transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) { // assume that any items moving now are moving due to the remove - if they schedule // a different transition, that will override this one anyway for (int i=0; itransitionNextReposition(visibleItems[i], QQuickItemViewTransitioner::RemoveTransition, false); } ChangeResult insertionPosChanges; @@ -2289,9 +1611,9 @@ void QQuickItemViewPrivate::layout() } forceLayout = false; - if (canTransition(FxViewItemTransitionManager::PopulateTransition, true)) { + if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) { for (int i=0; itransitionNextReposition(visibleItems.at(i), QQuickItemViewTransitioner::PopulateTransition, true); } layoutVisibleItems(); @@ -2310,11 +1632,11 @@ void QQuickItemViewPrivate::layout() updateViewport(); updateUnrequestedPositions(); - if (hasItemTransitions()) { + if (transitioner) { // items added in the last refill() may need to be transitioned in - e.g. a remove // causes items to slide up into view - if (canTransition(FxViewItemTransitionManager::MoveTransition, false) - || canTransition(FxViewItemTransitionManager::RemoveTransition, false)) { + if (transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, false) + || transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, false)) { translateAndTransitionItemsAfter(lastIndexInView, insertionPosChanges, removalPosChanges); } @@ -2324,8 +1646,7 @@ void QQuickItemViewPrivate::layout() for (QList::Iterator it = releasePendingTransition.begin(); it != releasePendingTransition.end(); ) { FxViewItem *item = *it; - if ( (item->transition && item->transition->isActive()) - || prepareNonVisibleItemTransition(item, viewBounds)) { + if (item->transitionRunning() || prepareNonVisibleItemTransition(item, viewBounds)) { ++it; } else { releaseItem(item); @@ -2334,11 +1655,12 @@ void QQuickItemViewPrivate::layout() } for (int i=0; istartTransition(); + visibleItems[i]->startTransition(transitioner); for (int i=0; istartTransition(); + releasePendingTransition[i]->startTransition(transitioner); + transitioner->setPopulateTransitionEnabled(false); } - usePopulateTransition = false; + runDelayedRemoveTransition = false; } @@ -2441,7 +1763,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult // for each item that was moved directly into the view as a result of a move(), // find the index it was moved from in order to set its initial position, so that we // can transition it from this "original" position to its new position in the view - if (canTransition(FxViewItemTransitionManager::MoveTransition, true)) { + if (transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)) { for (int i=0; i= 0) { @@ -2449,7 +1771,7 @@ bool QQuickItemViewPrivate::applyModelChanges(ChangeResult *totalInsertionResult repositionItemAt(movingIntoView[i].item, fromIndex, -totalInsertionResult->sizeChangesAfterVisiblePos); else repositionItemAt(movingIntoView[i].item, fromIndex, totalInsertionResult->sizeChangesAfterVisiblePos); - transitionNextReposition(movingIntoView[i].item, FxViewItemTransitionManager::MoveTransition, true); + transitioner->transitionNextReposition(movingIntoView[i].item, QQuickItemViewTransitioner::MoveTransition, true); } } } @@ -2513,10 +1835,12 @@ bool QQuickItemViewPrivate::applyRemovalChange(const QDeclarativeChangeSet::Remo } else if (item->index >= removal.index + removal.count) { // after removed items item->index -= removal.count; - if (removal.isMove()) - transitionNextReposition(item, FxViewItemTransitionManager::MoveTransition, false); - else - transitionNextReposition(item, FxViewItemTransitionManager::RemoveTransition, false); + if (transitioner) { + if (removal.isMove()) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, false); + else + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::RemoveTransition, false); + } ++it; } else { // removed item @@ -2550,7 +1874,8 @@ void QQuickItemViewPrivate::removeItem(FxViewItem *item, const QDeclarativeChang } if (removal.isMove()) { currentChanges.removedItems.insert(removal.moveKey(item->index), item); - transitionNextReposition(item, FxViewItemTransitionManager::MoveTransition, true); + if (transitioner) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, true); } else { // track item so it is released later currentChanges.removedItems.insertMulti(QDeclarativeChangeSet::MoveKey(), item); @@ -2598,16 +1923,24 @@ void QQuickItemViewPrivate::repositionFirstItem(FxViewItem *prevVisibleItemsFirs } } +void QQuickItemViewPrivate::createTransitioner() +{ + if (!transitioner) { + transitioner = new QQuickItemViewTransitioner; + transitioner->setChangeListener(this); + } +} + void QQuickItemViewPrivate::prepareVisibleItemTransitions() { Q_Q(QQuickItemView); - if (!hasItemTransitions()) + if (!transitioner) return; - addTransitionIndexes.clear(); - addTransitionTargets.clear(); - moveTransitionIndexes.clear(); - moveTransitionTargets.clear(); + transitioner->addTransitionIndexes.clear(); + transitioner->addTransitionTargets.clear(); + transitioner->moveTransitionIndexes.clear(); + transitioner->moveTransitionTargets.clear(); QRectF viewBounds(0, position(), q->width(), q->height()); for (int i=0; iisTransitionTarget) { switch (visibleItems[i]->nextTransitionType) { - case FxViewItemTransitionManager::NoTransition: + case QQuickItemViewTransitioner::NoTransition: break; - case FxViewItemTransitionManager::PopulateTransition: - case FxViewItemTransitionManager::AddTransition: - addTransitionIndexes.append(visibleItems[i]->index); - addTransitionTargets.append(visibleItems[i]->item); + case QQuickItemViewTransitioner::PopulateTransition: + case QQuickItemViewTransitioner::AddTransition: + transitioner->addTransitionIndexes.append(visibleItems[i]->index); + transitioner->addTransitionTargets.append(visibleItems[i]->item); break; - case FxViewItemTransitionManager::MoveTransition: - moveTransitionIndexes.append(visibleItems[i]->index); - moveTransitionTargets.append(visibleItems[i]->item); + case QQuickItemViewTransitioner::MoveTransition: + transitioner->moveTransitionIndexes.append(visibleItems[i]->index); + transitioner->moveTransitionTargets.append(visibleItems[i]->item); break; - case FxViewItemTransitionManager::RemoveTransition: + case QQuickItemViewTransitioner::RemoveTransition: // removed targets won't be in visibleItems, handle these // in prepareNonVisibleItemTransition() break; @@ -2638,10 +1971,13 @@ void QQuickItemViewPrivate::prepareVisibleItemTransitions() void QQuickItemViewPrivate::prepareRemoveTransitions(QHash *removedItems) { - removeTransitionIndexes.clear(); - removeTransitionTargets.clear(); + if (!transitioner) + return; - if (canTransition(FxViewItemTransitionManager::RemoveTransition, true)) { + transitioner->removeTransitionIndexes.clear(); + transitioner->removeTransitionTargets.clear(); + + if (transitioner->canTransition(QQuickItemViewTransitioner::RemoveTransition, true)) { for (QHash::Iterator it = removedItems->begin(); it != removedItems->end(); ) { bool isRemove = it.key().moveId < 0; @@ -2649,7 +1985,7 @@ void QQuickItemViewPrivate::prepareRemoveTransitions(QHashreleaseAfterTransition = true; releasePendingTransition.append(item); - transitionNextReposition(item, FxViewItemTransitionManager::RemoveTransition, true); + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::RemoveTransition, true); it = removedItems->erase(it); } else { ++it; @@ -2665,18 +2001,21 @@ bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, co // removed, or moved to outside of the view, as well as those that are // displaced to a position outside of the view due to an insert or move. - if (item->nextTransitionType == FxViewItemTransitionManager::MoveTransition) + if (!transitioner) + return false; + + if (item->nextTransitionType == QQuickItemViewTransitioner::MoveTransition) repositionItemAt(item, item->index, 0); if (!item->prepareTransition(viewBounds)) return false; if (item->isTransitionTarget) { - if (item->nextTransitionType == FxViewItemTransitionManager::MoveTransition) { - moveTransitionIndexes.append(item->index); - moveTransitionTargets.append(item->item); - } else if (item->nextTransitionType == FxViewItemTransitionManager::RemoveTransition) { - removeTransitionIndexes.append(item->index); - removeTransitionTargets.append(item->item); + if (item->nextTransitionType == QQuickItemViewTransitioner::MoveTransition) { + transitioner->moveTransitionIndexes.append(item->index); + transitioner->moveTransitionTargets.append(item->item); + } else if (item->nextTransitionType == QQuickItemViewTransitioner::RemoveTransition) { + transitioner->removeTransitionIndexes.append(item->index); + transitioner->removeTransitionTargets.append(item->item); } } @@ -2684,6 +2023,15 @@ bool QQuickItemViewPrivate::prepareNonVisibleItemTransition(FxViewItem *item, co return true; } +void QQuickItemViewPrivate::viewItemTransitionFinished(QQuickViewItem *i) +{ + FxViewItem *item = static_cast(i); + if (item->releaseAfterTransition) { + releasePendingTransition.removeOne(item); + releaseItem(item); + } +} + /* This may return 0 if the item is being created asynchronously. When the item becomes available, refill() will be called and the item diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 0d3cd1c3ce..63262f32ab 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -324,53 +324,9 @@ public: QString m_nextSection; }; -class QQuickViewTransitionAttached : public QObject -{ - Q_OBJECT - - Q_PROPERTY(int index READ index NOTIFY indexChanged) - Q_PROPERTY(QQuickItem* item READ item NOTIFY itemChanged) - Q_PROPERTY(QPointF destination READ destination NOTIFY destinationChanged) - - Q_PROPERTY(QList targetIndexes READ targetIndexes NOTIFY targetIndexesChanged) - Q_PROPERTY(QDeclarativeListProperty targetItems READ targetItems NOTIFY targetItemsChanged) - -public: - QQuickViewTransitionAttached(QObject *parent); - - int index() const { return m_index; } - QQuickItem *item() const { return m_item; } - QPointF destination() const { return m_destination; } - - QList targetIndexes() const { return m_targetIndexes; } - QDeclarativeListProperty targetItems(); - - static QQuickViewTransitionAttached *qmlAttachedProperties(QObject *); - -signals: - void indexChanged(); - void itemChanged(); - void destinationChanged(); - - void targetIndexesChanged(); - void targetItemsChanged(); - -private: - friend class FxViewItemTransitionManager; - int m_index; - QQuickItem *m_item; - QPointF m_destination; - - QList m_targetIndexes; - QList m_targetItems; -}; - QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickViewTransitionAttached) -QML_DECLARE_TYPEINFO(QQuickViewTransitionAttached, QML_HAS_ATTACHED_PROPERTIES) - QT_END_HEADER #endif // QQUICKITEMVIEW_P_H diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h index fce6e4eba5..57860a43c6 100644 --- a/src/quick/items/qquickitemview_p_p.h +++ b/src/quick/items/qquickitemview_p_p.h @@ -43,10 +43,10 @@ #define QQUICKITEMVIEW_P_P_H #include "qquickitemview_p.h" +#include "qquickitemviewtransition_p.h" #include "qquickflickable_p_p.h" #include "qquickvisualdatamodel_p.h" #include "qquickvisualitemmodel_p.h" -#include #include @@ -57,55 +57,12 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class FxViewItem; -class FxViewItemTransitionManager : public QDeclarativeTransitionManager -{ -public: - enum TransitionType { - NoTransition, - PopulateTransition, - AddTransition, - MoveTransition, - RemoveTransition - }; - - FxViewItemTransitionManager(); - ~FxViewItemTransitionManager(); - - bool isActive() const; - void startTransition(FxViewItem *item, FxViewItemTransitionManager::TransitionType type, const QPointF &to, bool isTargetItem); - - bool m_active; - FxViewItem *m_item; - QPointF m_toPos; - FxViewItemTransitionManager::TransitionType m_type; - bool m_isTarget; - -protected: - virtual void finished(); -}; - - -class FxViewItem +class FxViewItem : public QQuickViewItem { public: FxViewItem(QQuickItem *, bool own); virtual ~FxViewItem(); - qreal itemX() const; - qreal itemY() const; - - void setVisible(bool visible); - - void setNextTransition(FxViewItemTransitionManager::TransitionType, bool isTargetItem); - bool transitionScheduledOrRunning() const; - bool isPendingRemoval() const; - - bool prepareTransition(const QRectF &viewBounds); - void startTransition(); - void stopTransition(); - void finishedTransition(); - // these are positions and sizes along the current direction of scrolling/flicking virtual qreal position() const = 0; virtual qreal endPosition() const = 0; @@ -113,23 +70,10 @@ public: virtual qreal sectionSize() const = 0; virtual bool contains(qreal x, qreal y) const = 0; - virtual QQuickItemView *itemView() const = 0; - QQuickItem *item; + QQuickItemViewAttached *attached; bool ownItem; bool releaseAfterTransition; - bool isTransitionTarget; - bool nextTransitionToSet; - int index; - QQuickItemViewAttached *attached; - - FxViewItemTransitionManager *transition; - QPointF nextTransitionTo; - FxViewItemTransitionManager::TransitionType nextTransitionType; - -protected: - void moveTo(const QPointF &pos); - void resetTransitionData(); }; @@ -155,11 +99,12 @@ public: }; -class QQuickItemViewPrivate : public QQuickFlickablePrivate +class QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener { Q_DECLARE_PUBLIC(QQuickItemView) public: QQuickItemViewPrivate(); + ~QQuickItemViewPrivate(); struct ChangeResult { QDeclarativeNullableValue visiblePos; @@ -243,13 +188,12 @@ public: void repositionFirstItem(FxViewItem *prevVisibleItemsFirst, qreal prevVisibleItemsFirstPos, FxViewItem *prevFirstVisible, ChangeResult *insertionResult, ChangeResult *removalResult); + void createTransitioner(); void prepareVisibleItemTransitions(); void prepareRemoveTransitions(QHash *removedItems); bool prepareNonVisibleItemTransition(FxViewItem *item, const QRectF &viewBounds); + virtual void viewItemTransitionFinished(QQuickViewItem *item); - bool canTransition(FxViewItemTransitionManager::TransitionType type, bool asTarget) const; - bool hasItemTransitions() const; - void transitionNextReposition(FxViewItem *item, FxViewItemTransitionManager::TransitionType type, bool isTarget); int findMoveKeyIndex(QDeclarativeChangeSet::MoveKey key, const QVector &changes) const; void checkVisible() const; @@ -281,7 +225,6 @@ public: FxViewItem *requestedItem; QQuickItemViewChangeSet currentChanges; - // XXX split into struct QDeclarativeComponent *highlightComponent; FxViewItem *highlight; int highlightRange; // enum value @@ -294,27 +237,13 @@ public: QDeclarativeComponent *footerComponent; FxViewItem *footer; - QDeclarativeTransition *populateTransition; - QDeclarativeTransition *addTransition; - QDeclarativeTransition *addDisplacedTransition; - QDeclarativeTransition *moveTransition; - QDeclarativeTransition *moveDisplacedTransition; - QDeclarativeTransition *removeTransition; - QDeclarativeTransition *removeDisplacedTransition; - - QList addTransitionIndexes; - QList moveTransitionIndexes; - QList removeTransitionIndexes; - QList addTransitionTargets; - QList moveTransitionTargets; - QList removeTransitionTargets; - struct MovedItem { FxViewItem *item; QDeclarativeChangeSet::MoveKey moveKey; MovedItem(FxViewItem *i, QDeclarativeChangeSet::MoveKey k) : item(i), moveKey(k) {} }; + QQuickItemViewTransitioner *transitioner; QList releasePendingTransition; mutable qreal minExtent; @@ -333,7 +262,6 @@ public: bool fillCacheBuffer : 1; bool inRequest : 1; bool requestedAsync : 1; - bool usePopulateTransition : 1; bool runDelayedRemoveTransition : 1; protected: diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp new file mode 100644 index 0000000000..3e3a99f553 --- /dev/null +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -0,0 +1,770 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickitemviewtransition_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + + +class QQuickItemViewTransitionJob : public QDeclarativeTransitionManager +{ +public: + QQuickItemViewTransitionJob(QQuickItemViewTransitioner *transitioner); + ~QQuickItemViewTransitionJob(); + + void startTransition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem); + + QQuickItemViewTransitioner *m_transitioner; + QQuickViewItem *m_item; + QPointF m_toPos; + QQuickItemViewTransitioner::TransitionType m_type; + bool m_isTarget; + +protected: + virtual void finished(); +}; + + +QQuickItemViewTransitionJob::QQuickItemViewTransitionJob(QQuickItemViewTransitioner *transitioner) + : m_transitioner(transitioner) + , m_item(0), m_type(QQuickItemViewTransitioner::NoTransition), m_isTarget(false) +{ +} + +QQuickItemViewTransitionJob::~QQuickItemViewTransitionJob() +{ +} + +void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem) +{ + if (!item) { + qWarning("startTransition(): invalid item"); + return; + } + + QDeclarativeTransition *trans = 0; + switch (type) { + case QQuickItemViewTransitioner::NoTransition: + break; + case QQuickItemViewTransitioner::PopulateTransition: + trans = m_transitioner->populateTransition; + break; + case QQuickItemViewTransitioner::AddTransition: + trans = isTargetItem ? m_transitioner->addTransition : m_transitioner->addDisplacedTransition; + break; + case QQuickItemViewTransitioner::MoveTransition: + trans = isTargetItem ? m_transitioner->moveTransition : m_transitioner->moveDisplacedTransition; + break; + case QQuickItemViewTransitioner::RemoveTransition: + trans = isTargetItem ? m_transitioner->removeTransition : m_transitioner->removeDisplacedTransition; + break; + } + + if (!trans) { + qWarning("QQuickItemView: invalid view transition!"); + return; + } + + m_item = item; + m_toPos = to; + m_type = type; + m_isTarget = isTargetItem; + + QQuickViewTransitionAttached *attached = + static_cast(qmlAttachedPropertiesObject(trans)); + if (attached) { + attached->m_index = item->index; + attached->m_item = item->item; + attached->m_destination = to; + switch (type) { + case QQuickItemViewTransitioner::NoTransition: + break; + case QQuickItemViewTransitioner::PopulateTransition: + case QQuickItemViewTransitioner::AddTransition: + attached->m_targetIndexes = m_transitioner->addTransitionIndexes; + attached->m_targetItems = m_transitioner->addTransitionTargets; + break; + case QQuickItemViewTransitioner::MoveTransition: + attached->m_targetIndexes = m_transitioner->moveTransitionIndexes; + attached->m_targetItems = m_transitioner->moveTransitionTargets; + break; + case QQuickItemViewTransitioner::RemoveTransition: + attached->m_targetIndexes = m_transitioner->removeTransitionIndexes; + attached->m_targetItems = m_transitioner->removeTransitionTargets; + break; + } + emit attached->indexChanged(); + emit attached->itemChanged(); + emit attached->destinationChanged(); + emit attached->targetIndexesChanged(); + emit attached->targetItemsChanged(); + } + + QDeclarativeStateOperation::ActionList actions; + actions << QDeclarativeAction(item->item, QLatin1String("x"), QVariant(to.x())); + actions << QDeclarativeAction(item->item, QLatin1String("y"), QVariant(to.y())); + + QDeclarativeTransitionManager::transition(actions, trans, item->item); +} + +void QQuickItemViewTransitionJob::finished() +{ + QDeclarativeTransitionManager::finished(); + + if (m_item) + m_item->finishedTransition(); + if (m_transitioner) + m_transitioner->finishedTransition(m_item); + + m_item = 0; + m_toPos.setX(0); + m_toPos.setY(0); + m_type = QQuickItemViewTransitioner::NoTransition; + m_isTarget = false; +} + + +QQuickItemViewTransitioner::QQuickItemViewTransitioner() + : populateTransition(0) + , addTransition(0), addDisplacedTransition(0) + , moveTransition(0), moveDisplacedTransition(0) + , removeTransition(0), removeDisplacedTransition(0) + , changeListener(0) + , usePopulateTransition(false) +{ +} + +bool QQuickItemViewTransitioner::canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const +{ + switch (type) { + case QQuickItemViewTransitioner::NoTransition: + break; + case QQuickItemViewTransitioner::PopulateTransition: + return usePopulateTransition + && populateTransition && populateTransition->enabled(); + case QQuickItemViewTransitioner::AddTransition: + if (asTarget) + return addTransition && addTransition->enabled(); + else + return addDisplacedTransition && addDisplacedTransition->enabled(); + case QQuickItemViewTransitioner::MoveTransition: + if (asTarget) + return moveTransition && moveTransition->enabled(); + else + return moveDisplacedTransition && moveDisplacedTransition->enabled(); + case QQuickItemViewTransitioner::RemoveTransition: + if (asTarget) + return removeTransition && removeTransition->enabled(); + else + return removeDisplacedTransition && removeDisplacedTransition->enabled(); + } + return false; +} + +void QQuickItemViewTransitioner::transitionNextReposition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, bool isTarget) +{ + bool matchedTransition = false; + if (type == QQuickItemViewTransitioner::AddTransition) { + // don't run add transitions for added items while populating + if (usePopulateTransition) + matchedTransition = false; + else + matchedTransition = canTransition(type, isTarget); + } else { + matchedTransition = canTransition(type, isTarget); + } + + if (matchedTransition) { + item->setNextTransition(type, isTarget); + } else { + // the requested transition type is not valid, but the item is scheduled/in another + // transition, so cancel it to allow the item to move directly to the correct pos + if (item->transitionScheduledOrRunning()) + item->stopTransition(); + } +} + +void QQuickItemViewTransitioner::finishedTransition(QQuickViewItem *item) +{ + if (changeListener) + changeListener->viewItemTransitionFinished(item); +} + + +QQuickViewItem::QQuickViewItem(QQuickItem *i) + : item(i) + , transition(0) + , nextTransitionType(QQuickItemViewTransitioner::NoTransition) + , index(-1) + , isTransitionTarget(false) + , nextTransitionToSet(false) +{ +} + +QQuickViewItem::~QQuickViewItem() +{ + if (transition) { + transition->m_item = 0; + transition->m_transitioner = 0; + } + delete transition; +} + +qreal QQuickViewItem::itemX() const +{ + if (nextTransitionType != QQuickItemViewTransitioner::NoTransition) + return nextTransitionToSet ? nextTransitionTo.x() : item->x(); + else if (transition && transition->isRunning()) + return transition->m_toPos.x(); + else + return item->x(); +} + +qreal QQuickViewItem::itemY() const +{ + // If item is transitioning to some pos, return that dest pos. + // If item was redirected to some new pos before the current transition finished, + // return that new pos. + if (nextTransitionType != QQuickItemViewTransitioner::NoTransition) + return nextTransitionToSet ? nextTransitionTo.y() : item->y(); + else if (transition && transition->isRunning()) + return transition->m_toPos.y(); + else + return item->y(); +} + +void QQuickViewItem::moveTo(const QPointF &pos) +{ + if (transitionScheduledOrRunning()) { + nextTransitionTo = pos; + nextTransitionToSet = true; + } else { + item->setPos(pos); + } +} + +void QQuickViewItem::setVisible(bool visible) +{ + if (!visible && transitionScheduledOrRunning()) + return; + item->setVisible(visible); +} + +bool QQuickViewItem::transitionScheduledOrRunning() const +{ + return (transition && transition->isRunning()) + || nextTransitionType != QQuickItemViewTransitioner::NoTransition; +} + +bool QQuickViewItem::transitionRunning() const +{ + return (transition && transition->isRunning()); +} + +bool QQuickViewItem::isPendingRemoval() const +{ + if (nextTransitionType == QQuickItemViewTransitioner::RemoveTransition) + return isTransitionTarget; + if (transition && transition->isRunning() && transition->m_type == QQuickItemViewTransitioner::RemoveTransition) + return transition->m_isTarget; + return false; +} + +bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) +{ + bool doTransition = false; + + switch (nextTransitionType) { + case QQuickItemViewTransitioner::NoTransition: + { + return false; + } + case QQuickItemViewTransitioner::PopulateTransition: + { + return true; + } + case QQuickItemViewTransitioner::AddTransition: + case QQuickItemViewTransitioner::RemoveTransition: + // For Add targets, do transition if item is moving into visible area + // For Remove targets, do transition if item is currently in visible area + if (isTransitionTarget) { + doTransition = (nextTransitionType == QQuickItemViewTransitioner::AddTransition) + ? viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())) + : viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())); + if (!doTransition) + item->setPos(nextTransitionTo); + } else { + if (viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) + || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()))) { + doTransition = (nextTransitionTo != item->pos()); + } else { + item->setPos(nextTransitionTo); + } + } + break; + case QQuickItemViewTransitioner::MoveTransition: + // do transition if moving from or into visible area + if (nextTransitionTo != item->pos()) { + doTransition = viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) + || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())); + if (!doTransition) + item->setPos(nextTransitionTo); + } + break; + } + + if (!doTransition) + resetTransitionData(); + return doTransition; +} + +void QQuickViewItem::startTransition(QQuickItemViewTransitioner *transitioner) +{ + if (nextTransitionType == QQuickItemViewTransitioner::NoTransition) + return; + + if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) { + delete transition; + transition = new QQuickItemViewTransitionJob(transitioner); + } + + // if item is not already moving somewhere, set it to not move anywhere + // so that removed items do not move to the default (0,0) + if (!nextTransitionToSet) + moveTo(item->pos()); + + transition->startTransition(this, nextTransitionType, nextTransitionTo, isTransitionTarget); + nextTransitionType = QQuickItemViewTransitioner::NoTransition; +} + +void QQuickViewItem::stopTransition() +{ + if (transition) { + transition->cancel(); + delete transition; + transition = 0; + } + resetTransitionData(); + finishedTransition(); +} + +void QQuickViewItem::setNextTransition(QQuickItemViewTransitioner::TransitionType type, bool isTargetItem) +{ + // Don't reset nextTransitionToSet - once it is set, it cannot be changed + // until the animation finishes since the itemX() and itemY() may be used + // to calculate positions for transitions for other items in the view. + nextTransitionType = type; + isTransitionTarget = isTargetItem; +} + +void QQuickViewItem::finishedTransition() +{ + nextTransitionToSet = false; + nextTransitionTo = QPointF(); +} + +void QQuickViewItem::resetTransitionData() +{ + nextTransitionType = QQuickItemViewTransitioner::NoTransition; + isTransitionTarget = false; + nextTransitionTo = QPointF(); + nextTransitionToSet = false; +} + + +QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) + : QObject(parent), m_item(0), m_index(-1) +{ +} +/*! + \qmlclass ViewTransition QQuickViewTransitionAttached + \inqmlmodule QtQuick 2 + \ingroup qml-view-elements + \brief The ViewTransition attached property provides details on items under transition in a view. + + With ListView and GridView, it is possible to specify transitions that should be applied whenever + the items in the view change as a result of modifications to the view's model. They both have the + following properties that can be set to the appropriate transitions to be run for various + operations: + + \list + \o \c add and \c addDisplaced - the transitions to run when items are added to the view + \o \c remove and \c removeDisplaced - the transitions to run when items are removed from the view + \o \c move and \c moveDisplaced - the transitions to run when items are moved within the view + (i.e. as a result of a move operation in the model) + \o \c populate - the transition to run when a view is created, or when the model changes + \endlist + + Such view transitions additionally have access to a ViewTransition attached property that + provides details of the items that are under transition and the operation that triggered the + transition. Since view transitions are run once per item, these details can be used to customise + each transition for each individual item. + + The ViewTransition attached property provides the following properties specific to the item to + which the transition is applied: + + \list + \o ViewTransition.item - the item that is under transition + \o ViewTransition.index - the index of this item + \o ViewTransition.destination - the (x,y) point to which this item is moving for the relevant view operation + \endlist + + In addition, ViewTransition provides properties specific to the items which are the target + of the operation that triggered the transition: + + \list + \o ViewTransition.targetIndexes - the indexes of the target items + \o ViewTransition.targetItems - the target items themselves + \endlist + + View transitions can be written without referring to any of the attributes listed + above. These attributes merely provide extra details that are useful for customising view + transitions. + + Following is an introduction to view transitions and the ways in which the ViewTransition + attached property can be used to augment view transitions. + + + \section2 View transitions: a simple example + + Here is a basic example of the use of view transitions. The view below specifies transitions for + the \c add and \c addDisplaced properties, which will be run when items are added to the view: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-basic.qml 0 + + When the space key is pressed, adding an item to the model, the new item will fade in and + increase in scale over 400 milliseconds as it is added to the view. Also, any item that is + displaced by the addition of a new item will animate to its new position in the view over + 400 milliseconds, as specified by the \c addDisplaced transition. + + If five items were inserted in succession at index 0, the effect would be this: + + \image viewtransitions-basic.gif + + Notice that the NumberAnimation objects above do not need to specify a \c target to animate + the appropriate item. Also, the NumberAnimation in the \c addTransition does not need to specify + the \c to value to move the item to its correct position in the view. This is because the view + implicitly sets the \c target and \c to values with the correct item and final item position + values if these properties are not explicitly defined. + + At its simplest, a view transition may just animate an item to its new position following a + view operation, just as the \c addDisplaced transition does above, or animate some item properties, + as in the \c add transition above. Additionally, a view transition may make use of the + ViewTransition attached property to customise animation behavior for different items. Following + are some examples of how this can be achieved. + + + \section2 Using the ViewTransition attached property + + As stated, the various ViewTransition properties provide details specific to the individual item + being transitioned as well as the operation that triggered the transition. In the animation above, + five items are inserted in succession at index 0. When the fifth and final insertion takes place, + adding "Item 4" to the view, the \c add transition is run once (for the inserted item) and the + \c addDisplaced transition is run four times (once for each of the four existing items in the view). + + At this point, if we examined the \c addDisplaced transition that was run for the bottom displaced + item ("Item 0"), the ViewTransition property values provided to this transition would be as follows: + + \table + \header + \o Property + \o Value + \o Explanation + \row + \o ViewTransition.item + \o "Item 0" delegate instance + \o The "Item 0" \l Rectangle object itself + \row + \o ViewTransition.index + \o \c int value of 4 + \o The index of "Item 0" within the model following the add operation + \row + \o ViewTransition.destination + \o \l point value of (0, 120) + \o The position that "Item 0" is moving to + \row + \o ViewTransition.targetIndexes + \o \c int array, just contains the integer "0" (zero) + \o The index of "Item 4", the new item added to the view + \row + \o ViewTransition.targetItems + \o object array, just contains the "Item 4" delegate instance + \o The "Item 4" \l Rectangle object - the new item added to the view + \endtable + + The ViewTransition.targetIndexes and ViewTransition.targetItems lists provide the items and + indexes of all delegate instances that are the targets of the relevant operation. For an add + operation, these are all the items that are added into the view; for a remove, these are all + the items removed from the view, and so on. (Note these lists will only contain references to + items that have been created within the view or its cached items; targets that are not within + the visible area of the view or within the item cache will not be accessible.) + + So, while the ViewTransition.item, ViewTransition.index and ViewTransition.destination values + vary for each individual transition that is run, the ViewTransition.targetIndexes and + ViewTransition.targetItems values are the same for every \c add and \c addDisplaced transition + that is triggered by a particular add operation. + + + \section3 Delaying animations based on index + + Since each view transition is run once for each item affected by the transition, the ViewTransition + properties can be used within a transition to define custom behavior for each item's transition. + For example, the ListView in the previous example could use this information to create a ripple-type + effect on the movement of the displaced items. + + This can be achieved by modifying the \c addDisplaced transition so that it delays the animation of + each displaced item based on the difference between its index (provided by ViewTransition.index) + and the first removed index (provided by ViewTransition.targetIndexes): + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-delayedbyindex.qml 0 + + Each displaced item delays its animation by an additional 100 milliseconds, producing a subtle + ripple-type effect when items are displaced by the add, like this: + + \image viewtransitions-delayedbyindex.gif + + + \section3 Animating items to intermediate positions + + The ViewTransition.item property gives a reference to the item to which the transition is being + applied. This can be used to access any of the item's attributes, custom \c property values, + and so on. + + Below is a modification of the \c addDisplaced transition from the previous example. It adds a + ParallelAnimation with nested NumberAnimation objects that reference ViewTransition.item to access + each item's \c x and \c y values at the start of their transitions. This allows each item to + animate to an intermediate position relative to its starting point for the transition, before + animating to its final position in the view: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-intermediatemove.qml 0 + + Now, a displaced item will first move to a position of (20, 50) relative to its starting + position, and then to its final, correct position in the view: + + \image viewtransitions-intermediatemove.gif + + Since the final NumberAnimation does not specify a \c to value, the view implicitly sets this + value to the item's final position in the view, and so this last animation will move this item + to the correct place. If the transition requires the final position of the item for some calculation, + this is accessible through ViewTransition.destination. + + Instead of using multiple NumberAnimations, you could use a PathAnimation to animate an item over + a curved path. For example, the \c add transition in the previous example could be augmented with + a PathAnimation as follows: to animate newly added items along a path: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-pathanim.qml 0 + + This animates newly added items along a path. Notice that each path is specified relative to + each item's final destination point, so that items inserted at different indexes start their + paths from different positions: + + \image viewtransitions-pathanim.gif + + + \section2 Handling interrupted animations + + A view transition may be interrupted at any time if a different view transition needs to be + applied while the original transition is in progress. For example, say Item A is inserted at index 0 + and undergoes an "add" transition; then, Item B is inserted at index 0 in quick succession before + Item A's transition has finished. Since Item B is inserted before Item A, it will displace Item + A, causing the view to interrupt Item A's "add" transition mid-way and start an "addDisplaced" + transition on Item A instead. + + For simple animations that simply animate an item's movement to its final destination, this + interruption is unlikely to require additional consideration. However, if a transition changes other + properties, this interruption may cause unwanted side effects. Consider the first example on this + page, repeated below for convenience: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-basic.qml 0 + + If multiple items are added in rapid succession, without waiting for a previous transition + to finish, this is the result: + + \image viewtransitions-interruptedbad.gif + + Each newly added item undergoes an \c add transition, but before the transition can finish, + another item is added, displacing the previously added item. Because of this, the \c add + transition on the previously added item is interrupted and an \c addDisplaced transition is + started on the item instead. Due to the interruption, the \c opacity and \c scale animations + have not completed, thus producing items with opacity and scale that are below 1.0. + + To fix this, the \c addDisplaced transition should additionally ensure the item properties are + set to the end values specified in the \c add transition, effectively resetting these values + whenever an item is displaced. In this case, it means setting the item opacity and scale to 1.0: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-interruptedgood.qml 0 + + Now, when an item's \c add transition is interrupted, its opacity and scale are animated to 1.0 + upon displacement, avoiding the erroneous visual effects from before: + + \image viewtransitions-interruptedgood.gif + + The same principle applies to any combination of view transitions. An added item may be moved + before its add transition finishes, or a moved item may be removed before its moved transition + finishes, and so on; so, the rule of thumb is that every transition should handle the same set of + properties. + + + \section2 Restrictions regarding ScriptAction + + When a view transition is initialized, any property bindings that refer to the ViewTransition + attached property are evaluated in preparation for the transition. Due to the nature of the + internal construction of a view transition, the attributes of the ViewTransition attached + property are only valid for the relevant item when the transition is initialized, and may not be + valid when the transition is actually run. + + Therefore, a ScriptAction within a view transition should not refer to the ViewTransition + attached property, as it may not refer to the expected values at the time that the ScriptAction + is actually invoked. Consider the following example: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-scriptactionbad.qml 0 + + When the space key is pressed, three items are moved from index 5 to index 1. For each moved + item, the \c moveTransition sequence presumably animates the item's color to "yellow", then + animates it to its final position, then changes the item color back to "lightsteelblue" using a + ScriptAction. However, when run, the transition does not produce the intended result: + + \image viewtransitions-scriptactionbad.gif + + Only the last moved item is returned to the "lightsteelblue" color; the others remain yellow. This + is because the ScriptAction is not run until after the transition has already been initialized, by + which time the ViewTransition.item value has changed to refer to a different item; the item that + the script had intended to refer to is not the one held by ViewTransition.item at the time the + ScriptAction is actually invoked. + + In this instance, to avoid this issue, the view could set the property using a PropertyAction + instead: + + \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-scriptactiongood.qml 0 + + When the transition is initialized, the PropertyAction \c target will be set to the respective + ViewTransition.item for the transition and will later run with the correct item target as + expected. + */ + +/*! + \qmlattachedproperty list QtQuick2::ViewTransition::index + + This attached property holds the index of the item that is being + transitioned. + + Note that if the item is being moved, this property holds the index that + the item is moving to, not from. +*/ + +/*! + \qmlattachedproperty list QtQuick2::ViewTransition::item + + This attached property holds the the item that is being transitioned. + + \warning This item should not be kept and referred to outside of the transition + as it may become invalid as the view changes. +*/ + +/*! + \qmlattachedproperty list QtQuick2::ViewTransition::destination + + This attached property holds the final destination position for the transitioned + item within the view. + + This property value is a \l point with \c x and \c y properties. +*/ + +/*! + \qmlattachedproperty list QtQuick2::ViewTransition::targetIndexes + + This attached property holds a list of the indexes of the items in view + that are the target of the relevant operation. + + The targets are the items that are the subject of the operation. For + an add operation, these are the items being added; for a remove, these + are the items being removed; for a move, these are the items being + moved. + + For example, if the transition was triggered by an insert operation + that added two items at index 1 and 2, this targetIndexes list would + have the value [1,2]. + + \note The targetIndexes list only contains the indexes of items that are actually + in view, or will be in the view once the relevant operation completes. + + \sa QtQuick2::ViewTransition::targetIndexes +*/ + +/*! + \qmlattachedproperty list QtQuick2::ViewTransition::targetItems + + This attached property holds the list of items in view that are the + target of the relevant operation. + + The targets are the items that are the subject of the operation. For + an add operation, these are the items being added; for a remove, these + are the items being removed; for a move, these are the items being + moved. + + For example, if the transition was triggered by an insert operation + that added two items at index 1 and 2, this targetItems list would + contain these two items. + + \note The targetItems list only contains items that are actually + in view, or will be in the view once the relevant operation completes. + + \warning The objects in this list should not be kept and referred to + outside of the transition as the items may become invalid. The targetItems + are only valid when the Transition is initially created; this also means + they should not be used by ScriptAction objects in the Transition, which are + not evaluated until the transition is run. + + \sa QtQuick2::ViewTransition::targetIndexes +*/ +QDeclarativeListProperty QQuickViewTransitionAttached::targetItems() +{ + return QDeclarativeListProperty(this, m_targetItems); +} + +QQuickViewTransitionAttached *QQuickViewTransitionAttached::qmlAttachedProperties(QObject *obj) +{ + return new QQuickViewTransitionAttached(obj); +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h new file mode 100644 index 0000000000..c388bed17e --- /dev/null +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKITEMVIEWTRANSITION_P_P_H +#define QQUICKITEMVIEWTRANSITION_P_P_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QQuickItem; +class QQuickViewItem; +class QQuickItemViewTransitionJob; + + +class QQuickItemViewTransitionChangeListener +{ +public: + QQuickItemViewTransitionChangeListener() {} + virtual ~QQuickItemViewTransitionChangeListener() {} + + virtual void viewItemTransitionFinished(QQuickViewItem *item) = 0; +}; + + +class QQuickItemViewTransitioner +{ +public: + enum TransitionType { + NoTransition, + PopulateTransition, + AddTransition, + MoveTransition, + RemoveTransition + }; + + QQuickItemViewTransitioner(); + virtual ~QQuickItemViewTransitioner() {} + + bool canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const; + void transitionNextReposition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, bool isTarget); + + inline void setPopulateTransitionEnabled(bool b) { usePopulateTransition = b; } + inline void setChangeListener(QQuickItemViewTransitionChangeListener *obj) { changeListener = obj; } + + QList addTransitionIndexes; + QList moveTransitionIndexes; + QList removeTransitionIndexes; + QList addTransitionTargets; + QList moveTransitionTargets; + QList removeTransitionTargets; + + QDeclarativeTransition *populateTransition; + QDeclarativeTransition *addTransition; + QDeclarativeTransition *addDisplacedTransition; + QDeclarativeTransition *moveTransition; + QDeclarativeTransition *moveDisplacedTransition; + QDeclarativeTransition *removeTransition; + QDeclarativeTransition *removeDisplacedTransition; + +private: + friend class QQuickItemViewTransitionJob; + + QQuickItemViewTransitionChangeListener *changeListener; + bool usePopulateTransition; + + void finishedTransition(QQuickViewItem *item); +}; + + +/* + An item in a view, that can be transitioned using QQuickViewTransitionJob. + */ +class QQuickViewItem +{ +public: + QQuickViewItem(QQuickItem *i); + virtual ~QQuickViewItem(); + + qreal itemX() const; + qreal itemY() const; + + void moveTo(const QPointF &pos); + void setVisible(bool visible); + + bool transitionScheduledOrRunning() const; + bool transitionRunning() const; + bool isPendingRemoval() const; + + bool prepareTransition(const QRectF &viewBounds); + void startTransition(QQuickItemViewTransitioner *transitioner); + void stopTransition(); + + QPointF nextTransitionTo; + QQuickItem *item; + QQuickItemViewTransitionJob *transition; + QQuickItemViewTransitioner::TransitionType nextTransitionType; + int index; + bool isTransitionTarget; + bool nextTransitionToSet; + +private: + friend class QQuickItemViewTransitioner; + friend class QQuickItemViewTransitionJob; + void setNextTransition(QQuickItemViewTransitioner::TransitionType, bool isTargetItem); + void finishedTransition(); + void resetTransitionData(); +}; + + +class QQuickViewTransitionAttached : public QObject +{ + Q_OBJECT + + Q_PROPERTY(int index READ index NOTIFY indexChanged) + Q_PROPERTY(QQuickItem* item READ item NOTIFY itemChanged) + Q_PROPERTY(QPointF destination READ destination NOTIFY destinationChanged) + + Q_PROPERTY(QList targetIndexes READ targetIndexes NOTIFY targetIndexesChanged) + Q_PROPERTY(QDeclarativeListProperty targetItems READ targetItems NOTIFY targetItemsChanged) + +public: + QQuickViewTransitionAttached(QObject *parent); + + int index() const { return m_index; } + QQuickItem *item() const { return m_item; } + QPointF destination() const { return m_destination; } + + QList targetIndexes() const { return m_targetIndexes; } + QDeclarativeListProperty targetItems(); + + static QQuickViewTransitionAttached *qmlAttachedProperties(QObject *); + +signals: + void indexChanged(); + void itemChanged(); + void destinationChanged(); + + void targetIndexesChanged(); + void targetItemsChanged(); + +private: + friend class QQuickItemViewTransitionJob; + QPointF m_destination; + QList m_targetIndexes; + QList m_targetItems; + + QQuickItem *m_item; + int m_index; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickViewTransitionAttached) +QML_DECLARE_TYPEINFO(QQuickViewTransitionAttached, QML_HAS_ATTACHED_PROPERTIES) + +QT_END_HEADER + +#endif // QQUICKITEMVIEWTRANSITION_P_P_H diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 0e643a13e3..2190952c69 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -316,9 +316,6 @@ public: return (x >= itemX() && x < itemX() + item->width() && y >= itemY() && y < itemY() + item->height()); } - QQuickItemView *itemView() const { - return view; - } QQuickListView *view; @@ -643,7 +640,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d #endif if (!(item = static_cast(createItem(modelIndex, doBuffer)))) break; - if (!canTransition(FxViewItemTransitionManager::PopulateTransition, true)) // pos will be set by layoutVisibleItems() + if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(pos); item->item->setVisible(!doBuffer); pos += item->size() + spacing; @@ -663,7 +660,7 @@ bool QQuickListViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, bool d break; --visibleIndex; visiblePos -= item->size() + spacing; - if (!canTransition(FxViewItemTransitionManager::PopulateTransition, true)) // pos will be set by layoutVisibleItems() + if (!transitioner || !transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) // pos will be set by layoutVisibleItems() item->setPosition(visiblePos); item->item->setVisible(!doBuffer); visibleItems.prepend(item); @@ -2341,6 +2338,10 @@ void QQuickListView::setSnapMode(SnapMode mode) the new item that has been added to the view; to animate the added items, set the \l add property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2405,6 +2406,10 @@ void QQuickListView::setSnapMode(SnapMode mode) the items that are the actual subjects of the move operation; to animate the moved items, set the \l move property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2472,6 +2477,10 @@ void QQuickListView::setSnapMode(SnapMode mode) the item that has actually been removed from the view; to animate the removed items, set the \l remove property. + If an item is displaced by multiple types of operations at the same time, it is not + defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition + will be applied. + For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2740,7 +2749,8 @@ bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In insertResult->changedFirstItem = true; if (!change.isMove()) { addedItems->append(item); - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, true); + if (transitioner) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true); } insertResult->sizeChangesBeforeVisiblePos += item->size() + spacing; pos -= item->size() + spacing; @@ -2766,11 +2776,12 @@ bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In if (change.isMove()) { // we know this is a move target, since move displaced items that are // shuffled into view due to a move would be added in refill() - if (canTransition(FxViewItemTransitionManager::MoveTransition, true) && newItem) + if (newItem && transitioner && transitioner->canTransition(QQuickItemViewTransitioner::MoveTransition, true)) movingIntoView->append(MovedItem(item, change.moveKey(item->index))); } else { addedItems->append(item); - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, true); + if (transitioner) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, true); } insertResult->sizeChangesAfterVisiblePos += item->size() + spacing; pos += item->size() + spacing; @@ -2782,10 +2793,12 @@ bool QQuickListViewPrivate::applyInsertionChange(const QDeclarativeChangeSet::In FxViewItem *item = visibleItems.at(index); if (item->index != -1) item->index += count; - if (change.isMove()) - transitionNextReposition(item, FxViewItemTransitionManager::MoveTransition, false); - else - transitionNextReposition(item, FxViewItemTransitionManager::AddTransition, false); + if (transitioner) { + if (change.isMove()) + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::MoveTransition, false); + else + transitioner->transitionNextReposition(item, QQuickItemViewTransitioner::AddTransition, false); + } } updateVisibleIndex(); @@ -2797,6 +2810,9 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex { Q_UNUSED(insertionResult); + if (!transitioner) + return; + int markerItemIndex = -1; for (int i=0; iindex == afterModelIndex) { @@ -2816,7 +2832,7 @@ void QQuickListViewPrivate::translateAndTransitionItemsAfter(int afterModelIndex if (!listItem->transitionScheduledOrRunning()) { qreal pos = listItem->position(); listItem->setPosition(pos - sizeRemoved); - transitionNextReposition(listItem, FxViewItemTransitionManager::RemoveTransition, false); + transitioner->transitionNextReposition(listItem, QQuickItemViewTransitioner::RemoveTransition, false); listItem->setPosition(pos); } } -- cgit v1.2.3 From 0507afe3fc13640fbf7d1a79c6699337b31498fc Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 28 Feb 2012 12:03:46 +1000 Subject: Properly cleanup cancelled incubation. Not all allocations were being destroyed. Change-Id: I2134bb224c58b947cfb990b0af2f6eedfd36da4a Reviewed-by: Andrew den Exter --- src/quick/items/qquickvisualdatamodel.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickvisualdatamodel.cpp b/src/quick/items/qquickvisualdatamodel.cpp index 0bdf0cb5af..3aa6077d32 100644 --- a/src/quick/items/qquickvisualdatamodel.cpp +++ b/src/quick/items/qquickvisualdatamodel.cpp @@ -461,8 +461,28 @@ void QQuickVisualDataModel::cancel(int index) Compositor::iterator it = d->m_compositor.find(d->m_compositorGroup, index); QQuickVisualDataModelItem *cacheItem = it->inCache() ? d->m_cache.at(it.cacheIndex) : 0; - if (cacheItem && cacheItem->incubationTask) - d->releaseIncubator(cacheItem->incubationTask); + if (cacheItem) { + if (cacheItem->incubationTask) { + delete cacheItem->incubationTask->incubatingContext; + cacheItem->incubationTask->incubatingContext = 0; + d->releaseIncubator(cacheItem->incubationTask); + cacheItem->incubationTask = 0; + } + if (cacheItem->object && !cacheItem->isObjectReferenced()) { + d->destroy(cacheItem->object); + if (QDeclarativePackage *package = qobject_cast(cacheItem->object)) + d->emitDestroyingPackage(package); + else if (QQuickItem *item = qobject_cast(cacheItem->object)) + d->emitDestroyingItem(item); + cacheItem->object = 0; + } + if (!cacheItem->isReferenced()) { + d->m_compositor.clearFlags(Compositor::Cache, it.cacheIndex, 1, Compositor::CacheFlag); + d->m_cache.removeAt(it.cacheIndex); + delete cacheItem; + Q_ASSERT(d->m_cache.count() == d->m_compositor.count(Compositor::Cache)); + } + } } void QQuickVisualDataModelPrivate::group_append( -- cgit v1.2.3 From ba3ac328ca721712c56f28a1fc6ae8e64b6ad7f2 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 22 Feb 2012 17:23:47 +1000 Subject: Add generic "displaced" transition property This is the default displaced transition that will be applied if addDisplaced, removeDisplaced or moveDisplaced are not specified (or are disabled). Change-Id: I9356036dc93bd9cb26e64e0b1769228113b74273 Reviewed-by: Martin Jones --- src/quick/items/qquickgridview.cpp | 74 +++++++++++++++++++++------- src/quick/items/qquickitemview.cpp | 16 ++++++ src/quick/items/qquickitemview_p.h | 5 ++ src/quick/items/qquickitemviewtransition.cpp | 60 +++++++++++++++------- src/quick/items/qquickitemviewtransition_p.h | 1 + src/quick/items/qquicklistview.cpp | 72 ++++++++++++++++++++------- 6 files changed, 176 insertions(+), 52 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index fbce0af0c3..8b9f8059fb 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -1634,8 +1634,8 @@ void QQuickGridView::setSnapMode(SnapMode mode) Whenever an item is added to the above view, the item will be animated from the position (100,100) to its final x,y position within the view, over one second. The transition only applies to the new items that are added to the view; it does not apply to the items below that are - displaced by the addition of the new items. To animate the displaced items, set the \l - addDisplaced property. + displaced by the addition of the new items. To animate the displaced items, set the \l displaced + or \l addDisplaced properties. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1671,9 +1671,10 @@ void QQuickGridView::setSnapMode(SnapMode mode) the new item that has been added to the view; to animate the added items, set the \l add property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1682,7 +1683,7 @@ void QQuickGridView::setSnapMode(SnapMode mode) populated, or when the view's \l model changes. In those cases, the \l populate transition is applied instead. - \sa add, populate, ViewTransition + \sa displaced, add, populate, ViewTransition */ /*! \qmlproperty Transition QtQuick2::GridView::move @@ -1705,7 +1706,7 @@ void QQuickGridView::setSnapMode(SnapMode mode) respective items in the view will be animated to their new positions in the view over one second. The transition only applies to the items that are the subject of the move operation in the model; it does not apply to items below them that are displaced by the move operation. - To animate the displaced items, set the \l moveDisplaced property. + To animate the displaced items, set the \l displaced or \l moveDisplaced properties. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -1738,14 +1739,15 @@ void QQuickGridView::setSnapMode(SnapMode mode) the items that are the actual subjects of the move operation; to animate the moved items, set the \l move property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. - \sa move, ViewTransition + \sa displaced, move, ViewTransition */ /*! @@ -1770,8 +1772,8 @@ void QQuickGridView::setSnapMode(SnapMode mode) Whenever an item is removed from the above view, the item will be animated to the position (100,100) over one second, and in parallel will also change its opacity to 0. The transition only applies to the items that are removed from the view; it does not apply to the items below - them that are displaced by the removal of the items. To animate the displaced items, set the \l - removeDisplaced property. + them that are displaced by the removal of the items. To animate the displaced items, set the + \l displaced or \l removeDisplaced properties. Note that by the time the transition is applied, the item has already been removed from the model; any references to the model data for the removed index will not be valid. @@ -1809,15 +1811,53 @@ void QQuickGridView::setSnapMode(SnapMode mode) the item that has actually been removed from the view; to animate the removed items, set the \l remove property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. - \sa remove, ViewTransition + \sa displaced, remove, ViewTransition */ + +/*! + \qmlproperty Transition QtQuick2::GridView::displaced + This property holds the generic transition to apply to items that have been displaced by + any model operation that affects the view. + + This is a convenience for specifying a generic transition for items that are displaced + by add, move or remove operations, without having to specify the individual addDisplaced, + moveDisplaced and removeDisplaced properties. For example, here is a view that specifies + a displaced transition: + + \code + GridView { + ... + displaced: Transition { + NumberAnimation { properties: "x,y"; duration: 1000 } + } + } + \endcode + + When any item is added, moved or removed within the above view, the items below it are + displaced, causing them to move down (or sideways, if horizontally orientated) within the + view. As this displacement occurs, the items' movement to their new x,y positions within + the view will be animated by a NumberAnimation over one second, as specified. + + If a view specifies this generic displaced transition as well as a specific addDisplaced, + moveDisplaced or removeDisplaced transition, the more specific transition will be used + instead of the generic displaced transition when the relevant operation occurs, providing that + the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled} + to false). If it has indeed been disabled, the generic displaced transition is applied instead. + + For more details and examples on how to use view transitions, see the ViewTransition + documentation. + + \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition +*/ + void QQuickGridView::viewportMoved() { Q_D(QQuickGridView); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 481a0d4360..600b72dfcb 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -705,6 +705,22 @@ void QQuickItemView::setRemoveDisplacedTransition(QDeclarativeTransition *transi } } +QDeclarativeTransition *QQuickItemView::displacedTransition() const +{ + Q_D(const QQuickItemView); + return d->transitioner ? d->transitioner->displacedTransition : 0; +} + +void QQuickItemView::setDisplacedTransition(QDeclarativeTransition *transition) +{ + Q_D(QQuickItemView); + d->createTransitioner(); + if (d->transitioner->displacedTransition != transition) { + d->transitioner->displacedTransition = transition; + emit displacedTransitionChanged(); + } +} + void QQuickItemViewPrivate::positionViewAtIndex(int index, int mode) { Q_Q(QQuickItemView); diff --git a/src/quick/items/qquickitemview_p.h b/src/quick/items/qquickitemview_p.h index 63262f32ab..69a3d4a0c8 100644 --- a/src/quick/items/qquickitemview_p.h +++ b/src/quick/items/qquickitemview_p.h @@ -83,6 +83,7 @@ class Q_AUTOTEST_EXPORT QQuickItemView : public QQuickFlickable Q_PROPERTY(QDeclarativeTransition *moveDisplaced READ moveDisplacedTransition WRITE setMoveDisplacedTransition NOTIFY moveDisplacedTransitionChanged) Q_PROPERTY(QDeclarativeTransition *remove READ removeTransition WRITE setRemoveTransition NOTIFY removeTransitionChanged) Q_PROPERTY(QDeclarativeTransition *removeDisplaced READ removeDisplacedTransition WRITE setRemoveDisplacedTransition NOTIFY removeDisplacedTransitionChanged) + Q_PROPERTY(QDeclarativeTransition *displaced READ displacedTransition WRITE setDisplacedTransition NOTIFY displacedTransitionChanged) Q_PROPERTY(QDeclarativeComponent *highlight READ highlight WRITE setHighlight NOTIFY highlightChanged) Q_PROPERTY(QQuickItem *highlightItem READ highlightItem NOTIFY highlightItemChanged) @@ -151,6 +152,9 @@ public: QDeclarativeTransition *removeDisplacedTransition() const; void setRemoveDisplacedTransition(QDeclarativeTransition *transition); + QDeclarativeTransition *displacedTransition() const; + void setDisplacedTransition(QDeclarativeTransition *transition); + QDeclarativeComponent *highlight() const; void setHighlight(QDeclarativeComponent *); @@ -211,6 +215,7 @@ signals: void moveDisplacedTransitionChanged(); void removeTransitionChanged(); void removeDisplacedTransitionChanged(); + void displacedTransitionChanged(); void highlightChanged(); void highlightItemChanged(); diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 3e3a99f553..0f092b76c3 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -90,13 +90,25 @@ void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickIt trans = m_transitioner->populateTransition; break; case QQuickItemViewTransitioner::AddTransition: - trans = isTargetItem ? m_transitioner->addTransition : m_transitioner->addDisplacedTransition; + if (isTargetItem) + trans = m_transitioner->addTransition; + else + trans = (m_transitioner->addDisplacedTransition && m_transitioner->addDisplacedTransition->enabled()) ? + m_transitioner->addDisplacedTransition : m_transitioner->displacedTransition; break; case QQuickItemViewTransitioner::MoveTransition: - trans = isTargetItem ? m_transitioner->moveTransition : m_transitioner->moveDisplacedTransition; + if (isTargetItem) + trans = m_transitioner->moveTransition; + else + trans = (m_transitioner->moveDisplacedTransition && m_transitioner->moveDisplacedTransition->enabled()) ? + m_transitioner->moveDisplacedTransition : m_transitioner->displacedTransition; break; case QQuickItemViewTransitioner::RemoveTransition: - trans = isTargetItem ? m_transitioner->removeTransition : m_transitioner->removeDisplacedTransition; + if (isTargetItem) + trans = m_transitioner->removeTransition; + else + trans = (m_transitioner->removeDisplacedTransition && m_transitioner->removeDisplacedTransition->enabled()) ? + m_transitioner->removeDisplacedTransition : m_transitioner->displacedTransition; break; } @@ -169,6 +181,7 @@ QQuickItemViewTransitioner::QQuickItemViewTransitioner() , addTransition(0), addDisplacedTransition(0) , moveTransition(0), moveDisplacedTransition(0) , removeTransition(0), removeDisplacedTransition(0) + , displacedTransition(0) , changeListener(0) , usePopulateTransition(false) { @@ -176,6 +189,12 @@ QQuickItemViewTransitioner::QQuickItemViewTransitioner() bool QQuickItemViewTransitioner::canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const { + if (!asTarget + && type != QQuickItemViewTransitioner::NoTransition && type != QQuickItemViewTransitioner::PopulateTransition + && displacedTransition && displacedTransition->enabled()) { + return true; + } + switch (type) { case QQuickItemViewTransitioner::NoTransition: break; @@ -428,11 +447,16 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) operations: \list - \o \c add and \c addDisplaced - the transitions to run when items are added to the view - \o \c remove and \c removeDisplaced - the transitions to run when items are removed from the view - \o \c move and \c moveDisplaced - the transitions to run when items are moved within the view - (i.e. as a result of a move operation in the model) \o \c populate - the transition to run when a view is created, or when the model changes + \o \c add - the transition to apply to items that are added to the view + \o \c remove - the transition to apply to items that are removed from the view + \o \c move - the transition to apply to items that are moved within the view (i.e. as a result + of a move operation in the model) + \o \c displaced - the generic transition to be applied to any items that are displaced by an + add, move or remove operation + \o \c addDisplaced, \c removeDisplaced and \c moveDisplaced - the transitions to be applied when + items are displaced by add, move, or remove operations, respectively (these override the + generic displaced transition if specified) \endlist Such view transitions additionally have access to a ViewTransition attached property that @@ -468,14 +492,14 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) \section2 View transitions: a simple example Here is a basic example of the use of view transitions. The view below specifies transitions for - the \c add and \c addDisplaced properties, which will be run when items are added to the view: + the \c add and \c displaced properties, which will be run when items are added to the view: \snippet doc/src/snippets/declarative/viewtransitions/viewtransitions-basic.qml 0 When the space key is pressed, adding an item to the model, the new item will fade in and increase in scale over 400 milliseconds as it is added to the view. Also, any item that is displaced by the addition of a new item will animate to its new position in the view over - 400 milliseconds, as specified by the \c addDisplaced transition. + 400 milliseconds, as specified by the \c displaced transition. If five items were inserted in succession at index 0, the effect would be this: @@ -488,7 +512,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) values if these properties are not explicitly defined. At its simplest, a view transition may just animate an item to its new position following a - view operation, just as the \c addDisplaced transition does above, or animate some item properties, + view operation, just as the \c displaced transition does above, or animate some item properties, as in the \c add transition above. Additionally, a view transition may make use of the ViewTransition attached property to customise animation behavior for different items. Following are some examples of how this can be achieved. @@ -500,9 +524,9 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) being transitioned as well as the operation that triggered the transition. In the animation above, five items are inserted in succession at index 0. When the fifth and final insertion takes place, adding "Item 4" to the view, the \c add transition is run once (for the inserted item) and the - \c addDisplaced transition is run four times (once for each of the four existing items in the view). + \c displaced transition is run four times (once for each of the four existing items in the view). - At this point, if we examined the \c addDisplaced transition that was run for the bottom displaced + At this point, if we examined the \c displaced transition that was run for the bottom displaced item ("Item 0"), the ViewTransition property values provided to this transition would be as follows: \table @@ -541,7 +565,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) So, while the ViewTransition.item, ViewTransition.index and ViewTransition.destination values vary for each individual transition that is run, the ViewTransition.targetIndexes and - ViewTransition.targetItems values are the same for every \c add and \c addDisplaced transition + ViewTransition.targetItems values are the same for every \c add and \c displaced transition that is triggered by a particular add operation. @@ -552,7 +576,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) For example, the ListView in the previous example could use this information to create a ripple-type effect on the movement of the displaced items. - This can be achieved by modifying the \c addDisplaced transition so that it delays the animation of + This can be achieved by modifying the \c displaced transition so that it delays the animation of each displaced item based on the difference between its index (provided by ViewTransition.index) and the first removed index (provided by ViewTransition.targetIndexes): @@ -570,7 +594,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) applied. This can be used to access any of the item's attributes, custom \c property values, and so on. - Below is a modification of the \c addDisplaced transition from the previous example. It adds a + Below is a modification of the \c displaced transition from the previous example. It adds a ParallelAnimation with nested NumberAnimation objects that reference ViewTransition.item to access each item's \c x and \c y values at the start of their transitions. This allows each item to animate to an intermediate position relative to its starting point for the transition, before @@ -607,7 +631,7 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) applied while the original transition is in progress. For example, say Item A is inserted at index 0 and undergoes an "add" transition; then, Item B is inserted at index 0 in quick succession before Item A's transition has finished. Since Item B is inserted before Item A, it will displace Item - A, causing the view to interrupt Item A's "add" transition mid-way and start an "addDisplaced" + A, causing the view to interrupt Item A's "add" transition mid-way and start a "displaced" transition on Item A instead. For simple animations that simply animate an item's movement to its final destination, this @@ -624,11 +648,11 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) Each newly added item undergoes an \c add transition, but before the transition can finish, another item is added, displacing the previously added item. Because of this, the \c add - transition on the previously added item is interrupted and an \c addDisplaced transition is + transition on the previously added item is interrupted and a \c displaced transition is started on the item instead. Due to the interruption, the \c opacity and \c scale animations have not completed, thus producing items with opacity and scale that are below 1.0. - To fix this, the \c addDisplaced transition should additionally ensure the item properties are + To fix this, the \c displaced transition should additionally ensure the item properties are set to the end values specified in the \c add transition, effectively resetting these values whenever an item is displaced. In this case, it means setting the item opacity and scale to 1.0: diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index c388bed17e..8dd2f86899 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -99,6 +99,7 @@ public: QDeclarativeTransition *moveDisplacedTransition; QDeclarativeTransition *removeTransition; QDeclarativeTransition *removeDisplacedTransition; + QDeclarativeTransition *displacedTransition; private: friend class QQuickItemViewTransitionJob; diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index 2190952c69..876859eeb1 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -2301,8 +2301,8 @@ void QQuickListView::setSnapMode(SnapMode mode) Whenever an item is added to the above view, the item will be animated from the position (100,100) to its final x,y position within the view, over one second. The transition only applies to the new items that are added to the view; it does not apply to the items below that are - displaced by the addition of the new items. To animate the displaced items, set the \l - addDisplaced property. + displaced by the addition of the new items. To animate the displaced items, set the \l displaced + or \l addDisplaced properties. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2338,9 +2338,10 @@ void QQuickListView::setSnapMode(SnapMode mode) the new item that has been added to the view; to animate the added items, set the \l add property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2349,7 +2350,7 @@ void QQuickListView::setSnapMode(SnapMode mode) populated, or when the view's \l model changes. In those cases, the \l populate transition is applied instead. - \sa add, populate, ViewTransition + \sa displaced, add, populate, ViewTransition */ /*! @@ -2373,7 +2374,7 @@ void QQuickListView::setSnapMode(SnapMode mode) respective items in the view will be animated to their new positions in the view over one second. The transition only applies to the items that are the subject of the move operation in the model; it does not apply to items below them that are displaced by the move operation. - To animate the displaced items, set the \l moveDisplaced property. + To animate the displaced items, set the \l displaced or \l moveDisplaced properties. For more details and examples on how to use view transitions, see the ViewTransition documentation. @@ -2406,14 +2407,15 @@ void QQuickListView::setSnapMode(SnapMode mode) the items that are the actual subjects of the move operation; to animate the moved items, set the \l move property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. - \sa move, ViewTransition + \sa displaced, move, ViewTransition */ /*! @@ -2438,8 +2440,8 @@ void QQuickListView::setSnapMode(SnapMode mode) Whenever an item is removed from the above view, the item will be animated to the position (100,100) over one second, and in parallel will also change its opacity to 0. The transition only applies to the items that are removed from the view; it does not apply to the items below - them that are displaced by the removal of the items. To animate the displaced items, set the \l - removeDisplaced property. + them that are displaced by the removal of the items. To animate the displaced items, set the + \l displaced or \l removeDisplaced properties. Note that by the time the transition is applied, the item has already been removed from the model; any references to the model data for the removed index will not be valid. @@ -2477,16 +2479,52 @@ void QQuickListView::setSnapMode(SnapMode mode) the item that has actually been removed from the view; to animate the removed items, set the \l remove property. - If an item is displaced by multiple types of operations at the same time, it is not - defined as to whether the addDisplaced, moveDisplaced or removeDisplaced transition - will be applied. + If an item is displaced by multiple types of operations at the same time, it is not defined as to + whether the addDisplaced, moveDisplaced or removeDisplaced transition will be applied. Additionally, + if it is not necessary to specify different transitions depending on whether an item is displaced + by an add, move or remove operation, consider setting the \l displaced property instead. For more details and examples on how to use view transitions, see the ViewTransition documentation. - \sa remove, ViewTransition + \sa displaced, remove, ViewTransition */ +/*! + \qmlproperty Transition QtQuick2::ListView::displaced + This property holds the generic transition to apply to items that have been displaced by + any model operation that affects the view. + + This is a convenience for specifying the generic transition to be applied to any items + that are displaced by an add, move or remove operation, without having to specify the + individual addDisplaced, moveDisplaced and removeDisplaced properties. For example, here + is a view that specifies a displaced transition: + + \code + ListView { + ... + displaced: Transition { + NumberAnimation { properties: "x,y"; duration: 1000 } + } + } + \endcode + + When any item is added, moved or removed within the above view, the items below it are + displaced, causing them to move down (or sideways, if horizontally orientated) within the + view. As this displacement occurs, the items' movement to their new x,y positions within + the view will be animated by a NumberAnimation over one second, as specified. + + If a view specifies this generic displaced transition as well as a specific addDisplaced, + moveDisplaced or removeDisplaced transition, the more specific transition will be used + instead of the generic displaced transition when the relevant operation occurs, providing that + the more specific transition has not been disabled (by setting \l {Transition::enabled}{enabled} + to false). If it has indeed been disabled, the generic displaced transition is applied instead. + + For more details and examples on how to use view transitions, see the ViewTransition + documentation. + + \sa addDisplaced, moveDisplaced, removeDisplaced, ViewTransition +*/ void QQuickListView::viewportMoved() { -- cgit v1.2.3 From 7fa6fcd30cb4a688eae744cae4abf9f263c16616 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 22 Feb 2012 18:13:29 +1000 Subject: Avoid unneccessary duplication of string data. Check for the existence of new line characters before trying to replace them. There's some redundancy if the characters are found but for single line strings we avoid the detach in replace. Change-Id: I48ccc614601a6f356b3d2e68f617e112c100bbdd Reviewed-by: Yann Bodson --- src/quick/items/qquicktext.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 28491d8f75..fd8ffe501b 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -305,9 +305,17 @@ void QQuickTextPrivate::updateLayout() formatModifiesFontSize = fontSizeModified; } else { layout.clearAdditionalFormats(); - multilengthEos = text.indexOf(QLatin1Char('\x9c')); - QString tmp = multilengthEos != -1 ? text.mid(0, multilengthEos) : text; - tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); + QString tmp = text; + multilengthEos = tmp.indexOf(QLatin1Char('\x9c')); + if (multilengthEos != -1) { + tmp = tmp.mid(0, multilengthEos); + tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); + } else if (tmp.contains(QLatin1Char('\n'))) { + // Replace always does a detach. Checking for the new line character first + // means iterating over those items again if found but prevents a realloc + // otherwise. + tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); + } layout.setText(tmp); } textHasChanged = false; -- cgit v1.2.3 From 4e0e0e5cc59a0e5379dcc1964976288d3c3e1b82 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 23 Feb 2012 13:25:58 +1000 Subject: Don't round Text dimensions. Painting issues in QtQuick1 meant drawing had to be aligned to pixel boundaries, since this is no longer a problem we should use qreal everywhere. Change-Id: I58e88e10270fa603170f1cedf471bfb53bd89b73 Reviewed-by: Yann Bodson --- src/quick/items/qquicktext.cpp | 37 +++++++++++++++++++------------------ src/quick/items/qquicktext_p_p.h | 6 +++--- 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index fd8ffe501b..656440f2d3 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -386,7 +386,7 @@ void QQuickTextPrivate::updateSize() return; } - QFontMetrics fm(font); + QFontMetricsF fm(font); if (text.isEmpty()) { qreal fontHeight = fm.height(); q->setImplicitSize(0, fontHeight); @@ -399,16 +399,16 @@ void QQuickTextPrivate::updateSize() qreal naturalWidth = 0; - int dy = q->height(); - QSize size(0, 0); - QSize previousSize = layedOutTextRect.size(); + qreal dy = q->height(); + QSizeF size(0, 0); + QSizeF previousSize = layedOutTextRect.size(); #if defined(Q_OS_MAC) layoutThread = QThread::currentThread(); #endif //setup instance of QTextLayout for all cases other than richtext if (!richText) { - QRect textRect = setupTextLayout(&naturalWidth); + QRectF textRect = setupTextLayout(&naturalWidth); layedOutTextRect = textRect; size = textRect.size(); dy -= size.height(); @@ -436,12 +436,12 @@ void QQuickTextPrivate::updateSize() 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(); - QSize dsize = doc->size().toSize(); - layedOutTextRect = QRect(QPoint(0,0), dsize); - size = QSize(int(doc->idealWidth()),dsize.height()); + dy -= doc->size().height(); + QSizeF dsize = doc->size(); + layedOutTextRect = QRectF(QPointF(0,0), dsize); + size = QSizeF(doc->idealWidth(),dsize.height()); } - int yoff = 0; + qreal yoff = 0; if (q->heightValid()) { if (vAlign == QQuickText::AlignBottom) @@ -601,13 +601,13 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, #endif } -QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine) const +QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const { if (nextLine) { nextLine->setLineWidth(INT_MAX); return layout.engine()->elidedText( Qt::TextElideMode(elideMode), - lineWidth, + QFixed::fromReal(lineWidth), 0, line.textStart(), line.textLength() + nextLine->textLength()); @@ -630,7 +630,7 @@ QString QQuickTextPrivate::elidedText(int lineWidth, const QTextLine &line, QTex already absolutely positioned horizontally). */ -QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) +QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) { Q_Q(QQuickText); layout.setCacheEnabled(true); @@ -673,8 +673,9 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) return QRect(0, 0, 0, height); } - const int lineWidth = q->widthValid() ? q->width() : INT_MAX; + const qreal lineWidth = q->widthValid() ? q->width() : FLT_MAX; const qreal maxHeight = q->heightValid() ? q->height() : FLT_MAX; + const bool customLayout = isLineLaidOutConnected(); const bool wasTruncated = truncated; @@ -783,7 +784,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) height = preLayoutHeight; elideText = layout.engine()->elidedText( Qt::TextElideMode(elideMode), - lineWidth, + QFixed::fromReal(lineWidth), 0, line.textStart(), line.textLength()); @@ -941,7 +942,7 @@ QRect QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) if (truncated != wasTruncated) emit q->truncatedChanged(); - return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height())); + return br; } void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height) @@ -1897,7 +1898,7 @@ QRectF QQuickText::boundingRect() const { Q_D(const QQuickText); - QRect rect = d->layedOutTextRect; + QRectF rect = d->layedOutTextRect; if (d->style != Normal) rect.adjust(-1, 0, 1, 2); @@ -1915,7 +1916,7 @@ QRectF QQuickText::boundingRect() const break; } - return QRectF(rect); + return rect; } /*! \internal */ diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index e060cc1cd2..d0770e6962 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -82,9 +82,9 @@ public: QTextDocument *textDocument(); bool isLineLaidOutConnected(); void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height); - QString elidedText(int lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; + QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; - QRect layedOutTextRect; + QRectF layedOutTextRect; qreal lineHeight; @@ -156,7 +156,7 @@ public: void ensureDoc(); - QRect setupTextLayout(qreal *const naturalWidth); + QRectF setupTextLayout(qreal *const naturalWidth); void setupCustomLineGeometry(QTextLine &line, qreal &height, int lineOffset = 0); bool isLinkActivatedConnected(); QString anchorAt(const QPointF &pos); -- cgit v1.2.3 From 7002ef6142250cfd7edc81f739ddafee7e71bdbf Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 28 Feb 2012 16:49:17 +1000 Subject: Make sure positioners remove change listeners for invisible items. Children that are invisble weren't having their change listeners removed, which showed illegal accesses on destruction in valgrind. Change-Id: Icae798e773168323781e9ab88b3dae6a5aea0952 Reviewed-by: Alan Alpert --- src/quick/items/qquickpositioners.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 77d2a360b8..95ee9bfb58 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -111,6 +111,8 @@ QQuickBasePositioner::~QQuickBasePositioner() Q_D(QQuickBasePositioner); for (int i = 0; i < positionedItems.count(); ++i) d->unwatchChanges(positionedItems.at(i).item); + for (int i = 0; i < unpositionedItems.count(); ++i) + d->unwatchChanges(unpositionedItems.at(i).item); positionedItems.clear(); } @@ -187,6 +189,9 @@ void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &v if (idx >= 0) { d->unwatchChanges(child); positionedItems.remove(idx); + } else if ((idx = unpositionedItems.find(posItem)) >= 0) { + d->unwatchChanges(child); + unpositionedItems.remove(idx); } d->setPositioningDirty(); } -- cgit v1.2.3 From e3a43b3ca3b1e2d6fd92945d6d7f42aed8203abc Mon Sep 17 00:00:00 2001 From: Yann Bodson Date: Fri, 24 Feb 2012 09:27:12 +1000 Subject: Reduce size of QQuickTextPrivate Move less used members to an extra struct lazily allocated Change-Id: I87e464af4b9d29303705dd7e766f734309ed7763 Reviewed-by: Andrew den Exter --- src/quick/items/qquicktext.cpp | 193 ++++++++++++++++++++++----------------- src/quick/items/qquicktext_p_p.h | 37 +++++--- 2 files changed, 130 insertions(+), 100 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 656440f2d3..f0ce26ed62 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -71,17 +71,16 @@ QT_BEGIN_NAMESPACE const QChar QQuickTextPrivate::elideChar = QChar(0x2026); QQuickTextPrivate::QQuickTextPrivate() - : lineHeight(1) - , elideLayout(0), textLine(0), doc(0) + : elideLayout(0), textLine(0) #if defined(Q_OS_MAC) , layoutThread(0), paintingThread(0) #endif , color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000) - , lineCount(1), maximumLineCount(INT_MAX), multilengthEos(-1), minimumPixelSize(12), minimumPointSize(12), nbActiveDownloads(0) - , hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone) + , lineCount(1), multilengthEos(-1) + , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop) , format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap) - , lineHeightMode(QQuickText::ProportionalHeight), style(QQuickText::Normal) - , fontSizeMode(QQuickText::FixedSize), updateType(UpdatePaintNode) + , style(QQuickText::Normal) + , updateType(UpdatePaintNode) , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false) , styledText(false), singleline(false), internalWidthUpdate(false), requireImplicitWidth(false) , truncated(false), hAlignImplicit(true), rightToLeftText(false) @@ -89,6 +88,18 @@ QQuickTextPrivate::QQuickTextPrivate() { } +QQuickTextPrivate::ExtraData::ExtraData() + : lineHeight(1.0) + , doc(0) + , minimumPixelSize(12) + , minimumPointSize(12) + , nbActiveDownloads(0) + , maximumLineCount(INT_MAX) + , lineHeightMode(QQuickText::ProportionalHeight) + , fontSizeMode(QQuickText::FixedSize) +{ +} + void QQuickTextPrivate::init() { Q_Q(QQuickText); @@ -323,10 +334,10 @@ void QQuickTextPrivate::updateLayout() } else { ensureDoc(); QTextBlockFormat::LineHeightTypes type; - type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight; + type = lineHeightMode() == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight; QTextBlockFormat blockFormat; - blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type); - for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) { + blockFormat.setLineHeight((lineHeightMode() == QQuickText::FixedHeight ? lineHeight() : lineHeight() * 100), type); + for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) { QTextCursor cursor(it); cursor.mergeBlockFormat(blockFormat); } @@ -345,13 +356,13 @@ void QQuickText::imageDownloadFinished() { Q_D(QQuickText); - (d->nbActiveDownloads)--; + (d->extra->nbActiveDownloads)--; // when all the remote images have been downloaded, // if one of the sizes was not specified at parsing time // we use the implicit size from pixmapcache and re-layout. - if (d->nbActiveDownloads == 0) { + if (d->extra.isAllocated() && d->extra->nbActiveDownloads == 0) { bool needToUpdateLayout = false; foreach (QDeclarativeStyledTextImgTag *img, d->visibleImgTags) { if (!img->size.isValid()) { @@ -415,7 +426,7 @@ void QQuickTextPrivate::updateSize() } else { singleline = false; // richtext can't elide or be optimized for single-line case ensureDoc(); - doc->setDefaultFont(font); + extra->doc->setDefaultFont(font); QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign(); if (rightToLeftText) { if (horizontalAlignment == QQuickText::AlignLeft) @@ -427,19 +438,19 @@ void QQuickTextPrivate::updateSize() option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign)); option.setWrapMode(QTextOption::WrapMode(wrapMode)); option.setUseDesignMetrics(true); - doc->setDefaultTextOption(option); + extra->doc->setDefaultTextOption(option); if (requireImplicitWidth && q->widthValid()) { - doc->setTextWidth(-1); - naturalWidth = doc->idealWidth(); + extra->doc->setTextWidth(-1); + naturalWidth = extra->doc->idealWidth(); } if (wrapMode != QQuickText::NoWrap && q->widthValid()) - doc->setTextWidth(q->width()); + extra->doc->setTextWidth(q->width()); else - doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) - dy -= doc->size().height(); - QSizeF dsize = doc->size(); + extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) + dy -= extra->doc->size().height(); + QSizeF dsize = extra->doc->size(); layedOutTextRect = QRectF(QPointF(0,0), dsize); - size = QSizeF(doc->idealWidth(),dsize.height()); + size = QSizeF(extra->doc->idealWidth(),dsize.height()); } qreal yoff = 0; @@ -581,8 +592,8 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, textLine->setWidth(q->width()); else textLine->setWidth(INT_MAX); - if (lineHeight != 1.0) - textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight); + if (lineHeight() != 1.0) + textLine->setHeight((lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight()); emit q->lineLaidOut(textLine); @@ -658,7 +669,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) // Layout to determine the implicit width. layout.beginLayout(); - for (int i = 0; i < maximumLineCount; ++i) { + for (int i = 0; i < maximumLineCount(); ++i) { QTextLine line = layout.createLine(); if (!line.isValid()) break; @@ -669,7 +680,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) } QFontMetrics fm(font); - qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight; + qreal height = (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : fm.height() * lineHeight(); return QRect(0, 0, 0, height); } @@ -686,15 +697,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) && (q->heightValid() || maximumLineCountValid); const bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid(); - const bool horizontalFit = fontSizeMode & QQuickText::HorizontalFit && q->widthValid(); - const bool verticalFit = fontSizeMode & QQuickText::VerticalFit + const bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid(); + const bool verticalFit = fontSizeMode() & QQuickText::VerticalFit && (q->heightValid() || (maximumLineCountValid && canWrap)); const bool pixelSize = font.pixelSize() != -1; QString layoutText = layout.text(); int largeFont = pixelSize ? font.pixelSize() : font.pointSize(); - int smallFont = fontSizeMode != QQuickText::FixedSize - ? qMin(pixelSize ? minimumPixelSize : minimumPointSize, largeFont) + int smallFont = fontSizeMode() != QQuickText::FixedSize + ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont) : largeFont; int scaledFontSize = largeFont; @@ -732,6 +743,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) elide = false; int characterCount = 0; int unwrappedLineCount = 1; + int maxLineCount = maximumLineCount(); height = 0; br = QRectF(); line = layout.createLine(); @@ -767,7 +779,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) line.setPosition(QPointF(FLT_MAX, FLT_MAX)); line = previousLine; --visibleCount; - height -= (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : previousLine.height() * lineHeight; + height -= (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : previousLine.height() * lineHeight(); break; } @@ -801,7 +813,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) // Stop if the maximum number of lines has been reached and elide the last line // if enabled. - if (visibleCount == maximumLineCount) { + if (visibleCount == maxLineCount) { truncated = true; characterCount = nextLine.textStart() + nextLine.textLength(); @@ -835,13 +847,13 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) if (requireImplicitWidth && characterCount < layoutText.length() - && unwrappedLineCount < maximumLineCount) { + && unwrappedLineCount < maxLineCount) { // Use a new layout to get the maximum width for the remaining text. Using a // different layout excludes the truncated text from rendering. QTextLayout widthLayout(layoutText.mid(characterCount), scaledFont); widthLayout.setTextOption(layout.textOption()); - for (; unwrappedLineCount <= maximumLineCount; ++unwrappedLineCount) { + for (; unwrappedLineCount <= maxLineCount; ++unwrappedLineCount) { QTextLine line = widthLayout.createLine(); if (!line.isValid()) break; @@ -952,7 +964,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal if (imgTags.isEmpty()) { line.setPosition(QPointF(line.position().x(), height)); - height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight; + height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : line.height() * lineHeight(); return; } @@ -971,7 +983,9 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal image->pix = new QDeclarativePixmap(qmlEngine(q), url, image->size); if (image->pix->isLoading()) { image->pix->connectFinished(q, SLOT(imageDownloadFinished())); - nbActiveDownloads++; + if (!extra.isAllocated() || !extra->nbActiveDownloads) + extra.value().nbActiveDownloads = 0; + extra->nbActiveDownloads++; } else if (image->pix->isReady()) { if (!image->size.isValid()) { image->size = image->pix->implicitSize(); @@ -1004,7 +1018,7 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal } line.setPosition(QPointF(line.position().x(), height + textTop)); - height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : totalLineHeight * lineHeight; + height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight(); } /*! @@ -1012,12 +1026,12 @@ void QQuickTextPrivate::setLineGeometry(QTextLine &line, qreal lineWidth, qreal */ void QQuickTextPrivate::ensureDoc() { - if (!doc) { + if (!extra.isAllocated() || !extra->doc) { Q_Q(QQuickText); - doc = new QQuickTextDocumentWithImageResources(q); - doc->setDocumentMargin(0); - doc->setBaseUrl(q->baseUrl()); - FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded())); + extra.value().doc = new QQuickTextDocumentWithImageResources(q); + extra->doc->setDocumentMargin(0); + extra->doc->setBaseUrl(q->baseUrl()); + FAST_CONNECT(extra->doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded())); } } @@ -1304,8 +1318,8 @@ void QQuickText::setText(const QString &n) if (isComponentComplete()) { if (d->richText) { d->ensureDoc(); - d->doc->setText(n); - d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); + d->extra->doc->setText(n); + d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { d->rightToLeftText = d->text.isRightToLeft(); } @@ -1569,11 +1583,6 @@ void QQuickTextPrivate::mirrorChange() } } -QTextDocument *QQuickTextPrivate::textDocument() -{ - return doc; -} - QQuickText::VAlignment QQuickText::vAlign() const { Q_D(const QQuickText); @@ -1666,7 +1675,7 @@ bool QQuickText::truncated() const int QQuickText::maximumLineCount() const { Q_D(const QQuickText); - return d->maximumLineCount; + return d->maximumLineCount(); } void QQuickText::setMaximumLineCount(int lines) @@ -1674,8 +1683,8 @@ void QQuickText::setMaximumLineCount(int lines) Q_D(QQuickText); d->maximumLineCountValid = lines==INT_MAX ? false : true; - if (d->maximumLineCount != lines) { - d->maximumLineCount = lines; + if (d->maximumLineCount() != lines) { + d->extra.value().maximumLineCount = lines; d->updateLayout(); emit maximumLineCountChanged(); } @@ -1777,8 +1786,8 @@ void QQuickText::setTextFormat(TextFormat format) if (isComponentComplete()) { if (!wasRich && d->richText) { d->ensureDoc(); - d->doc->setText(d->text); - d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); + d->extra->doc->setText(d->text); + d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { d->rightToLeftText = d->text.isRightToLeft(); } @@ -1831,7 +1840,7 @@ void QQuickText::setElideMode(QQuickText::TextElideMode mode) d->elideMode = mode; d->updateLayout(); - emit elideModeChanged(d->elideMode); + emit elideModeChanged(mode); } /*! @@ -1873,8 +1882,10 @@ void QQuickText::setBaseUrl(const QUrl &url) if (baseUrl() != url) { d->baseUrl = url; - if (d->doc) - d->doc->setBaseUrl(url); + if (d->richText) { + d->ensureDoc(); + d->extra->doc->setBaseUrl(url); + } if (d->styledText) { d->textHasChanged = true; qDeleteAll(d->imgTags); @@ -1933,7 +1944,7 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft; bool wrapped = d->wrapMode != QQuickText::NoWrap; bool elide = d->elideMode != QQuickText::ElideNone; - bool scaleFont = d->fontSizeMode != QQuickText::FixedSize && (widthValid() || heightValid()); + bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid()); if ((!widthChanged && !heightChanged) || d->internalWidthUpdate) goto geomChangeDone; @@ -1954,7 +1965,7 @@ void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height() && !scaleFont) { if (!d->truncated) goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher. - if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount) + if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount()) goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher. } @@ -2021,7 +2032,7 @@ QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data if (d->richText) { d->ensureDoc(); - node->addTextDocument(bounds.topLeft(), d->doc, color, d->style, styleColor, linkColor); + node->addTextDocument(bounds.topLeft(), d->extra->doc, color, d->style, styleColor, linkColor); } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) { node->addTextLayout(QPoint(0, bounds.y()), &d->layout, color, d->style, styleColor, linkColor); if (d->elideLayout) @@ -2081,17 +2092,17 @@ qreal QQuickText::contentHeight() const qreal QQuickText::lineHeight() const { Q_D(const QQuickText); - return d->lineHeight; + return d->lineHeight(); } void QQuickText::setLineHeight(qreal lineHeight) { Q_D(QQuickText); - if ((d->lineHeight == lineHeight) || (lineHeight < 0.0)) + if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0)) return; - d->lineHeight = lineHeight; + d->extra.value().lineHeight = lineHeight; d->updateLayout(); emit lineHeightChanged(lineHeight); } @@ -2111,16 +2122,16 @@ void QQuickText::setLineHeight(qreal lineHeight) QQuickText::LineHeightMode QQuickText::lineHeightMode() const { Q_D(const QQuickText); - return d->lineHeightMode; + return d->lineHeightMode(); } void QQuickText::setLineHeightMode(LineHeightMode mode) { Q_D(QQuickText); - if (mode == d->lineHeightMode) + if (mode == d->lineHeightMode()) return; - d->lineHeightMode = mode; + d->extra.value().lineHeightMode = mode; d->updateLayout(); emit lineHeightModeChanged(mode); @@ -2154,18 +2165,18 @@ void QQuickText::setLineHeightMode(LineHeightMode mode) QQuickText::FontSizeMode QQuickText::fontSizeMode() const { Q_D(const QQuickText); - return d->fontSizeMode; + return d->fontSizeMode(); } void QQuickText::setFontSizeMode(FontSizeMode mode) { Q_D(QQuickText); - if (d->fontSizeMode == mode) + if (d->fontSizeMode() == mode) return; polish(); - d->fontSizeMode = mode; + d->extra.value().fontSizeMode = mode; emit fontSizeModeChanged(); } @@ -2182,18 +2193,18 @@ void QQuickText::setFontSizeMode(FontSizeMode mode) int QQuickText::minimumPixelSize() const { Q_D(const QQuickText); - return d->minimumPixelSize; + return d->minimumPixelSize(); } void QQuickText::setMinimumPixelSize(int size) { Q_D(QQuickText); - if (d->minimumPixelSize == size) + if (d->minimumPixelSize() == size) return; - if (d->fontSizeMode != FixedSize && (widthValid() || heightValid())) + if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) polish(); - d->minimumPixelSize = size; + d->extra.value().minimumPixelSize = size; emit minimumPixelSizeChanged(); } @@ -2210,18 +2221,18 @@ void QQuickText::setMinimumPixelSize(int size) int QQuickText::minimumPointSize() const { Q_D(const QQuickText); - return d->minimumPointSize; + return d->minimumPointSize(); } void QQuickText::setMinimumPointSize(int size) { Q_D(QQuickText); - if (d->minimumPointSize == size) + if (d->minimumPointSize() == size) return; - if (d->fontSizeMode != FixedSize && (widthValid() || heightValid())) + if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) polish(); - d->minimumPointSize = size; + d->extra.value().minimumPointSize = size; emit minimumPointSizeChanged(); } @@ -2231,7 +2242,9 @@ void QQuickText::setMinimumPointSize(int size) int QQuickText::resourcesLoading() const { Q_D(const QQuickText); - return d->doc ? d->doc->resourcesLoading() : 0; + if (d->richText && d->extra.isAllocated() && d->extra->doc) + return d->extra->doc->resourcesLoading(); + return 0; } /*! \internal */ @@ -2241,8 +2254,8 @@ void QQuickText::componentComplete() if (d->updateOnComponentComplete) { if (d->richText) { d->ensureDoc(); - d->doc->setText(d->text); - d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); + d->extra->doc->setText(d->text); + d->rightToLeftText = d->extra->doc->toPlainText().isRightToLeft(); } else { d->rightToLeftText = d->text.isRightToLeft(); } @@ -2289,15 +2302,21 @@ void QQuickText::mousePressEvent(QMouseEvent *event) { Q_D(QQuickText); + QString link; if (d->isLinkActivatedConnected()) { if (d->styledText) - d->activeLink = d->anchorAt(event->localPos()); - else if (d->richText && d->doc) - d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos()); + link = d->anchorAt(event->localPos()); + else if (d->richText) { + d->ensureDoc(); + link = d->extra->doc->documentLayout()->anchorAt(event->localPos()); + } } - if (d->activeLink.isEmpty()) + if (link.isEmpty()) { event->setAccepted(false); + } else { + d->extra.value().activeLink = link; + } // ### may malfunction if two of the same links are clicked & dragged onto each other) @@ -2317,12 +2336,14 @@ void QQuickText::mouseReleaseEvent(QMouseEvent *event) if (d->isLinkActivatedConnected()) { if (d->styledText) link = d->anchorAt(event->localPos()); - else if (d->richText && d->doc) - link = d->doc->documentLayout()->anchorAt(event->localPos()); + else if (d->richText) { + d->ensureDoc(); + link = d->extra->doc->documentLayout()->anchorAt(event->localPos()); + } } - if (!link.isEmpty() && d->activeLink == link) - emit linkActivated(d->activeLink); + if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link) + emit linkActivated(d->extra->activeLink); else event->setAccepted(false); diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index d0770e6962..e61eea90ae 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -60,6 +60,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -79,17 +80,28 @@ public: bool determineHorizontalAlignment(); bool setHAlign(QQuickText::HAlignment, bool forceAlign = false); void mirrorChange(); - QTextDocument *textDocument(); bool isLineLaidOutConnected(); void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height); QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; QRectF layedOutTextRect; - qreal lineHeight; + struct ExtraData { + ExtraData(); + + qreal lineHeight; + QQuickTextDocumentWithImageResources *doc; + QString activeLink; + int minimumPixelSize; + int minimumPointSize; + int nbActiveDownloads; + int maximumLineCount; + QQuickText::LineHeightMode lineHeightMode; + QQuickText::FontSizeMode fontSizeMode; + }; + QLazilyAllocated extra; QString text; - QString activeLink; QUrl baseUrl; QFont font; QFont sourceFont; @@ -99,7 +111,6 @@ public: QTextLayout layout; QTextLayout *elideLayout; QQuickTextLine *textLine; - QQuickTextDocumentWithImageResources *doc; #if defined(Q_OS_MAC) QList linesRects; @@ -112,11 +123,7 @@ public: QRgb styleColor; int lineCount; - int maximumLineCount; int multilengthEos; - int minimumPixelSize; - int minimumPointSize; - int nbActiveDownloads; enum UpdateType { UpdateNone, @@ -124,14 +131,12 @@ public: UpdatePaintNode }; + QQuickText::TextElideMode elideMode; QQuickText::HAlignment hAlign; QQuickText::VAlignment vAlign; - QQuickText::TextElideMode elideMode; QQuickText::TextFormat format; QQuickText::WrapMode wrapMode; - QQuickText::LineHeightMode lineHeightMode; QQuickText::TextStyle style; - QQuickText::FontSizeMode fontSizeMode; UpdateType updateType; bool maximumLineCountValid:1; @@ -161,9 +166,13 @@ public: bool isLinkActivatedConnected(); QString anchorAt(const QPointF &pos); - static inline QQuickTextPrivate *get(QQuickText *t) { - return t->d_func(); - } + inline qreal lineHeight() const { return extra.isAllocated() ? extra->lineHeight : 1.0; } + inline int maximumLineCount() const { return extra.isAllocated() ? extra->maximumLineCount : INT_MAX; } + inline QQuickText::LineHeightMode lineHeightMode() const { return extra.isAllocated() ? extra->lineHeightMode : QQuickText::ProportionalHeight; } + inline QQuickText::FontSizeMode fontSizeMode() const { return extra.isAllocated() ? extra->fontSizeMode : QQuickText::FixedSize; } + inline int minimumPixelSize() const { return extra.isAllocated() ? extra->minimumPixelSize : 12; } + inline int minimumPointSize() const { return extra.isAllocated() ? extra->minimumPointSize : 12; } + static inline QQuickTextPrivate *get(QQuickText *t) { return t->d_func(); } }; class QDeclarativePixmap; -- cgit v1.2.3 From c4fa565379d82050ec0c114c6cef01474ea506ed Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 29 Feb 2012 14:37:33 +1000 Subject: Fix crash when transition finishes after view is deleted Change-Id: I5bb525bab735536fa7ae3a7f60bf775cd93cf3c1 Reviewed-by: Martin Jones --- src/quick/items/qquickitemview.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 600b72dfcb..5d58cbf4f5 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1318,6 +1318,8 @@ QQuickItemViewPrivate::QQuickItemViewPrivate() QQuickItemViewPrivate::~QQuickItemViewPrivate() { + if (transitioner) + transitioner->setChangeListener(0); delete transitioner; } -- cgit v1.2.3 From 318f15e3d379f41c2fd74d1b801586e572f3affd Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 29 Feb 2012 15:47:03 +1000 Subject: Check item before notifying transition has finished Fixes crash when using SmoothedAnimation with view transitions Change-Id: Ib9a201e417c34d64f8144a616e75cae8b67568e2 Reviewed-by: Andrew den Exter --- src/quick/items/qquickitemviewtransition.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 0f092b76c3..ea81e14871 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -163,8 +163,6 @@ void QQuickItemViewTransitionJob::finished() { QDeclarativeTransitionManager::finished(); - if (m_item) - m_item->finishedTransition(); if (m_transitioner) m_transitioner->finishedTransition(m_item); @@ -245,8 +243,11 @@ void QQuickItemViewTransitioner::transitionNextReposition(QQuickViewItem *item, void QQuickItemViewTransitioner::finishedTransition(QQuickViewItem *item) { - if (changeListener) - changeListener->viewItemTransitionFinished(item); + if (item) { + item->finishedTransition(); + if (changeListener) + changeListener->viewItemTransitionFinished(item); + } } -- cgit v1.2.3 From 6b3b47539967722ee18d072c004e96ba1acb3234 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 28 Feb 2012 17:29:40 +1000 Subject: Update item position in parent change atomically. Changing x and y individually generates two geometry changed events, the first of which has an invalid position as the x coordinate is relative to the new parent and the y relative to the old parent. This in turn causes the Drag item to send move events with incorrect positions. Task-number: QTBUG-24534 Change-Id: If2636a968acc0fffce21d1a7e51510426ace38a0 Reviewed-by: Michael Brasser --- src/quick/items/qquickstateoperations.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index c4dd0fd146..ca2a94716a 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -132,8 +132,7 @@ void QQuickParentChangePrivate::doChange(QQuickItem *targetParent, QQuickItem *s if (ok) { //qDebug() << x << y << rotation << scale; - target->setX(x); - target->setY(y); + target->setPos(QPointF(x, y)); target->setRotation(target->rotation() + rotation); target->setScale(target->scale() * scale); } -- cgit v1.2.3 From ae4c3c14e2535fbbf439c2baeb4333bbc21c2a96 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 29 Feb 2012 11:37:42 +1000 Subject: Allow styled text to be elided. Task-number: QTBUG-24521 Change-Id: Idd451d0a8a238a60691386726e34054c0368b658 Reviewed-by: Yann Bodson --- src/quick/items/qquicktext.cpp | 72 +++++++++++++++++++++++++++++++++++----- src/quick/items/qquicktext_p_p.h | 2 ++ 2 files changed, 65 insertions(+), 9 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index f0ce26ed62..6d1cc0d8d2 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -612,6 +612,22 @@ void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, #endif } +void QQuickTextPrivate::elideFormats( + const int start, const int length, int offset, QList *elidedFormats) +{ + const int end = start + length; + QList formats = layout.additionalFormats(); + for (int i = 0; i < formats.count(); ++i) { + QTextLayout::FormatRange format = formats.at(i); + const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start); + if (formatLength > 0) { + format.start = qMax(offset, format.start - start + offset); + format.length = formatLength; + elidedFormats->append(format); + } + } +} + QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine) const { if (nextLine) { @@ -624,12 +640,15 @@ QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, QT line.textLength() + nextLine->textLength()); } else { QString elideText = layout.text().mid(line.textStart(), line.textLength()); - elideText[elideText.length() - 1] = elideChar; - // Appending the elide character may push the line over the maximum width - // in which case the elided text will need to be elided. - QFontMetricsF metrics(layout.font()); - if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth) - elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth); + if (!styledText) { + // QFontMetrics won't help eliding styled text. + elideText[elideText.length() - 1] = elideChar; + // Appending the elide character may push the line over the maximum width + // in which case the elided text will need to be elided. + QFontMetricsF metrics(layout.font()); + if (metrics.width(elideChar) + line.naturalTextWidth() >= lineWidth) + elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth); + } return elideText; } } @@ -690,9 +709,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) const bool customLayout = isLineLaidOutConnected(); const bool wasTruncated = truncated; - const bool singlelineElide = !styledText && elideMode != QQuickText::ElideNone && q->widthValid(); - const bool multilineElide = !styledText - && elideMode == QQuickText::ElideRight + const bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid(); + const bool multilineElide = elideMode == QQuickText::ElideRight && q->widthValid() && (q->heightValid() || maximumLineCountValid); const bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid(); @@ -719,6 +737,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) qreal height = 0; QString elideText; bool once = true; + int elideStart = 0; + int elideEnd = 0; *naturalWidth = 0; @@ -773,6 +793,9 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator ? elidedText(lineWidth, previousLine, &line) : elidedText(lineWidth, previousLine); + elideStart = previousLine.textStart(); + // elideEnd isn't required for right eliding. + // The previous line is the last one visible so move the current one off somewhere // out of the way and back everything up one line. line.setLineWidth(0); @@ -800,6 +823,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) 0, line.textStart(), line.textLength()); + elideStart = line.textStart(); + elideEnd = elideStart + line.textLength(); } else { br = br.united(line.naturalTextRect()); } @@ -825,6 +850,8 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) elideText = wrappedLine ? elidedText(lineWidth, line, &nextLine) : elidedText(lineWidth, line); + elideStart = line.textStart(); + // elideEnd isn't required for right eliding. } else { br = br.united(line.naturalTextRect()); } @@ -917,6 +944,33 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const naturalWidth) if (elide) { if (!elideLayout) elideLayout = new QTextLayout; + if (styledText) { + QList formats; + switch (elideMode) { + case QQuickText::ElideRight: + elideFormats(elideStart, elideText.length() - 1, 0, &formats); + break; + case QQuickText::ElideLeft: + elideFormats(elideEnd - elideText.length() + 1, elideText.length() - 1, 1, &formats); + break; + case QQuickText::ElideMiddle: { + const int index = elideText.indexOf(elideChar); + if (index != -1) { + elideFormats(elideStart, index, 0, &formats); + elideFormats( + elideEnd - elideText.length() + index + 1, + elideText.length() - index - 1, + index + 1, + &formats); + } + break; + } + default: + break; + } + elideLayout->setAdditionalFormats(formats); + } + elideLayout->setFont(layout.font()); elideLayout->setTextOption(layout.textOption()); elideLayout->setText(elideText); diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h index e61eea90ae..3be62541ea 100644 --- a/src/quick/items/qquicktext_p_p.h +++ b/src/quick/items/qquicktext_p_p.h @@ -82,7 +82,9 @@ public: void mirrorChange(); bool isLineLaidOutConnected(); void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height); + QString elidedText(qreal lineWidth, const QTextLine &line, QTextLine *nextLine = 0) const; + void elideFormats(int start, int length, int offset, QList *elidedFormats); QRectF layedOutTextRect; -- cgit v1.2.3 From 5422a86b39490c30ca86a272a111c3d7da15fb3f Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 1 Mar 2012 10:40:22 +1000 Subject: No double click event in QML_TRANSLATE_TOUCH_TO_MOUSE mode Since double clicks are delivered before the click, the initial grab may not have been established. Change-Id: Id9282489f0551d421da800294e88ead0915482cc Reviewed-by: Michael Brasser --- src/quick/items/qquickcanvas.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index e6a3e87401..670baa8df7 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -378,10 +378,17 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonDblClick, p); me.setTimestamp(event->timestamp()); me.setAccepted(false); - deliverMouseEvent(&me); - if (me.isAccepted()) { - touchMouseId = p.id(); - event->setAccepted(true); + if (!mouseGrabberItem) { + if (deliverInitialMousePressEvent(rootItem, &me)) { + touchMouseId = p.id(); + event->setAccepted(true); + } + } else { + deliverMouseEvent(&me); + if (me.isAccepted()) { + touchMouseId = p.id(); + event->setAccepted(true); + } } } QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonPress, p); @@ -391,8 +398,9 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) if (me.isAccepted()) { touchMouseId = p.id(); event->setAccepted(true); - break; } + if (touchMouseId != -1) + break; } else if (p.id() == touchMouseId) { if (p.state() & Qt::TouchPointMoved) { QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseMove, p); -- cgit v1.2.3 From 3b01983d4f21cbd53745bb9132b9b2fffb019077 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 1 Mar 2012 17:37:11 +1000 Subject: Fix if transitioner is deleted before transition job finishes Don't let TransitionJob call finishedTransition() on a deleted transitioner. Also don't use target transitions that are not enabled. Change-Id: I94d58e8c7b072f7f3d76533956cac2d63ac33ff6 Reviewed-by: Alan Alpert --- src/quick/items/qquickitemviewtransition.cpp | 163 +++++++++++++++++---------- src/quick/items/qquickitemviewtransition_p.h | 10 +- 2 files changed, 111 insertions(+), 62 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index ea81e14871..9235321418 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -45,14 +45,17 @@ QT_BEGIN_NAMESPACE +static QList qquickitemviewtransition_emptyIndexes = QList(); +static QList qquickitemviewtransition_emptyTargets = QList(); + class QQuickItemViewTransitionJob : public QDeclarativeTransitionManager { public: - QQuickItemViewTransitionJob(QQuickItemViewTransitioner *transitioner); + QQuickItemViewTransitionJob(); ~QQuickItemViewTransitionJob(); - void startTransition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem); + void startTransition(QQuickViewItem *item, QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem); QQuickItemViewTransitioner *m_transitioner; QQuickViewItem *m_item; @@ -65,59 +68,41 @@ protected: }; -QQuickItemViewTransitionJob::QQuickItemViewTransitionJob(QQuickItemViewTransitioner *transitioner) - : m_transitioner(transitioner) - , m_item(0), m_type(QQuickItemViewTransitioner::NoTransition), m_isTarget(false) +QQuickItemViewTransitionJob::QQuickItemViewTransitionJob() + : m_transitioner(0) + , m_item(0) + , m_type(QQuickItemViewTransitioner::NoTransition) + , m_isTarget(false) { } QQuickItemViewTransitionJob::~QQuickItemViewTransitionJob() { + if (m_transitioner) + m_transitioner->runningJobs.remove(this); } -void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem) +void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, const QPointF &to, bool isTargetItem) { + if (type == QQuickItemViewTransitioner::NoTransition) + return; if (!item) { qWarning("startTransition(): invalid item"); return; } - - QDeclarativeTransition *trans = 0; - switch (type) { - case QQuickItemViewTransitioner::NoTransition: - break; - case QQuickItemViewTransitioner::PopulateTransition: - trans = m_transitioner->populateTransition; - break; - case QQuickItemViewTransitioner::AddTransition: - if (isTargetItem) - trans = m_transitioner->addTransition; - else - trans = (m_transitioner->addDisplacedTransition && m_transitioner->addDisplacedTransition->enabled()) ? - m_transitioner->addDisplacedTransition : m_transitioner->displacedTransition; - break; - case QQuickItemViewTransitioner::MoveTransition: - if (isTargetItem) - trans = m_transitioner->moveTransition; - else - trans = (m_transitioner->moveDisplacedTransition && m_transitioner->moveDisplacedTransition->enabled()) ? - m_transitioner->moveDisplacedTransition : m_transitioner->displacedTransition; - break; - case QQuickItemViewTransitioner::RemoveTransition: - if (isTargetItem) - trans = m_transitioner->removeTransition; - else - trans = (m_transitioner->removeDisplacedTransition && m_transitioner->removeDisplacedTransition->enabled()) ? - m_transitioner->removeDisplacedTransition : m_transitioner->displacedTransition; - break; + if (!transitioner) { + qWarning("startTransition(): invalid transitioner"); + return; } + QDeclarativeTransition *trans = transitioner->transitionObject(type, isTargetItem); if (!trans) { qWarning("QQuickItemView: invalid view transition!"); return; } m_item = item; + m_transitioner = transitioner; m_toPos = to; m_type = type; m_isTarget = isTargetItem; @@ -128,23 +113,8 @@ void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickIt attached->m_index = item->index; attached->m_item = item->item; attached->m_destination = to; - switch (type) { - case QQuickItemViewTransitioner::NoTransition: - break; - case QQuickItemViewTransitioner::PopulateTransition: - case QQuickItemViewTransitioner::AddTransition: - attached->m_targetIndexes = m_transitioner->addTransitionIndexes; - attached->m_targetItems = m_transitioner->addTransitionTargets; - break; - case QQuickItemViewTransitioner::MoveTransition: - attached->m_targetIndexes = m_transitioner->moveTransitionIndexes; - attached->m_targetItems = m_transitioner->moveTransitionTargets; - break; - case QQuickItemViewTransitioner::RemoveTransition: - attached->m_targetIndexes = m_transitioner->removeTransitionIndexes; - attached->m_targetItems = m_transitioner->removeTransitionTargets; - break; - } + attached->m_targetIndexes = m_transitioner->targetIndexes(type); + attached->m_targetItems = m_transitioner->targetItems(type); emit attached->indexChanged(); emit attached->itemChanged(); emit attached->destinationChanged(); @@ -156,6 +126,7 @@ void QQuickItemViewTransitionJob::startTransition(QQuickViewItem *item, QQuickIt actions << QDeclarativeAction(item->item, QLatin1String("x"), QVariant(to.x())); actions << QDeclarativeAction(item->item, QLatin1String("y"), QVariant(to.y())); + m_transitioner->runningJobs << this; QDeclarativeTransitionManager::transition(actions, trans, item->item); } @@ -164,7 +135,7 @@ void QQuickItemViewTransitionJob::finished() QDeclarativeTransitionManager::finished(); if (m_transitioner) - m_transitioner->finishedTransition(m_item); + m_transitioner->finishedTransition(this, m_item); m_item = 0; m_toPos.setX(0); @@ -185,6 +156,12 @@ QQuickItemViewTransitioner::QQuickItemViewTransitioner() { } +QQuickItemViewTransitioner::~QQuickItemViewTransitioner() +{ + for (QSet::iterator it = runningJobs.begin(); it != runningJobs.end(); ++it) + (*it)->m_transitioner = 0; +} + bool QQuickItemViewTransitioner::canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const { if (!asTarget @@ -241,8 +218,78 @@ void QQuickItemViewTransitioner::transitionNextReposition(QQuickViewItem *item, } } -void QQuickItemViewTransitioner::finishedTransition(QQuickViewItem *item) +QDeclarativeTransition *QQuickItemViewTransitioner::transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget) { + if (type == QQuickItemViewTransitioner::NoTransition) + return 0; + + if (type == PopulateTransition) + asTarget = true; // no separate displaced transition + + QDeclarativeTransition *trans = 0; + switch (type) { + case NoTransition: + break; + case PopulateTransition: + trans = populateTransition; + break; + case AddTransition: + trans = asTarget ? addTransition : addDisplacedTransition; + break; + case MoveTransition: + trans = asTarget ? moveTransition : moveDisplacedTransition; + break; + case RemoveTransition: + trans = asTarget ? removeTransition : removeDisplacedTransition; + break; + } + + if (!asTarget && (!trans || !trans->enabled())) + trans = displacedTransition; + if (trans && trans->enabled()) + return trans; + return 0; +} + +const QList &QQuickItemViewTransitioner::targetIndexes(QQuickItemViewTransitioner::TransitionType type) const +{ + switch (type) { + case QQuickItemViewTransitioner::NoTransition: + break; + case QQuickItemViewTransitioner::PopulateTransition: + case QQuickItemViewTransitioner::AddTransition: + return addTransitionIndexes; + case QQuickItemViewTransitioner::MoveTransition: + return moveTransitionIndexes; + case QQuickItemViewTransitioner::RemoveTransition: + return removeTransitionIndexes; + } + + return qquickitemviewtransition_emptyIndexes; +} + +const QList &QQuickItemViewTransitioner::targetItems(QQuickItemViewTransitioner::TransitionType type) const +{ + switch (type) { + case QQuickItemViewTransitioner::NoTransition: + break; + case QQuickItemViewTransitioner::PopulateTransition: + case QQuickItemViewTransitioner::AddTransition: + return addTransitionTargets; + case QQuickItemViewTransitioner::MoveTransition: + return moveTransitionTargets; + case QQuickItemViewTransitioner::RemoveTransition: + return removeTransitionTargets; + } + + return qquickitemviewtransition_emptyTargets; +} + +void QQuickItemViewTransitioner::finishedTransition(QQuickItemViewTransitionJob *job, QQuickViewItem *item) +{ + if (!runningJobs.contains(job)) + return; + runningJobs.remove(job); if (item) { item->finishedTransition(); if (changeListener) @@ -263,10 +310,6 @@ QQuickViewItem::QQuickViewItem(QQuickItem *i) QQuickViewItem::~QQuickViewItem() { - if (transition) { - transition->m_item = 0; - transition->m_transitioner = 0; - } delete transition; } @@ -385,7 +428,7 @@ void QQuickViewItem::startTransition(QQuickItemViewTransitioner *transitioner) if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) { delete transition; - transition = new QQuickItemViewTransitionJob(transitioner); + transition = new QQuickItemViewTransitionJob; } // if item is not already moving somewhere, set it to not move anywhere @@ -393,7 +436,7 @@ void QQuickViewItem::startTransition(QQuickItemViewTransitioner *transitioner) if (!nextTransitionToSet) moveTo(item->pos()); - transition->startTransition(this, nextTransitionType, nextTransitionTo, isTransitionTarget); + transition->startTransition(this, transitioner, nextTransitionType, nextTransitionTo, isTransitionTarget); nextTransitionType = QQuickItemViewTransitioner::NoTransition; } diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 8dd2f86899..1ebc52c185 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -77,14 +77,20 @@ public: }; QQuickItemViewTransitioner(); - virtual ~QQuickItemViewTransitioner() {} + virtual ~QQuickItemViewTransitioner(); bool canTransition(QQuickItemViewTransitioner::TransitionType type, bool asTarget) const; void transitionNextReposition(QQuickViewItem *item, QQuickItemViewTransitioner::TransitionType type, bool isTarget); + QDeclarativeTransition *transitionObject(QQuickItemViewTransitioner::TransitionType type, bool asTarget); + const QList &targetIndexes(QQuickItemViewTransitioner::TransitionType type) const; + const QList &targetItems(QQuickItemViewTransitioner::TransitionType type) const; + inline void setPopulateTransitionEnabled(bool b) { usePopulateTransition = b; } inline void setChangeListener(QQuickItemViewTransitionChangeListener *obj) { changeListener = obj; } + QSet runningJobs; + QList addTransitionIndexes; QList moveTransitionIndexes; QList removeTransitionIndexes; @@ -107,7 +113,7 @@ private: QQuickItemViewTransitionChangeListener *changeListener; bool usePopulateTransition; - void finishedTransition(QQuickViewItem *item); + void finishedTransition(QQuickItemViewTransitionJob *job, QQuickViewItem *item); }; -- cgit v1.2.3 From 79608d6f72ea5963aed2fa161b9ef6781adbc41e Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 27 Feb 2012 13:16:11 +1000 Subject: Improved transitions for Row, Column, Grid, Flow The view transitions functionality for ListView and GridView has been integrated into the positioner elements. Not all of this functionality is available for positioners, though, since they don't have models (and thus cannot identify certain model operations) and they don't manage the lifetime of their children. Task-number: QTBUG-24336 Change-Id: I71588de289555d2ef5a763af11358bc0af7b31a7 Reviewed-by: Alan Alpert --- src/quick/items/qquickitemviewtransition.cpp | 34 ++- src/quick/items/qquickpositioners.cpp | 370 +++++++++++++++------------ src/quick/items/qquickpositioners_p.h | 16 +- src/quick/items/qquickpositioners_p_p.h | 11 +- 4 files changed, 250 insertions(+), 181 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index 9235321418..abff768ad3 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -377,6 +377,12 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) { bool doTransition = false; + // If item is not already moving somewhere, set it to not move anywhere. + // This ensures that removed targets don't transition to the default (0,0) and that + // items set for other transition types only transition if they actually move somewhere. + if (nextTransitionType != QQuickItemViewTransitioner::NoTransition && !nextTransitionToSet) + moveTo(item->pos()); + switch (nextTransitionType) { case QQuickItemViewTransitioner::NoTransition: { @@ -390,7 +396,12 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) case QQuickItemViewTransitioner::RemoveTransition: // For Add targets, do transition if item is moving into visible area // For Remove targets, do transition if item is currently in visible area - if (isTransitionTarget) { + if (viewBounds.isNull()) { + if (isTransitionTarget) + doTransition = true; + else + doTransition = (nextTransitionTo != item->pos()); + } else if (isTransitionTarget) { doTransition = (nextTransitionType == QQuickItemViewTransitioner::AddTransition) ? viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())) : viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())); @@ -408,7 +419,8 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) case QQuickItemViewTransitioner::MoveTransition: // do transition if moving from or into visible area if (nextTransitionTo != item->pos()) { - doTransition = viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) + doTransition = viewBounds.isNull() + || viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())); if (!doTransition) item->setPos(nextTransitionTo); @@ -503,7 +515,19 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) generic displaced transition if specified) \endlist - Such view transitions additionally have access to a ViewTransition attached property that + For the \l Row, \l Column, \l Grid and \l Flow positioner elements, which operate with collections of child + items rather than data models, the following properties are used instead: + + \list + \o \c add - the transition to apply to items that are created for the positioner, added to + or reparented to the positioner, or items that have become \l {Item::}{visible} + \o \c move - the transition to apply to items that have moved within the positioner, including + when they are displaced due to the addition or removal of other items, or when items are otherwise + rearranged within the positioner, or when items are repositioned due to the resizing of other + items in the positioner + \endlist + + View transitions have access to a ViewTransition attached property that provides details of the items that are under transition and the operation that triggered the transition. Since view transitions are run once per item, these details can be used to customise each transition for each individual item. @@ -525,6 +549,10 @@ QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent) \o ViewTransition.targetItems - the target items themselves \endlist + (Note that for the \l Row, \l Column, \l Grid and \l Flow positioner elements, the \c move transition only + provides these two additional details when the transition is triggered by the addition of items + to a positioner.) + View transitions can be written without referring to any of the attributes listed above. These attributes merely provide extra details that are useful for customising view transitions. diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp index 95ee9bfb58..6ed35a9f42 100644 --- a/src/quick/items/qquickpositioners.cpp +++ b/src/quick/items/qquickpositioners.cpp @@ -109,6 +109,7 @@ QQuickBasePositioner::QQuickBasePositioner(QQuickBasePositionerPrivate &dd, Posi QQuickBasePositioner::~QQuickBasePositioner() { Q_D(QQuickBasePositioner); + delete d->transitioner; for (int i = 0; i < positionedItems.count(); ++i) d->unwatchChanges(positionedItems.at(i).item); for (int i = 0; i < unpositionedItems.count(); ++i) @@ -142,31 +143,36 @@ void QQuickBasePositioner::setSpacing(qreal s) QDeclarativeTransition *QQuickBasePositioner::move() const { Q_D(const QQuickBasePositioner); - return d->moveTransition; + return d->transitioner ? d->transitioner->displacedTransition : 0; } void QQuickBasePositioner::setMove(QDeclarativeTransition *mt) { Q_D(QQuickBasePositioner); - if (mt == d->moveTransition) + if (!d->transitioner) + d->transitioner = new QQuickItemViewTransitioner; + if (mt == d->transitioner->displacedTransition) return; - d->moveTransition = mt; + + d->transitioner->displacedTransition = mt; emit moveChanged(); } QDeclarativeTransition *QQuickBasePositioner::add() const { Q_D(const QQuickBasePositioner); - return d->addTransition; + return d->transitioner ? d->transitioner->addTransition : 0; } void QQuickBasePositioner::setAdd(QDeclarativeTransition *add) { Q_D(QQuickBasePositioner); - if (add == d->addTransition) + if (!d->transitioner) + d->transitioner = new QQuickItemViewTransitioner; + if (add == d->transitioner->addTransition) return; - d->addTransition = add; + d->transitioner->addTransition = add; emit addChanged(); } @@ -218,6 +224,7 @@ void QQuickBasePositioner::prePositioning() for (int ii = 0; ii < unpositionedItems.count(); ii++) oldItems.append(unpositionedItems[ii]); unpositionedItems.clear(); + int addedIndex = -1; for (int ii = 0; ii < children.count(); ++ii) { QQuickItem *child = children.at(ii); @@ -229,9 +236,22 @@ void QQuickBasePositioner::prePositioning() posItem.isNew = true; if (!childPrivate->explicitVisible || !child->width() || !child->height()) { posItem.isVisible = false; + posItem.index = -1; unpositionedItems.append(posItem); } else { + posItem.index = positionedItems.count(); positionedItems.append(posItem); + + if (d->transitioner) { + if (addedIndex < 0) + addedIndex = posItem.index; + PositionedItem *theItem = &positionedItems[positionedItems.count()-1]; + + d->transitioner->transitionNextReposition(theItem, + QQuickItemViewTransitioner::AddTransition, true); + d->transitioner->addTransitionIndexes << posItem.index; + d->transitioner->addTransitionTargets << posItem.item; + } } } else { PositionedItem *item = &oldItems[wIdx]; @@ -239,75 +259,93 @@ void QQuickBasePositioner::prePositioning() // i.e. their positioning is not affected if an ancestor is hidden. if (!childPrivate->explicitVisible || !child->width() || !child->height()) { item->isVisible = false; + item->index = -1; unpositionedItems.append(*item); } else if (!item->isVisible) { + // item changed from non-visible to visible, treat it as a "new" item item->isVisible = true; item->isNew = true; + item->index = positionedItems.count(); positionedItems.append(*item); + + if (d->transitioner) { + if (addedIndex < 0) + addedIndex = item->index; + d->transitioner->transitionNextReposition(&positionedItems[positionedItems.count()-1], + QQuickItemViewTransitioner::AddTransition, true); + d->transitioner->addTransitionIndexes << item->index; + d->transitioner->addTransitionTargets << item->item; + } } else { item->isNew = false; + item->index = positionedItems.count(); positionedItems.append(*item); } } } + + if (d->transitioner) { + for (int i=0; i= 0) { + d->transitioner->transitionNextReposition(&positionedItems[i], QQuickItemViewTransitioner::AddTransition, false); + } else { + // just queue the item for a move-type displace - if the item hasn't + // moved anywhere, it won't be transitioned anyway + d->transitioner->transitionNextReposition(&positionedItems[i], QQuickItemViewTransitioner::MoveTransition, false); + } + } + } + } + QSizeF contentSize(0,0); reportConflictingAnchors(); if (!d->anchorConflict) { doPositioning(&contentSize); updateAttachedProperties(); } - if (!d->addActions.isEmpty() || !d->moveActions.isEmpty()) - finishApplyTransitions(); + + if (d->transitioner) { + QRectF viewBounds; + for (int i=0; itransitioner); + } + d->transitioner->addTransitionIndexes.clear(); + d->transitioner->addTransitionTargets.clear(); + } + d->doingPositioning = false; + //Set implicit size to the size of its children setImplicitSize(contentSize.width(), contentSize.height()); } -void QQuickBasePositioner::positionX(qreal x, const PositionedItem &target) +void QQuickBasePositioner::positionItem(qreal x, qreal y, PositionedItem *target) { Q_D(QQuickBasePositioner); - if (d->type == Horizontal || d->type == Both) { - if (target.isNew) { - if (!d->addTransition || !d->addTransition->enabled()) - target.item->setX(x); - else - d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x)); - } else if (x != target.item->x()) { - if (!d->moveTransition || !d->moveTransition->enabled()) - target.item->setX(x); - else - d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x)); - } + if ( (target->itemX() != x || target->itemY() != y) + && d->type == Both) { + target->moveTo(QPointF(x, y)); } } -void QQuickBasePositioner::positionY(qreal y, const PositionedItem &target) +void QQuickBasePositioner::positionItemX(qreal x, PositionedItem *target) { Q_D(QQuickBasePositioner); - if (d->type == Vertical || d->type == Both) { - if (target.isNew) { - if (!d->addTransition || !d->addTransition->enabled()) - target.item->setY(y); - else - d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y)); - } else if (y != target.item->y()) { - if (!d->moveTransition || !d->moveTransition->enabled()) - target.item->setY(y); - else - d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y)); - } + if (target->itemX() != x + && (d->type == Horizontal || d->type == Both)) { + target->moveTo(QPointF(x, target->itemY())); } } -void QQuickBasePositioner::finishApplyTransitions() +void QQuickBasePositioner::positionItemY(qreal y, PositionedItem *target) { Q_D(QQuickBasePositioner); - // Note that if a transition is not set the transition manager will - // apply the changes directly, in the case add/move aren't set - d->addTransitionManager.transition(d->addActions, d->addTransition); - d->moveTransitionManager.transition(d->moveActions, d->moveTransition); - d->addActions.clear(); - d->moveActions.clear(); + if (target->itemY() != y + && (d->type == Vertical || d->type == Both)) { + target->moveTo(QPointF(target->itemX(), y)); + } } QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj) @@ -501,30 +539,42 @@ void QQuickPositionerAttached::setIsLastItem(bool isLastItem) /*! \qmlproperty Transition QtQuick2::Column::add - This property holds the transition to be applied when adding an - item to the positioner. The transition will only be applied to the - added item(s). Positioner transitions will only affect the - position (x, y) of items. + This property holds the transition to be run for items that are added to this + positioner. For a positioner, this applies to: + + \list + \o Items that are created or reparented as a child of the positioner + \o Child items that change their \l visible property from false to true, and thus + are now visible + \endlist - For a positioner, adding an item can mean that either the object - has been created or reparented, and thus is now a child or the - positioner, or that the object has changed its \l visible property - from false to true, and thus is now visible. + The transition can use the \l ViewTransition property to access more details about + the item that is being added. See the \l ViewTransition documentation for more details + and examples on using these transitions. - \sa move + \sa move, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition QtQuick2::Column::move - This property holds the transition to apply to any item that has moved - within the positioner. Positioner transitions will only affect - the position (x, y) of items. + This property holds the transition to run for items that have moved within the + positioner. For a positioner, this applies to: - This transition is applied to items that are displaced as a result of the - addition or removal of other items in the positioner, or when items move due to - a move operation in a related model, or when items resize themselves. + \list + \o Child items that move when they are displaced due to the addition, removal or + rearrangement of other items in the positioner + \o Child items that are repositioned due to the resizing of other items in the positioner + \endlist + + The transition can use the \l ViewTransition property to access more details about + the item that is being moved. Note, however, that for this move transition, the + ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when + this transition is triggered by the addition of other items in the positioner; in other + cases, these lists will be empty. + + See the \l ViewTransition documentation for more details and examples on using these transitions. - \sa add, {declarative/positioners}{Positioners example} + \sa add, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty real QtQuick2::Column::spacing @@ -545,11 +595,8 @@ void QQuickColumn::doPositioning(QSizeF *contentSize) qreal voffset = 0; for (int ii = 0; ii < positionedItems.count(); ++ii) { - const PositionedItem &child = positionedItems.at(ii); - - if (child.item->y() != voffset) - positionY(voffset, child); - + PositionedItem &child = positionedItems[ii]; + positionItemY(voffset, &child); contentSize->setWidth(qMax(contentSize->width(), child.item->width())); voffset += child.item->height(); @@ -625,42 +672,42 @@ void QQuickColumn::reportConflictingAnchors() /*! \qmlproperty Transition QtQuick2::Row::add - This property holds the transition to be applied when adding an - item to the positioner. The transition will only be applied to the - added item(s). Positioner transitions will only affect the - position (x, y) of items. + This property holds the transition to be run for items that are added to this + positioner. For a positioner, this applies to: - For a positioner, adding an item can mean that either the object - has been created or reparented, and thus is now a child or the - positioner, or that the object has changed its \l visible property - from false to true, and thus is now visible. + \list + \o Items that are created or reparented as a child of the positioner + \o Child items that change their \l visible property from false to true, and thus + are now visible + \endlist + + The transition can use the \l ViewTransition property to access more details about + the item that is being added. See the \l ViewTransition documentation for more details + and examples on using these transitions. - \sa move + \sa move, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition QtQuick2::Row::move - This property holds the transition to apply to any item that has moved - within the positioner. Positioner transitions will only affect - the position (x, y) of items. - - This transition is applied to items that are displaced as a result of the - addition or removal of other items in the positioner, or when items move due to - a move operation in a related model, or when items resize themselves. - - \qml - Row { - id: positioner - move: Transition { - NumberAnimation { - properties: "x" - duration: 1000 - } - } - } - \endqml + This property holds the transition to run for items that have moved within the + positioner. For a positioner, this applies to: + + \list + \o Child items that move when they are displaced due to the addition, removal or + rearrangement of other items in the positioner + \o Child items that are repositioned due to the resizing of other items in the positioner + \endlist + + The transition can use the \l ViewTransition property to access more details about + the item that is being moved. Note, however, that for this move transition, the + ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when + this transition is triggered by the addition of other items in the positioner; in other + cases, these lists will be empty. - \sa add, {declarative/positioners}{Positioners example} + See the \l ViewTransition documentation for more details and examples on using these transitions. + + \sa add, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty real QtQuick2::Row::spacing @@ -736,11 +783,10 @@ void QQuickRow::doPositioning(QSizeF *contentSize) QList hoffsets; for (int ii = 0; ii < positionedItems.count(); ++ii) { - const PositionedItem &child = positionedItems.at(ii); + PositionedItem &child = positionedItems[ii]; if (d->isLeftToRight()) { - if (child.item->x() != hoffset) - positionX(hoffset, child); + positionItemX(hoffset, &child); } else { hoffsets << hoffset; } @@ -767,10 +813,9 @@ void QQuickRow::doPositioning(QSizeF *contentSize) int acc = 0; for (int ii = 0; ii < positionedItems.count(); ++ii) { - const PositionedItem &child = positionedItems.at(ii); + PositionedItem &child = positionedItems[ii]; hoffset = end - hoffsets[acc++] - child.item->width(); - if (child.item->x() != hoffset) - positionX(hoffset, child); + positionItemX(hoffset, &child); } } @@ -839,41 +884,42 @@ void QQuickRow::reportConflictingAnchors() /*! \qmlproperty Transition QtQuick2::Grid::add - This property holds the transition to be applied when adding an - item to the positioner. The transition will only be applied to the - added item(s). Positioner transitions will only affect the - position (x, y) of items. + This property holds the transition to be run for items that are added to this + positioner. For a positioner, this applies to: + + \list + \o Items that are created or reparented as a child of the positioner + \o Child items that change their \l visible property from false to true, and thus + are now visible + \endlist - For a positioner, adding an item can mean that either the object - has been created or reparented, and thus is now a child or the - positioner, or that the object has changed its \l visible property - from false to true, and thus is now visible. + The transition can use the \l ViewTransition property to access more details about + the item that is being added. See the \l ViewTransition documentation for more details + and examples on using these transitions. - \sa move + \sa move, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition QtQuick2::Grid::move - This property holds the transition to apply to any item that has moved - within the positioner. Positioner transitions will only affect - the position (x, y) of items. + This property holds the transition to run for items that have moved within the + positioner. For a positioner, this applies to: + + \list + \o Child items that move when they are displaced due to the addition, removal or + rearrangement of other items in the positioner + \o Child items that are repositioned due to the resizing of other items in the positioner + \endlist - This transition is applied to items that are displaced as a result of the - addition or removal of other items in the positioner, or when items move due to - a move operation in a related model, or when items resize themselves. + The transition can use the \l ViewTransition property to access more details about + the item that is being moved. Note, however, that for this move transition, the + ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when + this transition is triggered by the addition of other items in the positioner; in other + cases, these lists will be empty. - \qml - Grid { - move: Transition { - NumberAnimation { - properties: "x,y" - duration: 1000 - } - } - } - \endqml + See the \l ViewTransition documentation for more details and examples on using these transitions. - \sa add, {declarative/positioners}{Positioners example} + \sa add, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty qreal QtQuick2::Grid::spacing @@ -1160,14 +1206,11 @@ void QQuickGrid::doPositioning(QSizeF *contentSize) int curRow =0; int curCol =0; for (int i = 0; i < positionedItems.count(); ++i) { - const PositionedItem &child = positionedItems.at(i); + PositionedItem &child = positionedItems[i]; qreal childXOffset = xoffset; if (!d->isLeftToRight()) childXOffset -= child.item->width(); - if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)) { - positionX(childXOffset, child); - positionY(yoffset, child); - } + positionItem(childXOffset, yoffset, &child); if (m_flow == LeftToRight) { if (d->isLeftToRight()) @@ -1254,42 +1297,42 @@ void QQuickGrid::reportConflictingAnchors() /*! \qmlproperty Transition QtQuick2::Flow::add - This property holds the transition to be applied when adding an - item to the positioner. The transition will only be applied to the - added item(s). Positioner transitions will only affect the - position (x, y) of items. + This property holds the transition to be run for items that are added to this + positioner. For a positioner, this applies to: + + \list + \o Items that are created or reparented as a child of the positioner + \o Child items that change their \l visible property from false to true, and thus + are now visible + \endlist - For a positioner, adding an item can mean that either the object - has been created or reparented, and thus is now a child or the - positioner, or that the object has changed its \l visible property - from false to true, and thus is now visible. + The transition can use the \l ViewTransition property to access more details about + the item that is being added. See the \l ViewTransition documentation for more details + and examples on using these transitions. - \sa move + \sa move, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition QtQuick2::Flow::move - This property holds the transition to apply to any item that has moved - within the positioner. Positioner transitions will only affect - the position (x, y) of items. - - This transition is applied to items that are displaced as a result of the - addition or removal of other items in the positioner, or when items move due to - a move operation in a related model, or when items resize themselves. - - \qml - Flow { - id: positioner - move: Transition { - NumberAnimation { - properties: "x,y" - ease: "easeOutBounce" - } - } - } - \endqml + This property holds the transition to run for items that have moved within the + positioner. For a positioner, this applies to: + + \list + \o Child items that move when they are displaced due to the addition, removal or + rearrangement of other items in the positioner + \o Child items that are repositioned due to the resizing of other items in the positioner + \endlist + + The transition can use the \l ViewTransition property to access more details about + the item that is being moved. Note, however, that for this move transition, the + ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when + this transition is triggered by the addition of other items in the positioner; in other + cases, these lists will be empty. + + See the \l ViewTransition documentation for more details and examples on using these transitions. - \sa add, {declarative/positioners}{Positioners example} + \sa add, ViewTransition, {declarative/positioners}{Positioners example} */ /*! \qmlproperty real QtQuick2::Flow::spacing @@ -1414,7 +1457,7 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) QList hoffsets; for (int i = 0; i < positionedItems.count(); ++i) { - const PositionedItem &child = positionedItems.at(i); + PositionedItem &child = positionedItems[i]; if (d->flow == LeftToRight) { if (widthValid() && hoffset && hoffset + child.item->width() > width()) { @@ -1431,13 +1474,11 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) } if (d->isLeftToRight()) { - if (child.item->x() != hoffset) - positionX(hoffset, child); + positionItem(hoffset, voffset, &child); } else { hoffsets << hoffset; + positionItemY(voffset, &child); } - if (child.item->y() != voffset) - positionY(voffset, child); contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width())); contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height())); @@ -1462,10 +1503,9 @@ void QQuickFlow::doPositioning(QSizeF *contentSize) end = contentSize->width(); int acc = 0; for (int i = 0; i < positionedItems.count(); ++i) { - const PositionedItem &child = positionedItems.at(i); + PositionedItem &child = positionedItems[i]; hoffset = end - hoffsets[acc++] - child.item->width(); - if (child.item->x() != hoffset) - positionX(hoffset, child); + positionItemX(hoffset, &child); } } diff --git a/src/quick/items/qquickpositioners_p.h b/src/quick/items/qquickpositioners_p.h index a4f18cfc21..32dd9030fe 100644 --- a/src/quick/items/qquickpositioners_p.h +++ b/src/quick/items/qquickpositioners_p.h @@ -43,6 +43,7 @@ #define QQUICKPOSITIONERS_P_H #include "qquickimplicitsizeitem_p.h" +#include "qquickitemviewtransition_p.h" #include #include @@ -96,6 +97,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickBasePositioner : public QQuickImplicitSizeIte Q_PROPERTY(QDeclarativeTransition *add READ add WRITE setAdd NOTIFY addChanged) public: enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 }; + QQuickBasePositioner(PositionerType, QQuickItem *parent); ~QQuickBasePositioner(); @@ -116,7 +118,6 @@ protected: QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent); virtual void componentComplete(); virtual void itemChange(ItemChange, const ItemChangeData &); - void finishApplyTransitions(); virtual void updatePolish(); @@ -131,19 +132,22 @@ protected Q_SLOTS: protected: virtual void doPositioning(QSizeF *contentSize)=0; virtual void reportConflictingAnchors()=0; - class PositionedItem { + + class PositionedItem : public QQuickViewItem + { public : - PositionedItem(QQuickItem *i) : item(i), isNew(false), isVisible(true) {} + PositionedItem(QQuickItem *i) : QQuickViewItem(i), isNew(false), isVisible(true) {} bool operator==(const PositionedItem &other) const { return other.item == item; } - QQuickItem *item; + bool isNew; bool isVisible; }; QPODVector positionedItems; QPODVector unpositionedItems;//Still 'in' the positioner, just not positioned - void positionX(qreal,const PositionedItem &target); - void positionY(qreal,const PositionedItem &target); + void positionItem(qreal x, qreal y, PositionedItem *target); + void positionItemX(qreal, PositionedItem *target); + void positionItemY(qreal, PositionedItem *target); private: Q_DISABLE_COPY(QQuickBasePositioner) diff --git a/src/quick/items/qquickpositioners_p_p.h b/src/quick/items/qquickpositioners_p_p.h index d281f1a372..f1d174dc0a 100644 --- a/src/quick/items/qquickpositioners_p_p.h +++ b/src/quick/items/qquickpositioners_p_p.h @@ -66,6 +66,8 @@ QT_BEGIN_NAMESPACE +class QQuickItemViewTransitioner; + class QQuickBasePositionerPrivate : public QQuickImplicitSizeItemPrivate, public QQuickItemChangeListener { Q_DECLARE_PUBLIC(QQuickBasePositioner) @@ -73,7 +75,7 @@ class QQuickBasePositionerPrivate : public QQuickImplicitSizeItemPrivate, public public: QQuickBasePositionerPrivate() : spacing(0), type(QQuickBasePositioner::None) - , moveTransition(0), addTransition(0), positioningDirty(false) + , transitioner(0), positioningDirty(false) , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) { } @@ -87,12 +89,7 @@ public: qreal spacing; QQuickBasePositioner::PositionerType type; - QDeclarativeTransition *moveTransition; - QDeclarativeTransition *addTransition; - QDeclarativeStateOperation::ActionList addActions; - QDeclarativeStateOperation::ActionList moveActions; - QDeclarativeTransitionManager addTransitionManager; - QDeclarativeTransitionManager moveTransitionManager; + QQuickItemViewTransitioner *transitioner; void watchChanges(QQuickItem *other); void unwatchChanges(QQuickItem* other); -- cgit v1.2.3 From 3c42ca87fac3326bb86a8bb816de07223b7b2e9d Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Fri, 2 Mar 2012 10:36:10 +1000 Subject: Treat parentless items as focus scopes The root item of a tree is implicitly a focus scope simply because it is the root of the tree. QQuickRootItem could gain the focus scope flag in order to solve this for most cases, but there would still be a possiblity of a crash for disconnected trees. Change-Id: I6e04f11df4268fb3b96660d50707d70935a5dc5e Reviewed-by: Martin Jones --- src/quick/items/qquickitem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 04f4c1f801..7ca683fac3 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2121,7 +2121,7 @@ QQuickItem *QQuickItemPrivate::InitializationState::getFocusScope(QQuickItem *it { if (!focusScope) { QQuickItem *fs = item->parentItem(); - while (!fs->isFocusScope()) + while (fs->parentItem() && !fs->isFocusScope()) fs = fs->parentItem(); focusScope = fs; } -- cgit v1.2.3 From 82a252afdd0f920357b1e543f2ee97f92c34919b Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 1 Mar 2012 13:45:29 +0200 Subject: Use velocity from touch events only when they are valid Add the capability flags to the extended mouse events. Otherwise it is not possible to tell if the velocity is valid. While the original version is fine if velocity is guaranteed to be available whenever QT_TRANSLATE_TOUCH_TO_MOUSE is set, some platform and driver combinations, e.g. the evdevtouch plugin that comes with Qt, do not provide velocity data in touch events. The touch-only mode of QML may be very useful in these cases too, we just need to fall back to the built-in velocity calculation. Change-Id: Iec5e7632a66380dc04c9435b09f5c173107bbe00 Reviewed-by: Martin Jones --- src/quick/items/qquickcanvas.cpp | 4 ++++ src/quick/items/qquickevents_p_p.h | 14 ++++++++++++-- src/quick/items/qquickflickable.cpp | 17 +++++++++++------ 3 files changed, 27 insertions(+), 8 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp index 670baa8df7..f135975b3c 100644 --- a/src/quick/items/qquickcanvas.cpp +++ b/src/quick/items/qquickcanvas.cpp @@ -378,6 +378,7 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonDblClick, p); me.setTimestamp(event->timestamp()); me.setAccepted(false); + me.setCapabilities(event->device()->capabilities()); if (!mouseGrabberItem) { if (deliverInitialMousePressEvent(rootItem, &me)) { touchMouseId = p.id(); @@ -394,6 +395,7 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonPress, p); me.setTimestamp(event->timestamp()); me.setAccepted(false); + me.setCapabilities(event->device()->capabilities()); deliverMouseEvent(&me); if (me.isAccepted()) { touchMouseId = p.id(); @@ -405,6 +407,7 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) if (p.state() & Qt::TouchPointMoved) { QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseMove, p); me.setTimestamp(event->timestamp()); + me.setCapabilities(event->device()->capabilities()); if (!mouseGrabberItem) { if (lastMousePosition.isNull()) lastMousePosition = me.windowPos(); @@ -428,6 +431,7 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event) return; QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonRelease, p); me.setTimestamp(event->timestamp()); + me.setCapabilities(event->device()->capabilities()); deliverMouseEvent(&me); mouseGrabberItem = 0; } diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index 1d13a19fed..7ff4835b4c 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -163,8 +163,11 @@ public: QQuickMouseEventEx(const QMouseEvent &event) : QMouseEvent(event) { - if (extended(&event)) - setVelocity(extended(&event)->velocity()); + const QQuickMouseEventEx *eventEx = extended(&event); + if (eventEx) { + setVelocity(eventEx->velocity()); + setCapabilities(eventEx->capabilities()); + } } static const QQuickMouseEventEx *extended(const QMouseEvent *e) { @@ -186,8 +189,15 @@ public: } QVector2D velocity() const { return _velocity; } + void setCapabilities(QTouchDevice::Capabilities caps) { + setExtended(); + _capabilities = caps; + } + QTouchDevice::Capabilities capabilities() const { return _capabilities; } + private: QVector2D _velocity; + QTouchDevice::Capabilities _capabilities; }; diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 43aaf92b1a..0e8097af15 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -975,7 +975,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event) lastPosTime = currentTimestamp; QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event); if (q->yflick() && !rejectY) { - if (extended) { + if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) { vData.addVelocitySample(extended->velocity().y(), maxVelocity); } else { qreal dy = event->localPos().y()-lastPos.y(); @@ -983,7 +983,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event) } } if (q->xflick() && !rejectX) { - if (extended) { + if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) { hData.addVelocitySample(extended->velocity().x(), maxVelocity); } else { qreal dx = event->localPos().x()-lastPos.x(); @@ -1020,7 +1020,8 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event) qreal vVelocity = 0; if (elapsed < 100 && vData.velocity != 0.) { QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event); - vVelocity = extended ? extended->velocity().y() : vData.velocity; + vVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) + ? extended->velocity().y() : vData.velocity; } if (vData.atBeginning || vData.atEnd) { vVelocity /= 2; @@ -1035,7 +1036,8 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event) qreal hVelocity = 0; if (elapsed < 100 && hData.velocity != 0.) { QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event); - hVelocity = extended ? extended->velocity().x() : hData.velocity; + hVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) + ? extended->velocity().x() : hData.velocity; } if (hData.atBeginning || hData.atEnd) { hVelocity /= 2; @@ -1769,8 +1771,11 @@ bool QQuickFlickable::sendMouseEvent(QMouseEvent *event) QQuickMouseEventEx mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers()); - if (QQuickMouseEventEx::extended(event)) - mouseEvent.setVelocity(QQuickMouseEventEx::extended(event)->velocity()); + QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event); + if (eventEx) { + mouseEvent.setVelocity(eventEx->velocity()); + mouseEvent.setCapabilities(eventEx->capabilities()); + } mouseEvent.setTimestamp(event->timestamp()); mouseEvent.setAccepted(false); -- cgit v1.2.3 From d290cb3a499a0c3a71ab1f63cbd2fc45b0f5835f Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 27 Feb 2012 16:26:05 +1000 Subject: Fix when animating items that are already moving The view must transition displaced/moved items that are currently transitioning to another position; check against the current transition-to position, not just the current item position. Task-number: QTBUG-24522 Change-Id: Icf1c290f76ceb8c93716f1562ae0bc5a75445b78 Reviewed-by: Martin Jones --- src/quick/items/qquickitemviewtransition.cpp | 20 +++++++++++++++----- src/quick/items/qquickitemviewtransition_p.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/quick/items') diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp index abff768ad3..3febc9b113 100644 --- a/src/quick/items/qquickitemviewtransition.cpp +++ b/src/quick/items/qquickitemviewtransition.cpp @@ -383,6 +383,9 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) if (nextTransitionType != QQuickItemViewTransitioner::NoTransition && !nextTransitionToSet) moveTo(item->pos()); + // For move transitions (both target and displaced) and displaced transitions of other + // types, only run the transition if the item is actually moving to another position. + switch (nextTransitionType) { case QQuickItemViewTransitioner::NoTransition: { @@ -394,14 +397,14 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) } case QQuickItemViewTransitioner::AddTransition: case QQuickItemViewTransitioner::RemoveTransition: - // For Add targets, do transition if item is moving into visible area - // For Remove targets, do transition if item is currently in visible area if (viewBounds.isNull()) { if (isTransitionTarget) doTransition = true; else - doTransition = (nextTransitionTo != item->pos()); + doTransition = transitionWillChangePosition(); } else if (isTransitionTarget) { + // For Add targets, do transition if item is moving into visible area + // For Remove targets, do transition if item is currently in visible area doTransition = (nextTransitionType == QQuickItemViewTransitioner::AddTransition) ? viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())) : viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())); @@ -410,7 +413,7 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) } else { if (viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height()))) { - doTransition = (nextTransitionTo != item->pos()); + doTransition = transitionWillChangePosition(); } else { item->setPos(nextTransitionTo); } @@ -418,7 +421,7 @@ bool QQuickViewItem::prepareTransition(const QRectF &viewBounds) break; case QQuickItemViewTransitioner::MoveTransition: // do transition if moving from or into visible area - if (nextTransitionTo != item->pos()) { + if (transitionWillChangePosition()) { doTransition = viewBounds.isNull() || viewBounds.intersects(QRectF(item->x(), item->y(), item->width(), item->height())) || viewBounds.intersects(QRectF(nextTransitionTo.x(), nextTransitionTo.y(), item->width(), item->height())); @@ -472,6 +475,13 @@ void QQuickViewItem::setNextTransition(QQuickItemViewTransitioner::TransitionTyp isTransitionTarget = isTargetItem; } +bool QQuickViewItem::transitionWillChangePosition() const +{ + if (transitionRunning() && transition->m_toPos != nextTransitionTo) + return true; + return nextTransitionTo != item->pos(); +} + void QQuickViewItem::finishedTransition() { nextTransitionToSet = false; diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h index 1ebc52c185..57ea85bae6 100644 --- a/src/quick/items/qquickitemviewtransition_p.h +++ b/src/quick/items/qquickitemviewtransition_p.h @@ -152,6 +152,7 @@ private: friend class QQuickItemViewTransitioner; friend class QQuickItemViewTransitionJob; void setNextTransition(QQuickItemViewTransitioner::TransitionType, bool isTargetItem); + bool transitionWillChangePosition() const; void finishedTransition(); void resetTransitionData(); }; -- cgit v1.2.3