X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fdeclarative%2Fitems%2Fqsgtextinput.cpp;h=d30faadb34115a1eca5824b45faa599bcce7a6ff;hb=8e6ecb56e5d61ce661422779c9d9cbf22f081a34;hp=405540d419cc708a0df50fb865e2c5d3a2af5192;hpb=c9224b6cf5cceb7d5314f7504d44bfe72bc66950;p=profile%2Fivi%2Fqtdeclarative.git diff --git a/src/declarative/items/qsgtextinput.cpp b/src/declarative/items/qsgtextinput.cpp index 405540d..d30faad 100644 --- a/src/declarative/items/qsgtextinput.cpp +++ b/src/declarative/items/qsgtextinput.cpp @@ -45,19 +45,43 @@ #include #include +#include #include #include #include #include #include +#include +#include QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD) + QWidgetPrivate *qt_widget_private(QWidget *widget); +/*! + \qmlclass TextInput QSGTextInput + \inqmlmodule QtQuick 2 + \ingroup qml-basic-visual-elements + \brief The TextInput item displays an editable line of text. + \inherits Item + + The TextInput element displays a single line of editable plain text. + + TextInput is used to accept a line of text input. Input constraints + can be placed on a TextInput item (for example, through a \l validator or \l inputMask), + and setting \l echoMode to an appropriate value enables TextInput to be used for + a password input field. + + On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled. + If you want such bindings (on any platform), you will need to construct them in QML. + + \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example} +*/ QSGTextInput::QSGTextInput(QSGItem* parent) -: QSGImplicitSizePaintedItem(*(new QSGTextInputPrivate), parent) +: QSGImplicitSizeItem(*(new QSGTextInputPrivate), parent) { Q_D(QSGTextInput); d->init(); @@ -67,6 +91,11 @@ QSGTextInput::~QSGTextInput() { } +/*! + \qmlproperty string QtQuick2::TextInput::text + + The text in the TextInput. +*/ QString QSGTextInput::text() const { Q_D(const QSGTextInput); @@ -81,6 +110,111 @@ void QSGTextInput::setText(const QString &s) d->control->setText(s); } +/*! + \qmlproperty string QtQuick2::TextInput::font.family + + Sets the family name of the font. + + The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]". + If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen. + If the family isn't available a family will be set using the font matching algorithm. +*/ + +/*! + \qmlproperty bool QtQuick2::TextInput::font.bold + + Sets whether the font weight is bold. +*/ + +/*! + \qmlproperty enumeration QtQuick2::TextInput::font.weight + + Sets the font's weight. + + The weight can be one of: + \list + \o Font.Light + \o Font.Normal - the default + \o Font.DemiBold + \o Font.Bold + \o Font.Black + \endlist + + \qml + TextInput { text: "Hello"; font.weight: Font.DemiBold } + \endqml +*/ + +/*! + \qmlproperty bool QtQuick2::TextInput::font.italic + + Sets whether the font has an italic style. +*/ + +/*! + \qmlproperty bool QtQuick2::TextInput::font.underline + + Sets whether the text is underlined. +*/ + +/*! + \qmlproperty bool QtQuick2::TextInput::font.strikeout + + Sets whether the font has a strikeout style. +*/ + +/*! + \qmlproperty real QtQuick2::TextInput::font.pointSize + + Sets the font size in points. The point size must be greater than zero. +*/ + +/*! + \qmlproperty int QtQuick2::TextInput::font.pixelSize + + Sets the font size in pixels. + + Using this function makes the font device dependent. + Use \c pointSize to set the size of the font in a device independent manner. +*/ + +/*! + \qmlproperty real QtQuick2::TextInput::font.letterSpacing + + Sets the letter spacing for the font. + + Letter spacing changes the default spacing between individual letters in the font. + A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing. +*/ + +/*! + \qmlproperty real QtQuick2::TextInput::font.wordSpacing + + Sets the word spacing for the font. + + Word spacing changes the default spacing between individual words. + A positive value increases the word spacing by a corresponding amount of pixels, + while a negative value decreases the inter-word spacing accordingly. +*/ + +/*! + \qmlproperty enumeration QtQuick2::TextInput::font.capitalization + + Sets the capitalization for the text. + + \list + \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied. + \o Font.AllUppercase - This alters the text to be rendered in all uppercase type. + \o Font.AllLowercase - This alters the text to be rendered in all lowercase type. + \o Font.SmallCaps - This alters the text to be rendered in small-caps type. + \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character. + \endlist + + \qml + TextInput { text: "Hello"; font.capitalization: Font.AllLowercase } + \endqml +*/ + QFont QSGTextInput::font() const { Q_D(const QSGTextInput); @@ -112,6 +246,11 @@ void QSGTextInput::setFont(const QFont &font) emit fontChanged(d->sourceFont); } +/*! + \qmlproperty color QtQuick2::TextInput::color + + The text color. +*/ QColor QSGTextInput::color() const { Q_D(const QSGTextInput); @@ -128,6 +267,12 @@ void QSGTextInput::setColor(const QColor &c) } } + +/*! + \qmlproperty color QtQuick2::TextInput::selectionColor + + The text highlight color, used behind selections. +*/ QColor QSGTextInput::selectionColor() const { Q_D(const QSGTextInput); @@ -144,11 +289,15 @@ void QSGTextInput::setSelectionColor(const QColor &color) QPalette p = d->control->palette(); p.setColor(QPalette::Highlight, d->selectionColor); d->control->setPalette(p); - if (d->control->hasSelectedText()) + if (d->control->hasSelectedText()) update(); emit selectionColorChanged(color); } +/*! + \qmlproperty color QtQuick2::TextInput::selectedTextColor + The highlighted text color, used in selections. +*/ QColor QSGTextInput::selectedTextColor() const { Q_D(const QSGTextInput); @@ -165,11 +314,34 @@ void QSGTextInput::setSelectedTextColor(const QColor &color) QPalette p = d->control->palette(); p.setColor(QPalette::HighlightedText, d->selectedTextColor); d->control->setPalette(p); - if (d->control->hasSelectedText()) + if (d->control->hasSelectedText()) update(); emit selectedTextColorChanged(color); } +/*! + \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment + \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment + + Sets the horizontal alignment of the text within the TextInput item's + width and height. By default, the text alignment follows the natural alignment + of the text, for example text that is read from left to right will be aligned to + the left. + + TextInput does not have vertical alignment, as the natural height is + exactly the height of the single line of text. If you set the height + manually to something larger, TextInput will always be top aligned + vertically. You can use anchors to align it however you want within + another item. + + The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and + \c TextInput.AlignHCenter. + + When using the attached property LayoutMirroring::enabled to mirror application + layouts, the horizontal alignment of text will also be mirrored. However, the property + \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment + of TextInput, use the read-only property \c effectiveHorizontalAlignment. +*/ QSGTextInput::HAlignment QSGTextInput::hAlign() const { Q_D(const QSGTextInput); @@ -250,6 +422,15 @@ void QSGTextInputPrivate::mirrorChange() } } +/*! + \qmlproperty bool QtQuick2::TextInput::readOnly + + Sets whether user input can modify the contents of the TextInput. + + If readOnly is set to true, then user input will not affect the text + property. Any bindings or attempts to set the text property will still + work. +*/ bool QSGTextInput::isReadOnly() const { Q_D(const QSGTextInput); @@ -270,6 +451,14 @@ void QSGTextInput::setReadOnly(bool ro) emit readOnlyChanged(ro); } +/*! + \qmlproperty int QtQuick2::TextInput::maximumLength + The maximum permitted length of the text in the TextInput. + + If the text is too long, it is truncated at the limit. + + By default, this property contains a value of 32767. +*/ int QSGTextInput::maxLength() const { Q_D(const QSGTextInput); @@ -287,6 +476,32 @@ void QSGTextInput::setMaxLength(int ml) emit maximumLengthChanged(ml); } +/*! + \qmlproperty bool QtQuick2::TextInput::cursorVisible + Set to true when the TextInput shows a cursor. + + This property is set and unset when the TextInput gets active focus, so that other + properties can be bound to whether the cursor is currently showing. As it + gets set and unset automatically, when you set the value yourself you must + keep in mind that your value may be overwritten. + + It can be set directly in script, for example if a KeyProxy might + forward keys to it and you desire it to look active when this happens + (but without actually giving it active focus). + + It should not be set directly on the element, like in the below QML, + as the specified value will be overridden an lost on focus changes. + + \code + TextInput { + text: "Text" + cursorVisible: false + } + \endcode + + In the above snippet the cursor will still become visible when the + TextInput gains active focus. +*/ bool QSGTextInput::isCursorVisible() const { Q_D(const QSGTextInput); @@ -308,6 +523,10 @@ void QSGTextInput::setCursorVisible(bool on) emit cursorVisibleChanged(d->cursorVisible); } +/*! + \qmlproperty int QtQuick2::TextInput::cursorPosition + The position of the cursor in the TextInput. +*/ int QSGTextInput::cursorPosition() const { Q_D(const QSGTextInput); @@ -321,6 +540,10 @@ void QSGTextInput::setCursorPosition(int cp) d->control->moveCursor(cp); } +/*! + Returns a Rect which encompasses the cursor, but which may be larger than is + required. Ignores custom cursor delegates. +*/ QRect QSGTextInput::cursorRectangle() const { Q_D(const QSGTextInput); @@ -331,19 +554,49 @@ QRect QSGTextInput::cursorRectangle() const r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1); return r; } +/*! + \qmlproperty int QtQuick2::TextInput::selectionStart + + The cursor position before the first character in the current selection. + + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). + \sa selectionEnd, cursorPosition, selectedText +*/ int QSGTextInput::selectionStart() const { Q_D(const QSGTextInput); return d->lastSelectionStart; } +/*! + \qmlproperty int QtQuick2::TextInput::selectionEnd + The cursor position after the last character in the current selection. + + This property is read-only. To change the selection, use select(start,end), + selectAll(), or selectWord(). + + \sa selectionStart, cursorPosition, selectedText +*/ int QSGTextInput::selectionEnd() const { Q_D(const QSGTextInput); return d->lastSelectionEnd; } +/*! + \qmlmethod void QtQuick2::TextInput::select(int start, int 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 QSGTextInput::select(int start, int end) { Q_D(QSGTextInput); @@ -352,12 +605,32 @@ void QSGTextInput::select(int start, int end) d->control->setSelection(start, end-start); } +/*! + \qmlproperty string QtQuick2::TextInput::selectedText + + This read-only property provides the text currently selected in the + text input. + + It is equivalent to the following snippet, but is faster and easier + to use. + + \js + myTextInput.text.toString().substring(myTextInput.selectionStart, + myTextInput.selectionEnd); + \endjs +*/ QString QSGTextInput::selectedText() const { Q_D(const QSGTextInput); return d->control->selectedText(); } +/*! + \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress + + Whether the TextInput should gain active focus on a mouse press. By default this is + set to true. +*/ bool QSGTextInput::focusOnPress() const { Q_D(const QSGTextInput); @@ -374,7 +647,12 @@ void QSGTextInput::setFocusOnPress(bool b) emit activeFocusOnPressChanged(d->focusOnPress); } +/*! + \qmlproperty bool QtQuick2::TextInput::autoScroll + Whether the TextInput should scroll when the text is longer than the width. By default this is + set to true. +*/ bool QSGTextInput::autoScroll() const { Q_D(const QSGTextInput); @@ -395,6 +673,114 @@ void QSGTextInput::setAutoScroll(bool b) } #ifndef QT_NO_VALIDATOR + +/*! + \qmlclass IntValidator QIntValidator + \inqmlmodule QtQuick 2 + \ingroup qml-basic-visual-elements + + This element provides a validator for integer values. + + IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and + will accept locale specific digits, group separators, and positive and negative signs. In + addition, IntValidator is always guaranteed to accept a number formatted according to the "C" + locale. +*/ +/*! + \qmlproperty int QtQuick2::IntValidator::top + + This property holds the validator's highest acceptable value. + By default, this property's value is derived from the highest signed integer available (typically 2147483647). +*/ +/*! + \qmlproperty int QtQuick2::IntValidator::bottom + + This property holds the validator's lowest acceptable value. + By default, this property's value is derived from the lowest signed integer available (typically -2147483647). +*/ + +/*! + \qmlclass DoubleValidator QDoubleValidator + \inqmlmodule QtQuick 2 + \ingroup qml-basic-visual-elements + + This element provides a validator for non-integer numbers. +*/ + +/*! + \qmlproperty real QtQuick2::DoubleValidator::top + + This property holds the validator's maximum acceptable value. + By default, this property contains a value of infinity. +*/ +/*! + \qmlproperty real QtQuick2::DoubleValidator::bottom + + This property holds the validator's minimum acceptable value. + By default, this property contains a value of -infinity. +*/ +/*! + \qmlproperty int QtQuick2::DoubleValidator::decimals + + This property holds the validator's maximum number of digits after the decimal point. + By default, this property contains a value of 1000. +*/ +/*! + \qmlproperty enumeration QtQuick2::DoubleValidator::notation + This property holds the notation of how a string can describe a number. + + The possible values for this property are: + + \list + \o DoubleValidator.StandardNotation + \o DoubleValidator.ScientificNotation (default) + \endlist + + If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2). +*/ + +/*! + \qmlclass RegExpValidator QRegExpValidator + \inqmlmodule QtQuick 2 + \ingroup qml-basic-visual-elements + + This element provides a validator, which counts as valid any string which + matches a specified regular expression. +*/ +/*! + \qmlproperty regExp QtQuick2::RegExpValidator::regExp + + This property holds the regular expression used for validation. + + Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression + matching "a". + + By default, this property contains a regular expression with the pattern .* that matches any string. +*/ + +/*! + \qmlproperty Validator QtQuick2::TextInput::validator + + Allows you to set a validator on the TextInput. When a validator is set + the TextInput will only accept input which leaves the text property in + an acceptable or intermediate state. The accepted signal will only be sent + if the text is in an acceptable state when enter is pressed. + + Currently supported validators are IntValidator, DoubleValidator and + RegExpValidator. An example of using validators is shown below, which allows + input of integers between 11 and 31 into the text input: + + \code + import QtQuick 1.0 + TextInput{ + validator: IntValidator{bottom: 11; top: 31;} + focus: true + } + \endcode + + \sa acceptableInput, inputMask +*/ + QValidator* QSGTextInput::validator() const { Q_D(const QSGTextInput); @@ -418,6 +804,15 @@ void QSGTextInput::setValidator(QValidator* v) } #endif // QT_NO_VALIDATOR +/*! + \qmlproperty string QtQuick2::TextInput::inputMask + + Allows you to set an input mask on the TextInput, restricting the allowable + text inputs. See QLineEdit::inputMask for further details, as the exact + same mask strings are used by TextInput. + + \sa acceptableInput, validator +*/ QString QSGTextInput::inputMask() const { Q_D(const QSGTextInput); @@ -434,12 +829,29 @@ void QSGTextInput::setInputMask(const QString &im) emit inputMaskChanged(d->control->inputMask()); } +/*! + \qmlproperty bool QtQuick2::TextInput::acceptableInput + + This property is always true unless a validator or input mask has been set. + If a validator or input mask has been set, this property will only be true + if the current text is acceptable to the validator or input mask as a final + string (not as an intermediate string). +*/ bool QSGTextInput::hasAcceptableInput() const { Q_D(const QSGTextInput); return d->control->hasAcceptableInput(); } +/*! + \qmlsignal QtQuick2::TextInput::onAccepted() + + This handler is called when the Return or Enter key is pressed. + Note that if there is a \l validator or \l inputMask set on the text + input, the handler will only be emitted if the input is in an acceptable + state. +*/ + void QSGTextInputPrivate::updateInputMethodHints() { Q_Q(QSGTextInput); @@ -453,7 +865,18 @@ void QSGTextInputPrivate::updateInputMethodHints() hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); q->setInputMethodHints(hints); } - +/*! + \qmlproperty enumeration QtQuick2::TextInput::echoMode + + Specifies how the text should be displayed in the TextInput. + \list + \o TextInput.Normal - Displays the text as it is. (Default) + \o TextInput.Password - Displays asterixes instead of characters. + \o TextInput.NoEcho - Displays nothing. + \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered + while editing, otherwise displays asterisks. + \endlist +*/ QSGTextInput::EchoMode QSGTextInput::echoMode() const { Q_D(const QSGTextInput); @@ -486,6 +909,19 @@ void QSGTextInput::setIMHints(Qt::InputMethodHints hints) d->updateInputMethodHints(); } +/*! + \qmlproperty Component QtQuick2::TextInput::cursorDelegate + The delegate for the cursor in the TextInput. + + If you set a cursorDelegate for a TextInput, this delegate will be used for + drawing the cursor instead of the standard cursor. An instance of the + delegate will be created and managed by the TextInput when a cursor is + needed, and the x property of delegate instance will be set so as + to be one pixel before the top left of the current character. + + Note that the root item of the delegate component must be a QDeclarativeItem or + QDeclarativeItem derived item. +*/ QDeclarativeComponent* QSGTextInput::cursorDelegate() const { Q_D(const QSGTextInput); @@ -547,6 +983,15 @@ void QSGTextInput::createCursor() d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text. } +/*! + \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos) + + This function takes a character position and returns the rectangle that the + cursor would occupy, if it was placed at that character position. + + This is similar to setting the cursorPosition, and then querying the cursor + rectangle, but the cursorPosition is not changed. +*/ QRectF QSGTextInput::positionToRectangle(int pos) const { Q_D(const QSGTextInput); @@ -558,6 +1003,24 @@ QRectF QSGTextInput::positionToRectangle(int pos) const cursorRectangle().height()); } +/*! + \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters) + + This function returns the character position at + x pixels from the left of the textInput. Position 0 is before the + first character, position 1 is after the first character but before the second, + and so on until position text.length, which is after all characters. + + 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. + + The cursor position type specifies how the cursor position should be resolved. + + \list + \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x. + \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x. + \endlist +*/ int QSGTextInput::positionAt(int x) const { return positionAt(x, CursorBetweenCharacters); @@ -597,7 +1060,7 @@ void QSGTextInput::keyPressEvent(QKeyEvent* ev) d->control->processKeyEvent(ev); } if (!ev->isAccepted()) - QSGPaintedItem::keyPressEvent(ev); + QSGImplicitSizeItem::keyPressEvent(ev); } void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev) @@ -610,7 +1073,7 @@ void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev) d->control->processInputMethodEvent(ev); } if (!ev->isAccepted()) - QSGPaintedItem::inputMethodEvent(ev); + QSGImplicitSizeItem::inputMethodEvent(ev); if (wasComposing != (d->control->preeditAreaText().length() > 0)) emit inputMethodComposingChanged(); @@ -626,7 +1089,7 @@ void QSGTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) d->control->selectWordAtPos(cursor); event->setAccepted(true); } else { - QSGPaintedItem::mouseDoubleClickEvent(event); + QSGImplicitSizeItem::mouseDoubleClickEvent(event); } } @@ -671,7 +1134,7 @@ void QSGTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event) moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode); event->setAccepted(true); } else { - QSGPaintedItem::mouseMoveEvent(event); + QSGImplicitSizeItem::mouseMoveEvent(event); } } @@ -696,7 +1159,7 @@ void QSGTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) d->clickCausedFocus = false; d->control->processEvent(event); if (!event->isAccepted()) - QSGPaintedItem::mouseReleaseEvent(event); + QSGImplicitSizeItem::mouseReleaseEvent(event); } bool QSGTextInputPrivate::sendMouseEventToInputContext( @@ -762,7 +1225,7 @@ bool QSGTextInput::event(QEvent* ev) handled = d->control->processEvent(ev); } if(!handled) - handled = QSGPaintedItem::event(ev); + handled = QSGImplicitSizeItem::event(ev); return handled; } @@ -773,7 +1236,7 @@ void QSGTextInput::geometryChanged(const QRectF &newGeometry, updateSize(); updateCursorRectangle(); } - QSGPaintedItem::geometryChanged(newGeometry, oldGeometry); + QSGImplicitSizeItem::geometryChanged(newGeometry, oldGeometry); } int QSGTextInputPrivate::calculateTextWidth() @@ -827,25 +1290,73 @@ void QSGTextInputPrivate::updateHorizontalScroll() } } -void QSGTextInput::paint(QPainter *p) +QSGNode *QSGTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) { - // XXX todo - QRect r = boundingRect().toRect(); - + Q_UNUSED(data); Q_D(QSGTextInput); - p->setRenderHint(QPainter::TextAntialiasing, true); - p->save(); - p->setPen(QPen(d->color)); - int flags = QLineControl::DrawText; - if(!isReadOnly() && d->cursorVisible && !d->cursorItem) - flags |= QLineControl::DrawCursor; - if (d->control->hasSelectedText()) - flags |= QLineControl::DrawSelections; - QFontMetrics fm = QFontMetrics(d->font); - // the y offset is there to keep the baseline constant in case we have script changes in the text. - QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent()); - d->control->draw(p, offset, r, flags); - p->restore(); + + QSGTextNode *node = static_cast(oldNode); + if (node == 0) + node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext()); + d->textNode = node; + + if (!d->textLayoutDirty) { + QSGSimpleRectNode *cursorNode = node->cursorNode(); + if (cursorNode != 0 && !isReadOnly()) { + QFontMetrics fm = QFontMetrics(d->font); + // the y offset is there to keep the baseline constant in case we have script changes in the text. + QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent()); + offset.rx() += d->control->cursorToX(); + + QRect br(boundingRect().toRect()); + cursorNode->setRect(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height()))); + + if (!d->cursorVisible + || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) { + d->hideCursor(); + } else { + d->showCursor(); + } + } + } else { + node->deleteContent(); + node->setMatrix(QMatrix4x4()); + + QPoint offset = QPoint(0,0); + QFontMetrics fm = QFontMetrics(d->font); + QRect br(boundingRect().toRect()); + if (d->autoScroll) { + // the y offset is there to keep the baseline constant in case we have script changes in the text. + offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent()); + } else { + offset = QPoint(d->hscroll, 0); + } + + QTextLayout *textLayout = d->control->textLayout(); + if (!textLayout->text().isEmpty()) { + node->addTextLayout(offset, textLayout, d->color, + QSGText::Normal, QColor(), + d->selectionColor, d->selectedTextColor, + d->control->selectionStart(), + d->control->selectionEnd() - 1); // selectionEnd() returns first char after + // selection + } + + if (!isReadOnly() && d->cursorItem == 0) { + offset.rx() += d->control->cursorToX(); + node->setCursor(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())), d->color); + if (!d->cursorVisible + || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) { + d->hideCursor(); + } else { + d->showCursor(); + } + } + + d->textLayoutDirty = false; + } + + return node; } QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const @@ -879,18 +1390,34 @@ QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const } } +/*! + \qmlmethod void QtQuick2::TextInput::deselect() + + Removes active text selection. +*/ void QSGTextInput::deselect() { Q_D(QSGTextInput); d->control->deselect(); } +/*! + \qmlmethod void QtQuick2::TextInput::selectAll() + + Causes all text to be selected. +*/ void QSGTextInput::selectAll() { Q_D(QSGTextInput); d->control->setSelection(0, d->control->text().length()); } +/*! + \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end) + + Returns true if the natural reading direction of the editor text + found between positions \a start and \a end is right to left. +*/ bool QSGTextInput::isRightToLeft(int start, int end) { Q_D(QSGTextInput); @@ -903,6 +1430,11 @@ bool QSGTextInput::isRightToLeft(int start, int end) } #ifndef QT_NO_CLIPBOARD +/*! + \qmlmethod QtQuick2::TextInput::cut() + + Moves the currently selected text to the system clipboard. +*/ void QSGTextInput::cut() { Q_D(QSGTextInput); @@ -910,12 +1442,22 @@ void QSGTextInput::cut() d->control->del(); } +/*! + \qmlmethod QtQuick2::TextInput::copy() + + Copies the currently selected text to the system clipboard. +*/ void QSGTextInput::copy() { Q_D(QSGTextInput); d->control->copy(); } +/*! + \qmlmethod QtQuick2::TextInput::paste() + + Replaces the currently selected text by the contents of the system clipboard. +*/ void QSGTextInput::paste() { Q_D(QSGTextInput); @@ -924,12 +1466,41 @@ void QSGTextInput::paste() } #endif // QT_NO_CLIPBOARD +/*! + \qmlmethod void QtQuick2::TextInput::selectWord() + + Causes the word closest to the current cursor position to be selected. +*/ void QSGTextInput::selectWord() { Q_D(QSGTextInput); d->control->selectWordAtPos(d->control->cursor()); } +/*! + \qmlproperty bool QtQuick2::TextInput::smooth + + This property holds whether the text is smoothly scaled or transformed. + + Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + +/*! + \qmlproperty string QtQuick2::TextInput::passwordCharacter + + This is the character displayed when echoMode is set to Password or + PasswordEchoOnEdit. By default it is an asterisk. + + If this property is set to a string with more than one character, + the first character is used. If the string is empty, the value + is ignored and the property is not set. +*/ QString QSGTextInput::passwordCharacter() const { Q_D(const QSGTextInput); @@ -949,12 +1520,32 @@ void QSGTextInput::setPasswordCharacter(const QString &str) emit passwordCharacterChanged(); } +/*! + \qmlproperty string QtQuick2::TextInput::displayText + + This is the text displayed in the TextInput. + + If \l echoMode is set to TextInput::Normal, this holds the + same value as the TextInput::text property. Otherwise, + this property holds the text visible to the user, while + the \l text property holds the actual entered text. +*/ QString QSGTextInput::displayText() const { Q_D(const QSGTextInput); return d->control->displayText(); } +/*! + \qmlproperty bool QtQuick2::TextInput::selectByMouse + + Defaults to false. + + If true, the user can use the mouse to select text in some + platform-specific way. Note that for some platforms this may + not be an appropriate interaction (eg. may conflict with how + the text needs to behave inside a Flickable. +*/ bool QSGTextInput::selectByMouse() const { Q_D(const QSGTextInput); @@ -970,6 +1561,19 @@ void QSGTextInput::setSelectByMouse(bool on) } } +/*! + \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode + + Specifies how text should be selected using a mouse. + + \list + \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default) + \o TextInput.SelectWords - The selection is updated with whole words. + \endlist + + This property only applies when \l selectByMouse is true. +*/ + QSGTextInput::SelectionMode QSGTextInput::mouseSelectionMode() const { Q_D(const QSGTextInput); @@ -985,6 +1589,12 @@ void QSGTextInput::setMouseSelectionMode(SelectionMode mode) } } +/*! + \qmlproperty bool QtQuick2::TextInput::canPaste + + Returns true if the TextInput is writable and the content of the clipboard is + suitable for pasting into the TextEdit. +*/ bool QSGTextInput::canPaste() const { Q_D(const QSGTextInput); @@ -997,6 +1607,43 @@ void QSGTextInput::moveCursorSelection(int position) d->control->moveCursor(position, true); } +/*! + \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters) + + Moves the cursor to \a position and updates the selection according to the optional \a mode + parameter. (To only move the cursor, set the \l cursorPosition property.) + + When this method is called it additionally sets either the + selectionStart or the selectionEnd (whichever was at the previous cursor position) + to the specified position. This allows you to easily extend and contract the selected + text range. + + The selection mode specifies whether the selection is updated on a per character or a per word + basis. If not specified the selection mode will default to TextInput.SelectCharacters. + + \list + \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at + the previous cursor position) to the specified position. + \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all + words between the specified postion and the previous cursor position. Words partially in the + range are included. + \endlist + + For example, take this sequence of calls: + + \code + cursorPosition = 5 + moveCursorSelection(9, TextInput.SelectCharacters) + moveCursorSelection(7, TextInput.SelectCharacters) + \endcode + + This moves the cursor to position 5, extend the selection end from 5 to 9 + and then retract the selection end from 9 to 7, leaving the text from position 5 to 7 + selected (the 6th and 7th characters). + + The same sequence with TextInput.SelectWords will extend the selection start to a word boundary + before or on position 5 and extend the selection end to a word boundary on or past position 9. +*/ void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode) { Q_D(QSGTextInput); @@ -1054,6 +1701,45 @@ void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode) } } +/*! + \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel() + + Opens software input panels like virtual keyboards for typing, useful for + customizing when you want the input keyboard to be shown and hidden in + your application. + + By default the opening of input panels follows the platform style. On Symbian^1 and + Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms + the panels are automatically opened when TextInput element gains active focus. Input panels are + always closed if no editor has active focus. + + . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement + the behavior you want. + + Only relevant on platforms, which provide virtual keyboards. + + \qml + import QtQuick 1.0 + TextInput { + id: textInput + text: "Hello world!" + activeFocusOnPress: false + MouseArea { + anchors.fill: parent + onClicked: { + if (!textInput.activeFocus) { + textInput.forceActiveFocus() + textInput.openSoftwareInputPanel(); + } else { + textInput.focus = false; + } + } + onPressAndHold: textInput.closeSoftwareInputPanel(); + } + } + \endqml +*/ void QSGTextInput::openSoftwareInputPanel() { if (qApp) { @@ -1064,6 +1750,45 @@ void QSGTextInput::openSoftwareInputPanel() } } +/*! + \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel() + + Closes a software input panel like a virtual keyboard shown on the screen, useful + for customizing when you want the input keyboard to be shown and hidden in + your application. + + By default the opening of input panels follows the platform style. On Symbian^1 and + Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms + the panels are automatically opened when TextInput element gains active focus. Input panels are + always closed if no editor has active focus. + + . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false + and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement + the behavior you want. + + Only relevant on platforms, which provide virtual keyboards. + + \qml + import QtQuick 1.0 + TextInput { + id: textInput + text: "Hello world!" + activeFocusOnPress: false + MouseArea { + anchors.fill: parent + onClicked: { + if (!textInput.activeFocus) { + textInput.forceActiveFocus(); + textInput.openSoftwareInputPanel(); + } else { + textInput.focus = false; + } + } + onPressAndHold: textInput.closeSoftwareInputPanel(); + } + } + \endqml +*/ void QSGTextInput::closeSoftwareInputPanel() { if (qApp) { @@ -1082,7 +1807,7 @@ void QSGTextInput::focusInEvent(QFocusEvent *event) openSoftwareInputPanel(); } } - QSGPaintedItem::focusInEvent(event); + QSGImplicitSizeItem::focusInEvent(event); } void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value) @@ -1100,6 +1825,18 @@ void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value) QSGItem::itemChange(change, value); } +/*! + \qmlproperty bool QtQuick2::TextInput::inputMethodComposing + + + This property holds whether the TextInput has partial text input from an + input method. + + While it is composing an input method may rely on mouse or key events from + the TextInput to edit or commit the partial text. This property can be + used to determine when to disable events handlers that may interfere with + the correct operation of an input method. +*/ bool QSGTextInput::isInputMethodComposing() const { Q_D(const QSGTextInput); @@ -1109,12 +1846,16 @@ bool QSGTextInput::isInputMethodComposing() const void QSGTextInputPrivate::init() { Q_Q(QSGTextInput); +#if defined(Q_WS_MAC) + control->setThreadChecks(true); +#endif control->setParent(q);//Now mandatory due to accessibility changes control->setCursorWidth(1); control->setPasswordCharacter(QLatin1Char('*')); q->setSmooth(smooth); q->setAcceptedMouseButtons(Qt::LeftButton); q->setFlag(QSGItem::ItemAcceptsInputMethod); + q->setFlag(QSGItem::ItemHasContents); q->connect(control, SIGNAL(cursorPositionChanged(int,int)), q, SLOT(cursorPosChanged())); q->connect(control, SIGNAL(selectionChanged()), @@ -1144,6 +1885,12 @@ void QSGTextInputPrivate::init() selectedTextColor = p.color(QPalette::HighlightedText); selectionColor = p.color(QPalette::Highlight); determineHorizontalAlignment(); + + if (!qmlDisableDistanceField()) { + QTextOption option = control->textLayout()->textOption(); + option.setUseDesignMetrics(true); + control->textLayout()->setTextOption(option); + } } void QSGTextInput::cursorPosChanged() @@ -1214,19 +1961,35 @@ void QSGTextInput::q_textChanged() } } +void QSGTextInputPrivate::showCursor() +{ + if (textNode != 0 && textNode->cursorNode() != 0) + textNode->cursorNode()->setColor(color); +} + +void QSGTextInputPrivate::hideCursor() +{ + if (textNode != 0 && textNode->cursorNode() != 0) + textNode->cursorNode()->setColor(QColor(0, 0, 0, 0)); +} + void QSGTextInput::updateRect(const QRect &r) { Q_D(QSGTextInput); - if(r == QRect()) - update(); - else - update(QRect(r.x() - d->hscroll, r.y(), r.width(), r.height())); + if (!isComponentComplete()) + return; + + if (r.isEmpty()) { + d->textLayoutDirty = true; + } + + update(); } QRectF QSGTextInput::boundingRect() const { Q_D(const QSGTextInput); - QRectF r = QSGPaintedItem::boundingRect(); + QRectF r = QSGImplicitSizeItem::boundingRect(); int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth(); @@ -1243,7 +2006,6 @@ void QSGTextInput::updateSize(bool needsRedraw) int h = height(); setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text. setImplicitWidth(d->calculateTextWidth()); - setContentsSize(boundingRect().size().toSize()); if(w==width() && h==height() && needsRedraw) update(); }