From b8b1e9784583e3b5960b1966328299f8a1bec440 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Mon, 31 May 2010 15:45:01 +1000 Subject: Simplify selection setting. Make TextInput more like TextEdit. By making selectionStart/End read-only, and adding adding select(). Task-number: QTBUG-11056 --- .../modelviews/webview/content/FieldText.qml | 2 - examples/declarative/text/edit/edit.qml | 16 ++--- .../graphicsitems/qdeclarativetextedit.cpp | 68 ++++++++++++---------- .../graphicsitems/qdeclarativetextedit_p.h | 8 +-- .../graphicsitems/qdeclarativetextinput.cpp | 54 +++++++++++------ .../graphicsitems/qdeclarativetextinput_p.h | 16 ++--- .../tst_qdeclarativetextedit.cpp | 39 ++++--------- .../tst_qdeclarativetextinput.cpp | 55 ++++++----------- .../qdeclarativetextedit/MultilineEdit.qml | 3 +- .../qmlvisual/qdeclarativetextinput/LineEdit.qml | 3 +- 10 files changed, 125 insertions(+), 139 deletions(-) diff --git a/examples/declarative/modelviews/webview/content/FieldText.qml b/examples/declarative/modelviews/webview/content/FieldText.qml index c9adde5..17fa4cd 100644 --- a/examples/declarative/modelviews/webview/content/FieldText.qml +++ b/examples/declarative/modelviews/webview/content/FieldText.qml @@ -161,8 +161,6 @@ Item { color: "black" readOnly: false focus: true - selectionStart: 0 - selectionEnd: -1 } PropertyChanges { target: editRegion diff --git a/examples/declarative/text/edit/edit.qml b/examples/declarative/text/edit/edit.qml index 2774739..0be42e9 100644 --- a/examples/declarative/text/edit/edit.qml +++ b/examples/declarative/text/edit/edit.qml @@ -157,14 +157,16 @@ Rectangle { if (editor.state == "selection" && drag != "") { if (drag == "start") { var pos = edit.positionAt(mouse.x+x+startHandle.width/2,mouse.y+y); - if (edit.selectionEnd < pos) - edit.selectionEnd = pos; - edit.selectionStart = pos; + var e = edit.selectionEnd; + if (e < pos) + e = pos; + edit.select(pos,e); } else if (drag == "end") { var pos = edit.positionAt(mouse.x+x-endHandle.width/2,mouse.y+y); - if (edit.selectionStart > pos) - edit.selectionStart = pos; - edit.selectionEnd = pos; + var s = edit.selectionStart; + if (s > pos) + s = pos; + edit.select(s,pos); } } } @@ -226,7 +228,7 @@ Rectangle { height: 16 Text { anchors.centerIn: parent; text: "Deselect" } MouseArea { anchors.fill: parent; - onClicked: { edit.cursorPosition = edit.selectionEnd; edit.selectionStart = edit.selectionEnd; editor.state = "" } } + onClicked: { edit.cursorPosition = edit.selectionEnd; edit.select(edit.cursorPosition,edit.cursorPosition); editor.state = "" } } } } } diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index f8876f2..935b431 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -717,12 +717,9 @@ void QDeclarativeTextEdit::loadCursorDelegate() \qmlproperty int TextEdit::selectionStart The cursor position before the first character in the current selection. - Setting this and selectionEnd allows you to specify a selection in the - text edit. - Note that if selectionStart == selectionEnd then there is no current - selection. If you attempt to set selectionStart to a value outside of - the current text, selectionStart will not be changed. + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). \sa selectionEnd, cursorPosition, selectedText */ @@ -732,25 +729,13 @@ int QDeclarativeTextEdit::selectionStart() const return d->control->textCursor().selectionStart(); } -void QDeclarativeTextEdit::setSelectionStart(int s) -{ - Q_D(QDeclarativeTextEdit); - if(d->lastSelectionStart == s || s < 0 || s > text().length()) - return; - d->lastSelectionStart = s; - d->updateSelection();// Will emit the relevant signals -} - /*! \qmlproperty int TextEdit::selectionEnd The cursor position after the last character in the current selection. - Setting this and selectionStart allows you to specify a selection in the - text edit. - Note that if selectionStart == selectionEnd then there is no current - selection. If you attempt to set selectionEnd to a value outside of - the current text, selectionEnd will not be changed. + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). \sa selectionStart, cursorPosition, selectedText */ @@ -760,15 +745,6 @@ int QDeclarativeTextEdit::selectionEnd() const return d->control->textCursor().selectionEnd(); } -void QDeclarativeTextEdit::setSelectionEnd(int s) -{ - Q_D(QDeclarativeTextEdit); - if(d->lastSelectionEnd == s || s < 0 || s > text().length()) - return; - d->lastSelectionEnd = s; - d->updateSelection();// Will emit the relevant signals -} - /*! \qmlproperty string TextEdit::selectedText @@ -1018,6 +994,8 @@ void QDeclarativeTextEditPrivate::focusChanged(bool hasFocus) } /*! + \qmlmethod void TextEdit::selectAll() + Causes all text to be selected. */ void QDeclarativeTextEdit::selectAll() @@ -1027,6 +1005,8 @@ void QDeclarativeTextEdit::selectAll() } /*! + \qmlmethod void TextEdit::selectWord() + Causes the word closest to the current cursor position to be selected. */ void QDeclarativeTextEdit::selectWord() @@ -1038,6 +1018,35 @@ void QDeclarativeTextEdit::selectWord() } /*! + \qmlmethod void TextEdit::select(start,end) + + Causes the text from \a start to \a end to be selected. + + If either start or end is out of range, the selection is not changed. + + After calling this, selectionStart will become the lesser + and selectionEnd will become the greater (regardless of the order passed + to this method). + + \sa selectionStart, selectionEnd +*/ +void QDeclarativeTextEdit::select(int start, int end) +{ + Q_D(QDeclarativeTextEdit); + if (start < 0 || end < 0 || start > d->text.length() || end > d->text.length()) + return; + QTextCursor cursor = d->control->textCursor(); + cursor.beginEditBlock(); + cursor.setPosition(start, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + cursor.endEditBlock(); + d->control->setTextCursor(cursor); + + // QTBUG-11100 + updateSelectionMarkers(); +} + +/*! \qmlmethod TextEdit::cut() Moves the currently selected text to the system clipboard. @@ -1254,7 +1263,6 @@ void QDeclarativeTextEditPrivate::updateSelection() QTextCursor cursor = control->textCursor(); bool startChange = (lastSelectionStart != cursor.selectionStart()); bool endChange = (lastSelectionEnd != cursor.selectionEnd()); - //### Is it worth calculating a more minimal set of movements? cursor.beginEditBlock(); cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); @@ -1264,8 +1272,6 @@ void QDeclarativeTextEditPrivate::updateSelection() q->selectionStartChanged(); if(endChange) q->selectionEndChanged(); - startChange = (lastSelectionStart != control->textCursor().selectionStart()); - endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); } void QDeclarativeTextEdit::updateSelectionMarkers() diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index a83b3db..3abfc35 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -82,8 +82,8 @@ class Q_DECLARATIVE_EXPORT QDeclarativeTextEdit : public QDeclarativePaintedItem Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QDeclarativeComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) - Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) - Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) + Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) + Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectionChanged) Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress NOTIFY focusOnPressChanged) Q_PROPERTY(bool showInputPanelOnFocus READ showInputPanelOnFocus WRITE setShowInputPanelOnFocus NOTIFY showInputPanelOnFocusChanged) @@ -160,10 +160,7 @@ public: void setCursorDelegate(QDeclarativeComponent*); int selectionStart() const; - void setSelectionStart(int); - int selectionEnd() const; - void setSelectionEnd(int); QString selectedText() const; @@ -230,6 +227,7 @@ Q_SIGNALS: public Q_SLOTS: void selectAll(); void selectWord(); + void select(int start, int end); void cut(); void copy(); void paste(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 9a6a070..25a2b49 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -429,10 +430,12 @@ void QDeclarativeTextInput::setCursorPosition(int cp) Returns a Rect which encompasses the cursor, but which may be larger than is required. Ignores custom cursor delegates. */ -QRect QDeclarativeTextInput::cursorRect() const +QRect QDeclarativeTextInput::cursorRectangle() const { Q_D(const QDeclarativeTextInput); - return d->control->cursorRect(); + QRect r = d->control->cursorRect(); + r.setHeight(r.height()-1); // Make consistent with TextEdit (QLineControl inexplicably adds 1) + return r; } /*! @@ -454,15 +457,6 @@ int QDeclarativeTextInput::selectionStart() const return d->lastSelectionStart; } -void QDeclarativeTextInput::setSelectionStart(int s) -{ - Q_D(QDeclarativeTextInput); - if(d->lastSelectionStart == s || s < 0 || s > text().length()) - return; - d->lastSelectionStart = s; - d->control->setSelection(s, d->lastSelectionEnd - s); -} - /*! \qmlproperty int TextInput::selectionEnd @@ -482,13 +476,12 @@ int QDeclarativeTextInput::selectionEnd() const return d->lastSelectionEnd; } -void QDeclarativeTextInput::setSelectionEnd(int s) +void QDeclarativeTextInput::select(int start, int end) { Q_D(QDeclarativeTextInput); - if(d->lastSelectionEnd == s || s < 0 || s > text().length()) + if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length()) return; - d->lastSelectionEnd = s; - d->control->setSelection(d->lastSelectionStart, s - d->lastSelectionStart); + d->control->setSelection(start, end-start); } /*! @@ -833,6 +826,19 @@ void QDeclarativeTextInput::moveCursor() } /*! + \qmlmethod rect TextInput::positionToRectangle(int x) +*/ +QRectF QDeclarativeTextInput::positionToRectangle(int x) const +{ + Q_D(const QDeclarativeTextInput); + QFontMetrics fm = QFontMetrics(d->font); + return QRectF(d->control->cursorToX(x)-d->hscroll, + 0.0, + d->control->cursorWidth(), + cursorRectangle().height()); +} + +/*! \qmlmethod int TextInput::positionAt(int x) This function returns the character position at @@ -843,7 +849,7 @@ void QDeclarativeTextInput::moveCursor() This means that for all x values before the first character this function returns 0, and for all x values after the last character this function returns text.length. */ -int QDeclarativeTextInput::positionAt(int x) +int QDeclarativeTextInput::positionAt(int x) const { Q_D(const QDeclarativeTextInput); return d->control->xToPos(x - d->hscroll); @@ -1019,7 +1025,6 @@ void QDeclarativeTextInput::drawContents(QPainter *p, const QRect &r) d->hscroll -= minLB; offset = QPoint(d->hscroll, 0); } - d->control->draw(p, offset, r, flags); p->restore(); @@ -1057,12 +1062,27 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) } } +/*! + \qmlmethod void TextInput::selectAll() + + Causes all text to be selected. +*/ void QDeclarativeTextInput::selectAll() { Q_D(QDeclarativeTextInput); d->control->setSelection(0, d->control->text().length()); } +/*! + \qmlmethod void TextInput::selectWord() + + Causes the word closest to the current cursor position to be selected. +*/ +void QDeclarativeTextInput::selectWord() +{ + Q_D(QDeclarativeTextInput); + d->control->selectWordAtPos(d->control->cursor()); +} /*! \qmlproperty bool TextInput::smooth diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 6bb94c2..0b7ddd5 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -72,10 +72,10 @@ class Q_DECLARATIVE_EXPORT QDeclarativeTextInput : public QDeclarativePaintedIte 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 cursorRect READ cursorRect NOTIFY cursorPositionChanged) + Q_PROPERTY(QRect cursorRectangle READ cursorRectangle NOTIFY cursorPositionChanged) Q_PROPERTY(QDeclarativeComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) - Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) - Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) + Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) + Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) Q_PROPERTY(int maximumLength READ maxLength WRITE setMaxLength NOTIFY maximumLengthChanged) @@ -110,7 +110,8 @@ public: }; //Auxilliary functions needed to control the TextInput from QML - Q_INVOKABLE int positionAt(int x); + Q_INVOKABLE int positionAt(int x) const; + Q_INVOKABLE QRectF positionToRectangle(int x) const; Q_INVOKABLE void moveCursorSelection(int pos); Q_INVOKABLE void openSoftwareInputPanel(); @@ -143,13 +144,10 @@ public: int cursorPosition() const; void setCursorPosition(int cp); - QRect cursorRect() const; + QRect cursorRectangle() const; int selectionStart() const; - void setSelectionStart(int); - int selectionEnd() const; - void setSelectionEnd(int); QString selectedText() const; @@ -231,6 +229,8 @@ protected: public Q_SLOTS: void selectAll(); + void selectWord(); + void select(int start, int end); private Q_SLOTS: void updateSize(bool needsRedraw = true); diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index d3e3c3a..47c5b63 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -551,11 +551,11 @@ void tst_qdeclarativetextedit::selection() //Test selection for(int i=0; i<= testStr.size(); i++) { - textEditObject->setSelectionEnd(i); + textEditObject->select(0,i); QCOMPARE(testStr.mid(0,i), textEditObject->selectedText()); } for(int i=0; i<= testStr.size(); i++) { - textEditObject->setSelectionStart(i); + textEditObject->select(i,testStr.size()); QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText()); } @@ -565,43 +565,26 @@ void tst_qdeclarativetextedit::selection() QVERIFY(textEditObject->selectionEnd() == 0); QVERIFY(textEditObject->selectedText().isNull()); - for(int i=0; i< testStr.size(); i++) { - textEditObject->setSelectionStart(i); - QCOMPARE(textEditObject->selectionEnd(), i); - QCOMPARE(testStr.mid(i,0), textEditObject->selectedText()); - textEditObject->setSelectionEnd(i+1); - QCOMPARE(textEditObject->selectionStart(), i); - QCOMPARE(testStr.mid(i,1), textEditObject->selectedText()); - } - - for(int i= testStr.size() - 1; i>0; i--) { - textEditObject->setSelectionEnd(i); - QCOMPARE(testStr.mid(i,0), textEditObject->selectedText()); - textEditObject->setSelectionStart(i-1); - QCOMPARE(testStr.mid(i-1,1), textEditObject->selectedText()); - } - //Test Error Ignoring behaviour textEditObject->setCursorPosition(0); QVERIFY(textEditObject->selectedText().isNull()); - textEditObject->setSelectionStart(-10); + textEditObject->select(-10,0); QVERIFY(textEditObject->selectedText().isNull()); - textEditObject->setSelectionStart(100); + textEditObject->select(100,101); QVERIFY(textEditObject->selectedText().isNull()); - textEditObject->setSelectionEnd(-10); + textEditObject->select(0,-10); QVERIFY(textEditObject->selectedText().isNull()); - textEditObject->setSelectionEnd(100); + textEditObject->select(0,100); QVERIFY(textEditObject->selectedText().isNull()); - textEditObject->setSelectionStart(0); - textEditObject->setSelectionEnd(10); + textEditObject->select(0,10); QVERIFY(textEditObject->selectedText().size() == 10); - textEditObject->setSelectionStart(-10); + textEditObject->select(-10,0); QVERIFY(textEditObject->selectedText().size() == 10); - textEditObject->setSelectionStart(100); + textEditObject->select(100,101); QVERIFY(textEditObject->selectedText().size() == 10); - textEditObject->setSelectionEnd(-10); + textEditObject->select(0,-10); QVERIFY(textEditObject->selectedText().size() == 10); - textEditObject->setSelectionEnd(100); + textEditObject->select(0,100); QVERIFY(textEditObject->selectedText().size() == 10); } diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index c01cfa5..54bb9c1 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -322,11 +322,11 @@ void tst_qdeclarativetextinput::selection() //Test selection for(int i=0; i<= testStr.size(); i++) { - textinputObject->setSelectionEnd(i); + textinputObject->select(0,i); QCOMPARE(testStr.mid(0,i), textinputObject->selectedText()); } for(int i=0; i<= testStr.size(); i++) { - textinputObject->setSelectionStart(i); + textinputObject->select(i,testStr.size()); QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText()); } @@ -336,43 +336,26 @@ void tst_qdeclarativetextinput::selection() QVERIFY(textinputObject->selectionEnd() == 0); QVERIFY(textinputObject->selectedText().isNull()); - for(int i=0; i< testStr.size(); i++) { - textinputObject->setSelectionStart(i); - QCOMPARE(textinputObject->selectionEnd(), i); - QCOMPARE(testStr.mid(i,0), textinputObject->selectedText()); - textinputObject->setSelectionEnd(i+1); - QCOMPARE(textinputObject->selectionStart(), i); - QCOMPARE(testStr.mid(i,1), textinputObject->selectedText()); - } - - for(int i= testStr.size() - 1; i>0; i--) { - textinputObject->setSelectionEnd(i); - QCOMPARE(testStr.mid(i,0), textinputObject->selectedText()); - textinputObject->setSelectionStart(i-1); - QCOMPARE(testStr.mid(i-1,1), textinputObject->selectedText()); - } - //Test Error Ignoring behaviour textinputObject->setCursorPosition(0); QVERIFY(textinputObject->selectedText().isNull()); - textinputObject->setSelectionStart(-10); + textinputObject->select(-10,0); QVERIFY(textinputObject->selectedText().isNull()); - textinputObject->setSelectionStart(100); + textinputObject->select(100,110); QVERIFY(textinputObject->selectedText().isNull()); - textinputObject->setSelectionEnd(-10); + textinputObject->select(0,-10); QVERIFY(textinputObject->selectedText().isNull()); - textinputObject->setSelectionEnd(100); + textinputObject->select(0,100); QVERIFY(textinputObject->selectedText().isNull()); - textinputObject->setSelectionStart(0); - textinputObject->setSelectionEnd(10); + textinputObject->select(0,10); QVERIFY(textinputObject->selectedText().size() == 10); - textinputObject->setSelectionStart(-10); + textinputObject->select(-10,10); QVERIFY(textinputObject->selectedText().size() == 10); - textinputObject->setSelectionStart(100); + textinputObject->select(100,101); QVERIFY(textinputObject->selectedText().size() == 10); - textinputObject->setSelectionEnd(-10); + textinputObject->select(0,-10); QVERIFY(textinputObject->selectedText().size() == 10); - textinputObject->setSelectionEnd(100); + textinputObject->select(0,100); QVERIFY(textinputObject->selectedText().size() == 10); delete textinputObject; @@ -565,8 +548,7 @@ void tst_qdeclarativetextinput::navigation() QVERIFY(input->hasFocus() == true); //QT-2944: If text is selected, ensure we deselect upon cursor motion input->setCursorPosition(input->text().length()); - input->setSelectionStart(0); - input->setSelectionEnd(input->text().length()); + input->select(0,input->text().length()); QVERIFY(input->selectionStart() != input->selectionEnd()); simulateKey(canvas, Qt::Key_Right); QVERIFY(input->selectionStart() == input->selectionEnd()); @@ -603,13 +585,13 @@ void tst_qdeclarativetextinput::cursorDelegate() //Test Delegate gets moved for(int i=0; i<= textInputObject->text().length(); i++){ textInputObject->setCursorPosition(i); - //+5 is because the TextInput cursorRect is just a 10xHeight area centered on cursor position - QCOMPARE(textInputObject->cursorRect().x() + 5, qRound(delegateObject->x())); - QCOMPARE(textInputObject->cursorRect().y(), qRound(delegateObject->y())); + //+5 is because the TextInput cursorRectangle is just a 10xHeight area centered on cursor position + QCOMPARE(textInputObject->cursorRectangle().x() + 5, qRound(delegateObject->x())); + QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y())); } textInputObject->setCursorPosition(0); - QCOMPARE(textInputObject->cursorRect().x()+5, qRound(delegateObject->x())); - QCOMPARE(textInputObject->cursorRect().y(), qRound(delegateObject->y())); + QCOMPARE(textInputObject->cursorRectangle().x()+5, qRound(delegateObject->x())); + QCOMPARE(textInputObject->cursorRectangle().y(), qRound(delegateObject->y())); //Test Delegate gets deleted textInputObject->setCursorDelegate(0); QVERIFY(!textInputObject->findChild("cursorInstance")); @@ -881,8 +863,7 @@ void tst_qdeclarativetextinput::focusOutClearSelection() view.show(); QApplication::setActiveWindow(&view); QTest::qWaitForWindowShown(&view); - input.setSelectionStart(2); - input.setSelectionEnd(5); + input.select(2,5); //The selection should work QTRY_COMPARE(input.selectedText(), QLatin1String("llo")); input2.setFocus(true); diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetextedit/MultilineEdit.qml b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/MultilineEdit.qml index 0273282..53538cb 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativetextedit/MultilineEdit.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativetextedit/MultilineEdit.qml @@ -65,8 +65,7 @@ Item { onReleased: { } onDoubleClicked: { - textEdit.selectionStart=0; - textEdit.selectionEnd=textEdit.text.length; + textEdit.selectAll() } z: textEdit.z + 1 } diff --git a/tests/auto/declarative/qmlvisual/qdeclarativetextinput/LineEdit.qml b/tests/auto/declarative/qmlvisual/qdeclarativetextinput/LineEdit.qml index cc0ad3c..69f57c6 100644 --- a/tests/auto/declarative/qmlvisual/qdeclarativetextinput/LineEdit.qml +++ b/tests/auto/declarative/qmlvisual/qdeclarativetextinput/LineEdit.qml @@ -58,8 +58,7 @@ Item { onReleased: { } onDoubleClicked: { - textInp.selectionStart=0; - textInp.selectionEnd=textInp.text.length; + textInp.selectAll() } z: textInp.z + 1 } -- cgit v0.12 From e5cc765d2fa1ff68f1592ad475d6b8f4e5a6f667 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 31 May 2010 14:45:43 +1000 Subject: Document issues with rectangle border width of 1 where clipping is used --- doc/src/declarative/pics/rect-border-width.png | Bin 0 -> 356 bytes doc/src/snippets/declarative/rect-border-width.qml | 19 +++++++++++++++++++ .../graphicsitems/qdeclarativerectangle.cpp | 16 ++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 doc/src/declarative/pics/rect-border-width.png create mode 100644 doc/src/snippets/declarative/rect-border-width.qml diff --git a/doc/src/declarative/pics/rect-border-width.png b/doc/src/declarative/pics/rect-border-width.png new file mode 100644 index 0000000..c3c6c2c Binary files /dev/null and b/doc/src/declarative/pics/rect-border-width.png differ diff --git a/doc/src/snippets/declarative/rect-border-width.qml b/doc/src/snippets/declarative/rect-border-width.qml new file mode 100644 index 0000000..27a241d --- /dev/null +++ b/doc/src/snippets/declarative/rect-border-width.qml @@ -0,0 +1,19 @@ +import Qt 4.7 + +//![0] +Rectangle { + width: 100; height: 100 + color: "yellow" + + Rectangle { + anchor.fill: parent + anchors.margins: 10 + clip: true + + Rectangle { + anchors.fill: parent + border.width: 1 + } + } +} +//![0] diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp index 301ca00..de3dbcd 100644 --- a/src/declarative/graphicsitems/qdeclarativerectangle.cpp +++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp @@ -202,8 +202,20 @@ void QDeclarativeRectangle::doUpdate() A width of 1 creates a thin line. For no line, use a width of 0 or a transparent color. - To keep the border smooth (rather than blurry), odd widths cause the rectangle to be painted at - a half-pixel offset; + If \c border.width is an odd number, the rectangle is painted at a half-pixel offset to retain + border smoothness. Also, the border is rendered evenly on either side of the + rectangle's boundaries, and the spare pixel is rendered to the right and below the + rectangle (as documented for QRect rendering). This can cause unintended effects if + \c border.width is 1 and the rectangle is \l{clip}{clipped} by a parent item: + + \table + \row + \o \snippet doc/src/snippets/declarative/rect-border-width.qml 0 + \o \image rect-border-width.png + \endtable + + Here, the innermost rectangle's border is clipped on the bottom and right edges by its + parent. To avoid this, the border width can be set to two instead of one. */ QDeclarativePen *QDeclarativeRectangle::border() { -- cgit v0.12 From 4759e47a2444d481156ad1a789e5affbc92e1b58 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Mon, 31 May 2010 16:59:48 +1000 Subject: Various doc fixes and improvements --- doc/src/declarative/basictypes.qdoc | 67 +++++++++++++++++---- doc/src/declarative/globalobject.qdoc | 2 +- doc/src/declarative/pics/repeater-modeldata.png | Bin 0 -> 2600 bytes doc/src/declarative/qml-intro.qdoc | 26 ++++---- .../snippets/declarative/repeater-modeldata.qml | 52 ++++++++++++++++ examples/declarative/sqllocalstorage/hello.qml | 2 +- .../tutorials/extending/chapter1-basics/app.qml | 1 + .../tutorials/extending/chapter2-methods/app.qml | 1 + .../tutorials/extending/chapter3-bindings/app.qml | 1 + .../extending/chapter4-customPropertyTypes/app.qml | 1 + .../graphicsitems/qdeclarativerepeater.cpp | 14 +++-- src/declarative/qml/qdeclarativeengine.cpp | 34 ++++++++--- 12 files changed, 159 insertions(+), 42 deletions(-) create mode 100644 doc/src/declarative/pics/repeater-modeldata.png create mode 100644 doc/src/snippets/declarative/repeater-modeldata.qml diff --git a/doc/src/declarative/basictypes.qdoc b/doc/src/declarative/basictypes.qdoc index 8db1c35..43ae214 100644 --- a/doc/src/declarative/basictypes.qdoc +++ b/doc/src/declarative/basictypes.qdoc @@ -46,9 +46,9 @@ QML has a set of primitive types, as listed below, that are used throughout the \l {QML Elements}. - The simpler types in this list can also be used for defining a new - \c property in a component. See \l{Extending types from QML} for the - list of types that can be used for custom properties. + Some of these types can also be used for defining + \c property values in QML. See \l{Extending types from QML} for the + list of types that can be used for \c property values. \annotatedlist qmlbasictypes */ @@ -171,6 +171,13 @@ Rectangle { color: "#800000FF" } \endqml + Or with the \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, + \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()} functions: + + \qml + Rectangle { color: Qt.rgba(255, 0, 0, 1) } + \endqml + \sa {QML Basic Types} */ @@ -184,9 +191,17 @@ Example: \qml - Widget { pos: "0,20" } + MyItem { position: "0,20" } \endqml + Or with the \l{Qt::point()}{Qt.point()} function: + + \qml + MyItem { position: Qt.point(0, 20) } + \endqml + + A point object has \c x and \c y attributes that contain the \c x and \c y values. + \sa {QML Basic Types} */ @@ -200,9 +215,17 @@ Example: \qml - Widget { size: "150x50" } + LayoutItem { preferredSize: "150x50" } + \endqml + + Or with the \l{Qt::size()}{Qt.size()} function: + + \qml + MyItem { position: Qt.size(150, 50) } \endqml + A size object has \c width and \c height attributes that contain the \c width and \c height values. + \sa {QML Basic Types} */ @@ -216,9 +239,18 @@ Example: \qml - Widget { geometry: "50,50,100x100" } + MyItem { geometry: "50,50,100x100" } \endqml + Or with the \l{Qt::rect()}{Qt.rect()} function: + + \qml + MyItem { position: Qt.rect(50, 50, 100, 100) } + \endqml + + A rect object has \c x, \c, y, \c width and \c height attributes that contain the + \c x, \c y, \c width and \c height values. + \sa {QML Basic Types} */ @@ -232,9 +264,12 @@ Example: \qml - DatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" } + MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" } \endqml + To read a date value returned from a C++ extension class, use + \l{Qt::formatDate()}{Qt.formatDate()} and \l{Qt::formatDateTime()}{Qt.formatDateTime()}. + \sa {QML Basic Types} */ @@ -248,9 +283,12 @@ Example: \qml - TimePicker { time: "14:22:15" } + MyTimePicker { time: "14:22:15" } \endqml + To read a time value returned from a C++ extension class, use + \l{Qt::formatTime()}{Qt.formatTime()} and \l{Qt::formatDateTime()}{Qt.formatDateTime()}. + \sa {QML Basic Types} */ @@ -297,9 +335,9 @@ Actions are used like this: \qml - MouseArea { onClicked: MyItem.myaction.trigger() } - State { name: "enabled"; when: MyItem.myaction.enabled == true } - Text { text: MyItem.someaction.text } + MouseArea { onClicked: myaction.trigger() } + State { name: "enabled"; when: myaction.enabled == true } + Text { text: someaction.text } \endqml \sa {QML Basic Types} @@ -327,7 +365,7 @@ ] } \endqml - \c Child1, \c Child2 and \c Child3 will all be added to the children list + \c child1, \c child2 and \c child3 will all be added to the children list in the order in which they appear. \sa {QML Basic Types} @@ -345,7 +383,7 @@ Rotation { angle: 60; axis: "0,1,0" } \endqml - or with the \c{Qt.vector3d()} helper function: + or with the \c{Qt.vector3d()} function: \qml Rotation { angle: 60; axis: Qt.vector3d(0, 1, 0) } @@ -357,5 +395,8 @@ Rotation { angle: 60; axis.x: 0; axis.y: 1; axis.z: 0 } \endqml + A vector3d object has \c x, \c, y, and \c z attributes that contain the + \c x, \c y, \c z values. + \sa {QML Basic Types} */ diff --git a/doc/src/declarative/globalobject.qdoc b/doc/src/declarative/globalobject.qdoc index 7d4f9b9..3121e95 100644 --- a/doc/src/declarative/globalobject.qdoc +++ b/doc/src/declarative/globalobject.qdoc @@ -49,7 +49,7 @@ Contains all the properties of the JavaScript global object, plus: \section1 Qt Object -The \l{qml-qt.html}{Qt object} provides useful enums and functions from Qt, for use in all QML +The \l{Qt}{Qt object} provides useful enums and functions from Qt, for use in all QML files. \section1 XMLHttpRequest diff --git a/doc/src/declarative/pics/repeater-modeldata.png b/doc/src/declarative/pics/repeater-modeldata.png new file mode 100644 index 0000000..817f35b Binary files /dev/null and b/doc/src/declarative/pics/repeater-modeldata.png differ diff --git a/doc/src/declarative/qml-intro.qdoc b/doc/src/declarative/qml-intro.qdoc index 64a4949..848e094 100644 --- a/doc/src/declarative/qml-intro.qdoc +++ b/doc/src/declarative/qml-intro.qdoc @@ -864,49 +864,49 @@ paused, and reaching the end of the media. They allow the developer to connect, some QML that will handle this event. -\section1 Analyzing An Example: Dial +\section1 Analyzing An Example: Dial Control -In the Qt \e {examples/declarative/toys} folder you will find a folder -\e {dial} which contains the \e dial example. +In the Qt \e {examples/declarative/ui-components} folder you will find a folder +\e {dialcontrol} which contains the \e dialcontrol example. \image qml-dial.png "QML Dial example with Slider" In essence this small application has a sliding bar that you can slide using a mouse, and a graphical dial that responds to the position of the slider. -The code for the example is in two parts: Dial.qml and dial-example.qml. +The code for the example is in two parts: Dial.qml and dialcontrol.qml. -\e {Dial.qml} can be found in the \e content sub-directory. It defines a Dial +\e {Dial.qml} can be found in the \e content sub-directory. It defines a \c Dial component similar to an odometer. Eventually, the example will hook up a slider component so that moving the slider will change the position of a needle on the dial. -The code for the Dial, identified by the name of the file, contains four images +The code for the \c Dial, identified by the name of the file, contains four images in overlapping order: the background (numbers and divisions), the shadow of the needle, the needle itself, and finally the 'glass' overlay (containing transparent layers). -The needle_shadow.png image has a Rotation assigned to the \e transform +The \c needle_shadow.png image has a \l Rotation assigned to the \e transform attribute of the \l Image. The rotation is set to match the angle of the needle image angle value \e {needleRotation.angle}. Both the needle and the needle_shadow have the same default \e x and \e y values but the rotation origin for the needle is slightly different so that a shadow will be evident as the needle moves. -\snippet ../../examples/declarative/toys/dial/content/Dial.qml needle_shadow +\snippet ../../examples/declarative/ui-components/dialcontrol/content/Dial.qml needle_shadow And the needle -\snippet ../../examples/declarative/toys/dial/content/Dial.qml needle +\snippet ../../examples/declarative/ui-components/dialcontrol/content/Dial.qml needle The final image is the overlay which simply has a position defined. -\snippet ../../examples/declarative/toys/dial/content/Dial.qml overlay +\snippet ../../examples/declarative/ui-components/dialcontrol/content/Dial.qml overlay -\e {dial-example.qml} in the \e {examples/declarative/toys/dial} directory is the +\e {dialcontrol.qml} in the \e {examples/declarative/ui-components/dialcontrol} directory is the main file of the example. It defines the visual environment that the Dial will fit into. Because the \e Dial component and the images live in the \e -content sub-directory we will have to import this into \e dial-example. So the +content sub-directory we will have to import this into \e dialcontrol.qml. So the start of the file looks like \code @@ -919,7 +919,7 @@ a gray color. Inside this rectangle is our component \e Dial and a \l Rectangle. Inside the rectangle called 'container' is another rectangle with the interesting name 'slider'. -\snippet ../../examples/declarative/toys/dial/dial-example.qml 0 +\snippet ../../examples/declarative/ui-components/dialcontrol/dialcontrol.qml 0 The Dial component, named 'dial, is \e anchored to the center of the main rectangle. The \c value attribute of 'dial' is set to a value based on the diff --git a/doc/src/snippets/declarative/repeater-modeldata.qml b/doc/src/snippets/declarative/repeater-modeldata.qml new file mode 100644 index 0000000..3b4cc6d --- /dev/null +++ b/doc/src/snippets/declarative/repeater-modeldata.qml @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt 4.7 + +//! [0] +Column { + Repeater { + model: ["apples", "oranges", "pears"] + Text { text: "Data: " + modelData } + } +} +//! [0] + diff --git a/examples/declarative/sqllocalstorage/hello.qml b/examples/declarative/sqllocalstorage/hello.qml index 0913d42..421a74c 100644 --- a/examples/declarative/sqllocalstorage/hello.qml +++ b/examples/declarative/sqllocalstorage/hello.qml @@ -68,4 +68,4 @@ Text { Component.onCompleted: findGreetings() } - +//![0] diff --git a/examples/declarative/tutorials/extending/chapter1-basics/app.qml b/examples/declarative/tutorials/extending/chapter1-basics/app.qml index 7de32f2..9af155c 100644 --- a/examples/declarative/tutorials/extending/chapter1-basics/app.qml +++ b/examples/declarative/tutorials/extending/chapter1-basics/app.qml @@ -55,3 +55,4 @@ Rectangle { text: aMusician.name + " plays the " + aMusician.instrument } } +//![0] diff --git a/examples/declarative/tutorials/extending/chapter2-methods/app.qml b/examples/declarative/tutorials/extending/chapter2-methods/app.qml index 495413f..02d33c2 100644 --- a/examples/declarative/tutorials/extending/chapter2-methods/app.qml +++ b/examples/declarative/tutorials/extending/chapter2-methods/app.qml @@ -57,3 +57,4 @@ Rectangle { onClicked: aMusician.perform() } } +//![0] diff --git a/examples/declarative/tutorials/extending/chapter3-bindings/app.qml b/examples/declarative/tutorials/extending/chapter3-bindings/app.qml index 46408cb..8bf6ecf 100644 --- a/examples/declarative/tutorials/extending/chapter3-bindings/app.qml +++ b/examples/declarative/tutorials/extending/chapter3-bindings/app.qml @@ -69,3 +69,4 @@ Rectangle { } } } +//![0] diff --git a/examples/declarative/tutorials/extending/chapter4-customPropertyTypes/app.qml b/examples/declarative/tutorials/extending/chapter4-customPropertyTypes/app.qml index 09662d6..d76f801 100644 --- a/examples/declarative/tutorials/extending/chapter4-customPropertyTypes/app.qml +++ b/examples/declarative/tutorials/extending/chapter4-customPropertyTypes/app.qml @@ -51,3 +51,4 @@ Item { Component.onCompleted: console.log("Reddy plays the " + reddy.instrument.type) } +//![0] diff --git a/src/declarative/graphicsitems/qdeclarativerepeater.cpp b/src/declarative/graphicsitems/qdeclarativerepeater.cpp index 04076f8..691cfa2 100644 --- a/src/declarative/graphicsitems/qdeclarativerepeater.cpp +++ b/src/declarative/graphicsitems/qdeclarativerepeater.cpp @@ -80,14 +80,20 @@ QDeclarativeRepeaterPrivate::~QDeclarativeRepeaterPrivate() The index is always exposed as an accessible \c index property. In the case of an object or string list, the data element (of type string or object) is available as the \c modelData property. In the case of a Qt model, - all roles are available as named properties just like in the view classes. The - following example shows how to use the index property inside the instantiated - items. + all roles are available as named properties just like in the view classes. - \snippet doc/src/snippets/declarative/repeater-index.qml 0 + The following example shows how to use the \c index property inside the instantiated + items: + \snippet doc/src/snippets/declarative/repeater-index.qml 0 \image repeater-index.png + The repeater could also use the \c modelData property to reference the data for a + particular index: + + \snippet doc/src/snippets/declarative/repeater-modeldata.qml 0 + \image repeater-modeldata.png + Items instantiated by the Repeater are inserted, in order, as children of the Repeater's parent. The insertion starts immediately after the repeater's position in its parent stacking list. This is to allow diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 8679e76..d8c842b 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -155,14 +155,26 @@ void QDeclarativeEnginePrivate::defineModule() \qmlclass Qt QDeclarativeEnginePrivate \brief The QML global Qt object provides useful enums and functions from Qt. -The Qt object provides useful enums and functions from Qt, for use in all QML files. +The \c Qt object provides useful enums and functions from Qt, for use in all QML files. + +The \c Qt object is not a QML element; it cannot be instantiated. It is a global object +with enums and functions. To use it, call the members of the global \c Qt object directly. +For example: + +\qml +import Qt 4.7 + +Text { + color: Qt.rgba(255, 0, 0, 1) + text: Qt.md5("hello, world") +} +\endqml -You do not create instances of this type, but instead use the members of the global "Qt" object. \section1 Enums The Qt object contains all enums in the Qt namespace. For example, you can -access the AlignLeft member of the Qt::AlignmentFlag enum with \c Qt.AlignLeft. +access the \c AlignLeft member of the \c Qt::AlignmentFlag enum with \c Qt.AlignLeft. For a full list of enums, see the \l{Qt Namespace} documentation. @@ -172,7 +184,7 @@ data types. This is primarily useful when setting the properties of an item when the property has one of the following types: \list -\o \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()} +\o \c color - use \l{Qt::rgba()}{Qt.rgba()}, \l{Qt::hsla()}{Qt.hsla()}, \l{Qt::darker()}{Qt.darker()}, \l{Qt::lighter()}{Qt.lighter()} or \l{Qt::tint()}{Qt.tint()} \o \c rect - use \l{Qt::rect()}{Qt.rect()} \o \c point - use \l{Qt::point()}{Qt.point()} \o \c size - use \l{Qt::size()}{Qt.size()} @@ -200,8 +212,8 @@ items from files or strings. See \l{Dynamic Object Management} for an overview of their use. \list - \o \l{Qt::createComponent}{object Qt.createComponent(url)} - \o \l{Qt::createQmlObject}{object Qt.createQmlObject(string qml, object parent, string filepath)} + \o \l{Qt::createComponent()}{object Qt.createComponent(url)} + \o \l{Qt::createQmlObject()}{object Qt.createQmlObject(string qml, object parent, string filepath)} \endlist */ @@ -1034,7 +1046,7 @@ QString QDeclarativeEnginePrivate::urlToLocalFileOrQrc(const QUrl& url) /*! \qmlmethod object Qt::createComponent(url) -Returns a \l Component object created from the QML file at the specified \a url, +Returns a \l Component object created using the QML file at the specified \a url, or \c null if there was an error in creating the component. Call \l {Component::createObject()}{Component.createObject()} on the returned @@ -1360,7 +1372,7 @@ QScriptValue QDeclarativeEnginePrivate::formatDateTime(QScriptContext*ctxt, QScr /*! \qmlmethod color Qt::rgba(real red, real green, real blue, real alpha) -Returns a Color with the specified \c red, \c green, \c blue and \c alpha components. +Returns a color with the specified \c red, \c green, \c blue and \c alpha components. All components should be in the range 0-1 inclusive. */ QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine *engine) @@ -1388,7 +1400,7 @@ QScriptValue QDeclarativeEnginePrivate::rgba(QScriptContext *ctxt, QScriptEngine /*! \qmlmethod color Qt::hsla(real hue, real saturation, real lightness, real alpha) -Returns a Color with the specified \c hue, \c saturation, \c lightness and \c alpha components. +Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components. All components should be in the range 0-1 inclusive. */ QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine *engine) @@ -1416,7 +1428,9 @@ QScriptValue QDeclarativeEnginePrivate::hsla(QScriptContext *ctxt, QScriptEngine /*! \qmlmethod rect Qt::rect(int x, int y, int width, int height) -Returns a Rect with the top-left corner at \c x, \c y and the specified \c width and \c height. +Returns a \c rect with the top-left corner at \c x, \c y and the specified \c width and \c height. + +The returned object has \c x, \c y, \c width and \c height attributes with the given values. */ QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine *engine) { -- cgit v0.12