1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qsgtextinput_p.h"
43 #include "qsgtextinput_p_p.h"
44 #include "qsgcanvas.h"
46 #include <private/qdeclarativeglobal_p.h>
47 #include <private/qwidget_p.h>
48 #include <private/qsgdistancefieldglyphcache_p.h>
50 #include <QtDeclarative/qdeclarativeinfo.h>
51 #include <QtWidgets/qgraphicssceneevent.h>
52 #include <QtWidgets/qinputcontext.h>
53 #include <QTextBoundaryFinder>
55 #include <qsgtextnode_p.h>
56 #include <qsgsimplerectnode.h>
60 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
62 QWidgetPrivate *qt_widget_private(QWidget *widget);
65 \qmlclass TextInput QSGTextInput
66 \inqmlmodule QtQuick 2
67 \ingroup qml-basic-visual-elements
68 \brief The TextInput item displays an editable line of text.
71 The TextInput element displays a single line of editable plain text.
73 TextInput is used to accept a line of text input. Input constraints
74 can be placed on a TextInput item (for example, through a \l validator or \l inputMask),
75 and setting \l echoMode to an appropriate value enables TextInput to be used for
76 a password input field.
78 On Mac OS X, the Up/Down key bindings for Home/End are explicitly disabled.
79 If you want such bindings (on any platform), you will need to construct them in QML.
81 \sa TextEdit, Text, {declarative/text/textselection}{Text Selection example}
83 QSGTextInput::QSGTextInput(QSGItem* parent)
84 : QSGImplicitSizeItem(*(new QSGTextInputPrivate), parent)
90 QSGTextInput::~QSGTextInput()
95 \qmlproperty string QtQuick2::TextInput::text
97 The text in the TextInput.
99 QString QSGTextInput::text() const
101 Q_D(const QSGTextInput);
102 return d->control->text();
105 void QSGTextInput::setText(const QString &s)
110 d->control->setText(s);
114 \qmlproperty string QtQuick2::TextInput::font.family
116 Sets the family name of the font.
118 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
119 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
120 If the family isn't available a family will be set using the font matching algorithm.
124 \qmlproperty bool QtQuick2::TextInput::font.bold
126 Sets whether the font weight is bold.
130 \qmlproperty enumeration QtQuick2::TextInput::font.weight
132 Sets the font's weight.
134 The weight can be one of:
137 \o Font.Normal - the default
144 TextInput { text: "Hello"; font.weight: Font.DemiBold }
149 \qmlproperty bool QtQuick2::TextInput::font.italic
151 Sets whether the font has an italic style.
155 \qmlproperty bool QtQuick2::TextInput::font.underline
157 Sets whether the text is underlined.
161 \qmlproperty bool QtQuick2::TextInput::font.strikeout
163 Sets whether the font has a strikeout style.
167 \qmlproperty real QtQuick2::TextInput::font.pointSize
169 Sets the font size in points. The point size must be greater than zero.
173 \qmlproperty int QtQuick2::TextInput::font.pixelSize
175 Sets the font size in pixels.
177 Using this function makes the font device dependent.
178 Use \c pointSize to set the size of the font in a device independent manner.
182 \qmlproperty real QtQuick2::TextInput::font.letterSpacing
184 Sets the letter spacing for the font.
186 Letter spacing changes the default spacing between individual letters in the font.
187 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
191 \qmlproperty real QtQuick2::TextInput::font.wordSpacing
193 Sets the word spacing for the font.
195 Word spacing changes the default spacing between individual words.
196 A positive value increases the word spacing by a corresponding amount of pixels,
197 while a negative value decreases the inter-word spacing accordingly.
201 \qmlproperty enumeration QtQuick2::TextInput::font.capitalization
203 Sets the capitalization for the text.
206 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
207 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
208 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
209 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
210 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
214 TextInput { text: "Hello"; font.capitalization: Font.AllLowercase }
218 QFont QSGTextInput::font() const
220 Q_D(const QSGTextInput);
221 return d->sourceFont;
224 void QSGTextInput::setFont(const QFont &font)
227 if (d->sourceFont == font)
230 d->sourceFont = font;
231 QFont oldFont = d->font;
233 if (d->font.pointSizeF() != -1) {
235 qreal size = qRound(d->font.pointSizeF()*2.0);
236 d->font.setPointSizeF(size/2.0);
238 if (oldFont != d->font) {
239 d->control->setFont(d->font);
241 updateCursorRectangle();
243 d->cursorItem->setHeight(QFontMetrics(d->font).height());
246 emit fontChanged(d->sourceFont);
250 \qmlproperty color QtQuick2::TextInput::color
254 QColor QSGTextInput::color() const
256 Q_D(const QSGTextInput);
260 void QSGTextInput::setColor(const QColor &c)
266 emit colorChanged(c);
272 \qmlproperty color QtQuick2::TextInput::selectionColor
274 The text highlight color, used behind selections.
276 QColor QSGTextInput::selectionColor() const
278 Q_D(const QSGTextInput);
279 return d->selectionColor;
282 void QSGTextInput::setSelectionColor(const QColor &color)
285 if (d->selectionColor == color)
288 d->selectionColor = color;
289 QPalette p = d->control->palette();
290 p.setColor(QPalette::Highlight, d->selectionColor);
291 d->control->setPalette(p);
292 if (d->control->hasSelectedText())
294 emit selectionColorChanged(color);
297 \qmlproperty color QtQuick2::TextInput::selectedTextColor
299 The highlighted text color, used in selections.
301 QColor QSGTextInput::selectedTextColor() const
303 Q_D(const QSGTextInput);
304 return d->selectedTextColor;
307 void QSGTextInput::setSelectedTextColor(const QColor &color)
310 if (d->selectedTextColor == color)
313 d->selectedTextColor = color;
314 QPalette p = d->control->palette();
315 p.setColor(QPalette::HighlightedText, d->selectedTextColor);
316 d->control->setPalette(p);
317 if (d->control->hasSelectedText())
319 emit selectedTextColorChanged(color);
323 \qmlproperty enumeration QtQuick2::TextInput::horizontalAlignment
324 \qmlproperty enumeration QtQuick2::TextInput::effectiveHorizontalAlignment
326 Sets the horizontal alignment of the text within the TextInput item's
327 width and height. By default, the text alignment follows the natural alignment
328 of the text, for example text that is read from left to right will be aligned to
331 TextInput does not have vertical alignment, as the natural height is
332 exactly the height of the single line of text. If you set the height
333 manually to something larger, TextInput will always be top aligned
334 vertically. You can use anchors to align it however you want within
337 The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and
338 \c TextInput.AlignHCenter.
340 When using the attached property LayoutMirroring::enabled to mirror application
341 layouts, the horizontal alignment of text will also be mirrored. However, the property
342 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
343 of TextInput, use the read-only property \c effectiveHorizontalAlignment.
345 QSGTextInput::HAlignment QSGTextInput::hAlign() const
347 Q_D(const QSGTextInput);
351 void QSGTextInput::setHAlign(HAlignment align)
354 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
355 d->hAlignImplicit = false;
356 if (d->setHAlign(align, forceAlign) && isComponentComplete()) {
357 updateCursorRectangle();
361 void QSGTextInput::resetHAlign()
364 d->hAlignImplicit = true;
365 if (d->determineHorizontalAlignment() && isComponentComplete()) {
366 updateCursorRectangle();
370 QSGTextInput::HAlignment QSGTextInput::effectiveHAlign() const
372 Q_D(const QSGTextInput);
373 QSGTextInput::HAlignment effectiveAlignment = d->hAlign;
374 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
376 case QSGTextInput::AlignLeft:
377 effectiveAlignment = QSGTextInput::AlignRight;
379 case QSGTextInput::AlignRight:
380 effectiveAlignment = QSGTextInput::AlignLeft;
386 return effectiveAlignment;
389 bool QSGTextInputPrivate::setHAlign(QSGTextInput::HAlignment alignment, bool forceAlign)
392 if ((hAlign != alignment || forceAlign) && alignment <= QSGTextInput::AlignHCenter) { // justify not supported
393 QSGTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
395 emit q->horizontalAlignmentChanged(alignment);
396 if (oldEffectiveHAlign != q->effectiveHAlign())
397 emit q->effectiveHorizontalAlignmentChanged();
403 bool QSGTextInputPrivate::determineHorizontalAlignment()
405 if (hAlignImplicit) {
406 // if no explicit alignment has been set, follow the natural layout direction of the text
407 QString text = control->text();
408 bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft();
409 return setHAlign(isRightToLeft ? QSGTextInput::AlignRight : QSGTextInput::AlignLeft);
414 void QSGTextInputPrivate::mirrorChange()
417 if (q->isComponentComplete()) {
418 if (!hAlignImplicit && (hAlign == QSGTextInput::AlignRight || hAlign == QSGTextInput::AlignLeft)) {
419 q->updateCursorRectangle();
420 emit q->effectiveHorizontalAlignmentChanged();
426 \qmlproperty bool QtQuick2::TextInput::readOnly
428 Sets whether user input can modify the contents of the TextInput.
430 If readOnly is set to true, then user input will not affect the text
431 property. Any bindings or attempts to set the text property will still
434 bool QSGTextInput::isReadOnly() const
436 Q_D(const QSGTextInput);
437 return d->control->isReadOnly();
440 void QSGTextInput::setReadOnly(bool ro)
443 if (d->control->isReadOnly() == ro)
446 setFlag(QSGItem::ItemAcceptsInputMethod, !ro);
447 d->control->setReadOnly(ro);
449 d->control->setCursorPosition(d->control->end());
451 emit readOnlyChanged(ro);
455 \qmlproperty int QtQuick2::TextInput::maximumLength
456 The maximum permitted length of the text in the TextInput.
458 If the text is too long, it is truncated at the limit.
460 By default, this property contains a value of 32767.
462 int QSGTextInput::maxLength() const
464 Q_D(const QSGTextInput);
465 return d->control->maxLength();
468 void QSGTextInput::setMaxLength(int ml)
471 if (d->control->maxLength() == ml)
474 d->control->setMaxLength(ml);
476 emit maximumLengthChanged(ml);
480 \qmlproperty bool QtQuick2::TextInput::cursorVisible
481 Set to true when the TextInput shows a cursor.
483 This property is set and unset when the TextInput gets active focus, so that other
484 properties can be bound to whether the cursor is currently showing. As it
485 gets set and unset automatically, when you set the value yourself you must
486 keep in mind that your value may be overwritten.
488 It can be set directly in script, for example if a KeyProxy might
489 forward keys to it and you desire it to look active when this happens
490 (but without actually giving it active focus).
492 It should not be set directly on the element, like in the below QML,
493 as the specified value will be overridden an lost on focus changes.
502 In the above snippet the cursor will still become visible when the
503 TextInput gains active focus.
505 bool QSGTextInput::isCursorVisible() const
507 Q_D(const QSGTextInput);
508 return d->cursorVisible;
511 void QSGTextInput::setCursorVisible(bool on)
514 if (d->cursorVisible == on)
516 d->cursorVisible = on;
517 d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0);
518 QRect r = d->control->cursorRect();
519 if (d->control->inputMask().isEmpty())
523 emit cursorVisibleChanged(d->cursorVisible);
527 \qmlproperty int QtQuick2::TextInput::cursorPosition
528 The position of the cursor in the TextInput.
530 int QSGTextInput::cursorPosition() const
532 Q_D(const QSGTextInput);
533 return d->control->cursor();
535 void QSGTextInput::setCursorPosition(int cp)
538 if (cp < 0 || cp > d->control->text().length())
540 d->control->moveCursor(cp);
544 Returns a Rect which encompasses the cursor, but which may be larger than is
545 required. Ignores custom cursor delegates.
547 QRect QSGTextInput::cursorRectangle() const
549 Q_D(const QSGTextInput);
550 QRect r = d->control->cursorRect();
551 // Scroll and make consistent with TextEdit
552 // QLineControl inexplicably adds 1 to the height and horizontal padding
553 // for unicode direction markers.
554 r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1);
558 \qmlproperty int QtQuick2::TextInput::selectionStart
560 The cursor position before the first character in the current selection.
562 This property is read-only. To change the selection, use select(start,end),
563 selectAll(), or selectWord().
565 \sa selectionEnd, cursorPosition, selectedText
567 int QSGTextInput::selectionStart() const
569 Q_D(const QSGTextInput);
570 return d->lastSelectionStart;
573 \qmlproperty int QtQuick2::TextInput::selectionEnd
575 The cursor position after the last character in the current selection.
577 This property is read-only. To change the selection, use select(start,end),
578 selectAll(), or selectWord().
580 \sa selectionStart, cursorPosition, selectedText
582 int QSGTextInput::selectionEnd() const
584 Q_D(const QSGTextInput);
585 return d->lastSelectionEnd;
588 \qmlmethod void QtQuick2::TextInput::select(int start, int end)
590 Causes the text from \a start to \a end to be selected.
592 If either start or end is out of range, the selection is not changed.
594 After calling this, selectionStart will become the lesser
595 and selectionEnd will become the greater (regardless of the order passed
598 \sa selectionStart, selectionEnd
600 void QSGTextInput::select(int start, int end)
603 if (start < 0 || end < 0 || start > d->control->text().length() || end > d->control->text().length())
605 d->control->setSelection(start, end-start);
609 \qmlproperty string QtQuick2::TextInput::selectedText
611 This read-only property provides the text currently selected in the
614 It is equivalent to the following snippet, but is faster and easier
618 myTextInput.text.toString().substring(myTextInput.selectionStart,
619 myTextInput.selectionEnd);
622 QString QSGTextInput::selectedText() const
624 Q_D(const QSGTextInput);
625 return d->control->selectedText();
629 \qmlproperty bool QtQuick2::TextInput::activeFocusOnPress
631 Whether the TextInput should gain active focus on a mouse press. By default this is
634 bool QSGTextInput::focusOnPress() const
636 Q_D(const QSGTextInput);
637 return d->focusOnPress;
640 void QSGTextInput::setFocusOnPress(bool b)
643 if (d->focusOnPress == b)
648 emit activeFocusOnPressChanged(d->focusOnPress);
651 \qmlproperty bool QtQuick2::TextInput::autoScroll
653 Whether the TextInput should scroll when the text is longer than the width. By default this is
656 bool QSGTextInput::autoScroll() const
658 Q_D(const QSGTextInput);
659 return d->autoScroll;
662 void QSGTextInput::setAutoScroll(bool b)
665 if (d->autoScroll == b)
669 //We need to repaint so that the scrolling is taking into account.
671 updateCursorRectangle();
672 emit autoScrollChanged(d->autoScroll);
675 #ifndef QT_NO_VALIDATOR
678 \qmlclass IntValidator QIntValidator
679 \inqmlmodule QtQuick 2
680 \ingroup qml-basic-visual-elements
682 This element provides a validator for integer values.
684 IntValidator uses the \l {QLocale::setDefault()}{default locale} to interpret the number and
685 will accept locale specific digits, group separators, and positive and negative signs. In
686 addition, IntValidator is always guaranteed to accept a number formatted according to the "C"
690 \qmlproperty int QtQuick2::IntValidator::top
692 This property holds the validator's highest acceptable value.
693 By default, this property's value is derived from the highest signed integer available (typically 2147483647).
696 \qmlproperty int QtQuick2::IntValidator::bottom
698 This property holds the validator's lowest acceptable value.
699 By default, this property's value is derived from the lowest signed integer available (typically -2147483647).
703 \qmlclass DoubleValidator QDoubleValidator
704 \inqmlmodule QtQuick 2
705 \ingroup qml-basic-visual-elements
707 This element provides a validator for non-integer numbers.
711 \qmlproperty real QtQuick2::DoubleValidator::top
713 This property holds the validator's maximum acceptable value.
714 By default, this property contains a value of infinity.
717 \qmlproperty real QtQuick2::DoubleValidator::bottom
719 This property holds the validator's minimum acceptable value.
720 By default, this property contains a value of -infinity.
723 \qmlproperty int QtQuick2::DoubleValidator::decimals
725 This property holds the validator's maximum number of digits after the decimal point.
726 By default, this property contains a value of 1000.
729 \qmlproperty enumeration QtQuick2::DoubleValidator::notation
730 This property holds the notation of how a string can describe a number.
732 The possible values for this property are:
735 \o DoubleValidator.StandardNotation
736 \o DoubleValidator.ScientificNotation (default)
739 If this property is set to DoubleValidator.ScientificNotation, the written number may have an exponent part (e.g. 1.5E-2).
743 \qmlclass RegExpValidator QRegExpValidator
744 \inqmlmodule QtQuick 2
745 \ingroup qml-basic-visual-elements
747 This element provides a validator, which counts as valid any string which
748 matches a specified regular expression.
751 \qmlproperty regExp QtQuick2::RegExpValidator::regExp
753 This property holds the regular expression used for validation.
755 Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular expression
758 By default, this property contains a regular expression with the pattern .* that matches any string.
762 \qmlproperty Validator QtQuick2::TextInput::validator
764 Allows you to set a validator on the TextInput. When a validator is set
765 the TextInput will only accept input which leaves the text property in
766 an acceptable or intermediate state. The accepted signal will only be sent
767 if the text is in an acceptable state when enter is pressed.
769 Currently supported validators are IntValidator, DoubleValidator and
770 RegExpValidator. An example of using validators is shown below, which allows
771 input of integers between 11 and 31 into the text input:
776 validator: IntValidator{bottom: 11; top: 31;}
781 \sa acceptableInput, inputMask
784 QValidator* QSGTextInput::validator() const
786 Q_D(const QSGTextInput);
787 //###const cast isn't good, but needed for property system?
788 return const_cast<QValidator*>(d->control->validator());
791 void QSGTextInput::setValidator(QValidator* v)
794 if (d->control->validator() == v)
797 d->control->setValidator(v);
798 if(!d->control->hasAcceptableInput()){
799 d->oldValidity = false;
800 emit acceptableInputChanged();
803 emit validatorChanged();
805 #endif // QT_NO_VALIDATOR
808 \qmlproperty string QtQuick2::TextInput::inputMask
810 Allows you to set an input mask on the TextInput, restricting the allowable
811 text inputs. See QLineEdit::inputMask for further details, as the exact
812 same mask strings are used by TextInput.
814 \sa acceptableInput, validator
816 QString QSGTextInput::inputMask() const
818 Q_D(const QSGTextInput);
819 return d->control->inputMask();
822 void QSGTextInput::setInputMask(const QString &im)
825 if (d->control->inputMask() == im)
828 d->control->setInputMask(im);
829 emit inputMaskChanged(d->control->inputMask());
833 \qmlproperty bool QtQuick2::TextInput::acceptableInput
835 This property is always true unless a validator or input mask has been set.
836 If a validator or input mask has been set, this property will only be true
837 if the current text is acceptable to the validator or input mask as a final
838 string (not as an intermediate string).
840 bool QSGTextInput::hasAcceptableInput() const
842 Q_D(const QSGTextInput);
843 return d->control->hasAcceptableInput();
847 \qmlsignal QtQuick2::TextInput::onAccepted()
849 This handler is called when the Return or Enter key is pressed.
850 Note that if there is a \l validator or \l inputMask set on the text
851 input, the handler will only be emitted if the input is in an acceptable
855 void QSGTextInputPrivate::updateInputMethodHints()
858 Qt::InputMethodHints hints = inputMethodHints;
859 uint echo = control->echoMode();
860 if (echo == QSGTextInput::Password || echo == QSGTextInput::NoEcho)
861 hints |= Qt::ImhHiddenText;
862 else if (echo == QSGTextInput::PasswordEchoOnEdit)
863 hints &= ~Qt::ImhHiddenText;
864 if (echo != QSGTextInput::Normal)
865 hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText);
866 q->setInputMethodHints(hints);
869 \qmlproperty enumeration QtQuick2::TextInput::echoMode
871 Specifies how the text should be displayed in the TextInput.
873 \o TextInput.Normal - Displays the text as it is. (Default)
874 \o TextInput.Password - Displays asterixes instead of characters.
875 \o TextInput.NoEcho - Displays nothing.
876 \o TextInput.PasswordEchoOnEdit - Displays characters as they are entered
877 while editing, otherwise displays asterisks.
880 QSGTextInput::EchoMode QSGTextInput::echoMode() const
882 Q_D(const QSGTextInput);
883 return (QSGTextInput::EchoMode)d->control->echoMode();
886 void QSGTextInput::setEchoMode(QSGTextInput::EchoMode echo)
889 if (echoMode() == echo)
891 d->control->setEchoMode((QLineControl::EchoMode)echo);
892 d->updateInputMethodHints();
894 emit echoModeChanged(echoMode());
897 Qt::InputMethodHints QSGTextInput::imHints() const
899 Q_D(const QSGTextInput);
900 return d->inputMethodHints;
903 void QSGTextInput::setIMHints(Qt::InputMethodHints hints)
906 if (d->inputMethodHints == hints)
908 d->inputMethodHints = hints;
909 d->updateInputMethodHints();
913 \qmlproperty Component QtQuick2::TextInput::cursorDelegate
914 The delegate for the cursor in the TextInput.
916 If you set a cursorDelegate for a TextInput, this delegate will be used for
917 drawing the cursor instead of the standard cursor. An instance of the
918 delegate will be created and managed by the TextInput when a cursor is
919 needed, and the x property of delegate instance will be set so as
920 to be one pixel before the top left of the current character.
922 Note that the root item of the delegate component must be a QDeclarativeItem or
923 QDeclarativeItem derived item.
925 QDeclarativeComponent* QSGTextInput::cursorDelegate() const
927 Q_D(const QSGTextInput);
928 return d->cursorComponent;
931 void QSGTextInput::setCursorDelegate(QDeclarativeComponent* c)
934 if (d->cursorComponent == c)
937 d->cursorComponent = c;
939 //note that the components are owned by something else
940 delete d->cursorItem;
942 d->startCreatingCursor();
945 emit cursorDelegateChanged();
948 void QSGTextInputPrivate::startCreatingCursor()
951 if(cursorComponent->isReady()){
953 }else if(cursorComponent->isLoading()){
954 q->connect(cursorComponent, SIGNAL(statusChanged(int)),
955 q, SLOT(createCursor()));
957 qmlInfo(q, cursorComponent->errors()) << QSGTextInput::tr("Could not load cursor delegate");
961 void QSGTextInput::createCursor()
964 if(d->cursorComponent->isError()){
965 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not load cursor delegate");
969 if(!d->cursorComponent->isReady())
973 delete d->cursorItem;
974 d->cursorItem = qobject_cast<QSGItem*>(d->cursorComponent->create());
976 qmlInfo(this, d->cursorComponent->errors()) << tr("Could not instantiate cursor delegate");
980 QDeclarative_setParent_noEvent(d->cursorItem, this);
981 d->cursorItem->setParentItem(this);
982 d->cursorItem->setX(d->control->cursorToX());
983 d->cursorItem->setHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
987 \qmlmethod rect QtQuick2::TextInput::positionToRectangle(int pos)
989 This function takes a character position and returns the rectangle that the
990 cursor would occupy, if it was placed at that character position.
992 This is similar to setting the cursorPosition, and then querying the cursor
993 rectangle, but the cursorPosition is not changed.
995 QRectF QSGTextInput::positionToRectangle(int pos) const
997 Q_D(const QSGTextInput);
998 if (pos > d->control->cursorPosition())
999 pos += d->control->preeditAreaText().length();
1000 return QRectF(d->control->cursorToX(pos)-d->hscroll,
1002 d->control->cursorWidth(),
1003 cursorRectangle().height());
1007 \qmlmethod int QtQuick2::TextInput::positionAt(int x, CursorPosition position = CursorBetweenCharacters)
1009 This function returns the character position at
1010 x pixels from the left of the textInput. Position 0 is before the
1011 first character, position 1 is after the first character but before the second,
1012 and so on until position text.length, which is after all characters.
1014 This means that for all x values before the first character this function returns 0,
1015 and for all x values after the last character this function returns text.length.
1017 The cursor position type specifies how the cursor position should be resolved.
1020 \o TextInput.CursorBetweenCharacters - Returns the position between characters that is nearest x.
1021 \o TextInput.CursorOnCharacter - Returns the position before the character that is nearest x.
1024 int QSGTextInput::positionAt(int x) const
1026 return positionAt(x, CursorBetweenCharacters);
1029 int QSGTextInput::positionAt(int x, CursorPosition position) const
1031 Q_D(const QSGTextInput);
1032 int pos = d->control->xToPos(x + d->hscroll, QTextLine::CursorPosition(position));
1033 const int cursor = d->control->cursor();
1035 const int preeditLength = d->control->preeditAreaText().length();
1036 pos = pos > cursor + preeditLength
1037 ? pos - preeditLength
1043 void QSGTextInput::keyPressEvent(QKeyEvent* ev)
1046 // Don't allow MacOSX up/down support, and we don't allow a completer.
1047 bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier;
1048 if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) {
1049 // Ignore when moving off the end unless there is a selection,
1050 // because then moving will do something (deselect).
1051 int cursorPosition = d->control->cursor();
1052 if (cursorPosition == 0)
1053 ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right);
1054 if (cursorPosition == d->control->text().length())
1055 ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left);
1060 d->control->processKeyEvent(ev);
1062 if (!ev->isAccepted())
1063 QSGImplicitSizeItem::keyPressEvent(ev);
1066 void QSGTextInput::inputMethodEvent(QInputMethodEvent *ev)
1069 const bool wasComposing = d->control->preeditAreaText().length() > 0;
1070 if (d->control->isReadOnly()) {
1073 d->control->processInputMethodEvent(ev);
1075 if (!ev->isAccepted())
1076 QSGImplicitSizeItem::inputMethodEvent(ev);
1078 if (wasComposing != (d->control->preeditAreaText().length() > 0))
1079 emit inputMethodComposingChanged();
1082 void QSGTextInput::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
1085 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonDblClick))
1087 if (d->selectByMouse) {
1088 int cursor = d->xToPos(event->pos().x());
1089 d->control->selectWordAtPos(cursor);
1090 event->setAccepted(true);
1092 QSGImplicitSizeItem::mouseDoubleClickEvent(event);
1096 void QSGTextInput::mousePressEvent(QGraphicsSceneMouseEvent *event)
1099 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonPress))
1101 if(d->focusOnPress){
1102 bool hadActiveFocus = hasActiveFocus();
1104 if (d->showInputPanelOnFocus) {
1105 if (hasActiveFocus() && hadActiveFocus && !isReadOnly()) {
1106 // re-open input panel on press if already focused
1107 openSoftwareInputPanel();
1109 } else { // show input panel on click
1110 if (hasActiveFocus() && !hadActiveFocus) {
1111 d->clickCausedFocus = true;
1115 if (d->selectByMouse) {
1116 setKeepMouseGrab(false);
1117 d->selectPressed = true;
1118 d->pressPos = event->pos();
1120 bool mark = (event->modifiers() & Qt::ShiftModifier) && d->selectByMouse;
1121 int cursor = d->xToPos(event->pos().x());
1122 d->control->moveCursor(cursor, mark);
1123 event->setAccepted(true);
1126 void QSGTextInput::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
1129 if (d->sendMouseEventToInputContext(event, QEvent::MouseMove))
1131 if (d->selectPressed) {
1132 if (qAbs(int(event->pos().x() - d->pressPos.x())) > QApplication::startDragDistance())
1133 setKeepMouseGrab(true);
1134 moveCursorSelection(d->xToPos(event->pos().x()), d->mouseSelectionMode);
1135 event->setAccepted(true);
1137 QSGImplicitSizeItem::mouseMoveEvent(event);
1141 void QSGTextInput::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
1144 if (d->sendMouseEventToInputContext(event, QEvent::MouseButtonRelease))
1146 if (d->selectPressed) {
1147 d->selectPressed = false;
1148 setKeepMouseGrab(false);
1150 if (!d->showInputPanelOnFocus) { // input panel on click
1151 if (d->focusOnPress && !isReadOnly() && boundingRect().contains(event->pos())) {
1152 if (canvas() && canvas() == QGuiApplication::activeWindow()) {
1153 // ### refactor: implement virtual keyboard properly..
1154 qDebug("QSGTextInput: virtual keyboard no implemented...");
1155 // qt_widget_private(canvas())->handleSoftwareInputPanel(event->button(), d->clickCausedFocus);
1159 d->clickCausedFocus = false;
1160 d->control->processEvent(event);
1161 if (!event->isAccepted())
1162 QSGImplicitSizeItem::mouseReleaseEvent(event);
1165 bool QSGTextInputPrivate::sendMouseEventToInputContext(
1166 QGraphicsSceneMouseEvent *event, QEvent::Type eventType)
1168 #if !defined QT_NO_IM
1169 if (event->widget() && control->composeMode()) {
1170 int tmp_cursor = xToPos(event->pos().x());
1171 int mousePos = tmp_cursor - control->cursor();
1172 if (mousePos < 0 || mousePos > control->preeditAreaText().length()) {
1174 // don't send move events outside the preedit area
1175 if (eventType == QEvent::MouseMove)
1179 QInputContext *qic = event->widget()->inputContext();
1181 QMouseEvent mouseEvent(
1183 event->widget()->mapFromGlobal(event->screenPos()),
1187 event->modifiers());
1188 // may be causing reset() in some input methods
1189 qic->mouseHandler(mousePos, &mouseEvent);
1190 event->setAccepted(mouseEvent.isAccepted());
1192 if (!control->preeditAreaText().isEmpty())
1203 void QSGTextInput::mouseUngrabEvent()
1206 d->selectPressed = false;
1207 setKeepMouseGrab(false);
1210 bool QSGTextInput::event(QEvent* ev)
1213 //Anything we don't deal with ourselves, pass to the control
1214 bool handled = false;
1216 case QEvent::KeyPress:
1217 case QEvent::KeyRelease://###Should the control be doing anything with release?
1218 case QEvent::InputMethod:
1219 case QEvent::GraphicsSceneMousePress:
1220 case QEvent::GraphicsSceneMouseMove:
1221 case QEvent::GraphicsSceneMouseRelease:
1222 case QEvent::GraphicsSceneMouseDoubleClick:
1225 handled = d->control->processEvent(ev);
1228 handled = QSGImplicitSizeItem::event(ev);
1232 void QSGTextInput::geometryChanged(const QRectF &newGeometry,
1233 const QRectF &oldGeometry)
1235 if (newGeometry.width() != oldGeometry.width()) {
1237 updateCursorRectangle();
1239 QSGImplicitSizeItem::geometryChanged(newGeometry, oldGeometry);
1242 int QSGTextInputPrivate::calculateTextWidth()
1244 return qRound(control->naturalTextWidth());
1247 void QSGTextInputPrivate::updateHorizontalScroll()
1250 const int preeditLength = control->preeditAreaText().length();
1251 const int width = q->width();
1252 int widthUsed = calculateTextWidth();
1254 if (!autoScroll || widthUsed <= width) {
1255 QSGTextInput::HAlignment effectiveHAlign = q->effectiveHAlign();
1256 // text fits in br; use hscroll for alignment
1257 switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) {
1258 case Qt::AlignRight:
1259 hscroll = widthUsed - width;
1261 case Qt::AlignHCenter:
1262 hscroll = (widthUsed - width) / 2;
1270 int cix = qRound(control->cursorToX(control->cursor() + preeditLength));
1271 if (cix - hscroll >= width) {
1272 // text doesn't fit, cursor is to the right of br (scroll right)
1273 hscroll = cix - width;
1274 } else if (cix - hscroll < 0 && hscroll < widthUsed) {
1275 // text doesn't fit, cursor is to the left of br (scroll left)
1277 } else if (widthUsed - hscroll < width) {
1278 // text doesn't fit, text document is to the left of br; align
1280 hscroll = widthUsed - width;
1282 if (preeditLength > 0) {
1283 // check to ensure long pre-edit text doesn't push the cursor
1285 cix = qRound(control->cursorToX(
1286 control->cursor() + qMax(0, control->preeditCursor() - 1)));
1293 QSGNode *QSGTextInput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1298 QSGTextNode *node = static_cast<QSGTextNode *>(oldNode);
1300 node = new QSGTextNode(QSGItemPrivate::get(this)->sceneGraphContext());
1303 if (!d->textLayoutDirty) {
1304 QSGSimpleRectNode *cursorNode = node->cursorNode();
1305 if (cursorNode != 0 && !isReadOnly()) {
1306 QFontMetrics fm = QFontMetrics(d->font);
1307 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1308 QPoint offset(-d->hscroll, fm.ascent() - d->control->ascent());
1309 offset.rx() += d->control->cursorToX();
1311 QRect br(boundingRect().toRect());
1312 cursorNode->setRect(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())));
1314 if (!d->cursorVisible
1315 || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1322 node->deleteContent();
1323 node->setMatrix(QMatrix4x4());
1325 QPoint offset = QPoint(0,0);
1326 QFontMetrics fm = QFontMetrics(d->font);
1327 QRect br(boundingRect().toRect());
1328 if (d->autoScroll) {
1329 // the y offset is there to keep the baseline constant in case we have script changes in the text.
1330 offset = br.topLeft() - QPoint(d->hscroll, d->control->ascent() - fm.ascent());
1332 offset = QPoint(d->hscroll, 0);
1335 QTextLayout *textLayout = d->control->textLayout();
1336 if (!textLayout->text().isEmpty()) {
1337 node->addTextLayout(offset, textLayout, d->color,
1338 QSGText::Normal, QColor(),
1339 d->selectionColor, d->selectedTextColor,
1340 d->control->selectionStart(),
1341 d->control->selectionEnd() - 1); // selectionEnd() returns first char after
1345 if (!isReadOnly() && d->cursorItem == 0) {
1346 offset.rx() += d->control->cursorToX();
1347 node->setCursor(QRectF(offset, QSizeF(d->control->cursorWidth(), br.height())), d->color);
1348 if (!d->cursorVisible
1349 || (!d->control->cursorBlinkStatus() && d->control->cursorBlinkPeriod() > 0)) {
1356 d->textLayoutDirty = false;
1362 QVariant QSGTextInput::inputMethodQuery(Qt::InputMethodQuery property) const
1364 Q_D(const QSGTextInput);
1366 case Qt::ImMicroFocus:
1367 return cursorRectangle();
1370 case Qt::ImCursorPosition:
1371 return QVariant(d->control->cursor());
1372 case Qt::ImSurroundingText:
1373 if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing())
1374 return QVariant(displayText());
1376 return QVariant(text());
1377 case Qt::ImCurrentSelection:
1378 return QVariant(selectedText());
1379 case Qt::ImMaximumTextLength:
1380 return QVariant(maxLength());
1381 case Qt::ImAnchorPosition:
1382 if (d->control->selectionStart() == d->control->selectionEnd())
1383 return QVariant(d->control->cursor());
1384 else if (d->control->selectionStart() == d->control->cursor())
1385 return QVariant(d->control->selectionEnd());
1387 return QVariant(d->control->selectionStart());
1394 \qmlmethod void QtQuick2::TextInput::deselect()
1396 Removes active text selection.
1398 void QSGTextInput::deselect()
1401 d->control->deselect();
1405 \qmlmethod void QtQuick2::TextInput::selectAll()
1407 Causes all text to be selected.
1409 void QSGTextInput::selectAll()
1412 d->control->setSelection(0, d->control->text().length());
1416 \qmlmethod void QtQuick2::TextInput::isRightToLeft(int start, int end)
1418 Returns true if the natural reading direction of the editor text
1419 found between positions \a start and \a end is right to left.
1421 bool QSGTextInput::isRightToLeft(int start, int end)
1425 qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start.";
1428 return d->control->text().mid(start, end - start).isRightToLeft();
1432 #ifndef QT_NO_CLIPBOARD
1434 \qmlmethod QtQuick2::TextInput::cut()
1436 Moves the currently selected text to the system clipboard.
1438 void QSGTextInput::cut()
1446 \qmlmethod QtQuick2::TextInput::copy()
1448 Copies the currently selected text to the system clipboard.
1450 void QSGTextInput::copy()
1457 \qmlmethod QtQuick2::TextInput::paste()
1459 Replaces the currently selected text by the contents of the system clipboard.
1461 void QSGTextInput::paste()
1464 if (!d->control->isReadOnly())
1465 d->control->paste();
1467 #endif // QT_NO_CLIPBOARD
1470 \qmlmethod void QtQuick2::TextInput::selectWord()
1472 Causes the word closest to the current cursor position to be selected.
1474 void QSGTextInput::selectWord()
1477 d->control->selectWordAtPos(d->control->cursor());
1481 \qmlproperty bool QtQuick2::TextInput::smooth
1483 This property holds whether the text is smoothly scaled or transformed.
1485 Smooth filtering gives better visual quality, but is slower. If
1486 the item is displayed at its natural size, this property has no visual or
1489 \note Generally scaling artifacts are only visible if the item is stationary on
1490 the screen. A common pattern when animating an item is to disable smooth
1491 filtering at the beginning of the animation and reenable it at the conclusion.
1495 \qmlproperty string QtQuick2::TextInput::passwordCharacter
1497 This is the character displayed when echoMode is set to Password or
1498 PasswordEchoOnEdit. By default it is an asterisk.
1500 If this property is set to a string with more than one character,
1501 the first character is used. If the string is empty, the value
1502 is ignored and the property is not set.
1504 QString QSGTextInput::passwordCharacter() const
1506 Q_D(const QSGTextInput);
1507 return QString(d->control->passwordCharacter());
1510 void QSGTextInput::setPasswordCharacter(const QString &str)
1513 if(str.length() < 1)
1515 d->control->setPasswordCharacter(str.constData()[0]);
1516 EchoMode echoMode_ = echoMode();
1517 if (echoMode_ == Password || echoMode_ == PasswordEchoOnEdit) {
1520 emit passwordCharacterChanged();
1524 \qmlproperty string QtQuick2::TextInput::displayText
1526 This is the text displayed in the TextInput.
1528 If \l echoMode is set to TextInput::Normal, this holds the
1529 same value as the TextInput::text property. Otherwise,
1530 this property holds the text visible to the user, while
1531 the \l text property holds the actual entered text.
1533 QString QSGTextInput::displayText() const
1535 Q_D(const QSGTextInput);
1536 return d->control->displayText();
1540 \qmlproperty bool QtQuick2::TextInput::selectByMouse
1544 If true, the user can use the mouse to select text in some
1545 platform-specific way. Note that for some platforms this may
1546 not be an appropriate interaction (eg. may conflict with how
1547 the text needs to behave inside a Flickable.
1549 bool QSGTextInput::selectByMouse() const
1551 Q_D(const QSGTextInput);
1552 return d->selectByMouse;
1555 void QSGTextInput::setSelectByMouse(bool on)
1558 if (d->selectByMouse != on) {
1559 d->selectByMouse = on;
1560 emit selectByMouseChanged(on);
1565 \qmlproperty enum QtQuick2::TextInput::mouseSelectionMode
1567 Specifies how text should be selected using a mouse.
1570 \o TextInput.SelectCharacters - The selection is updated with individual characters. (Default)
1571 \o TextInput.SelectWords - The selection is updated with whole words.
1574 This property only applies when \l selectByMouse is true.
1577 QSGTextInput::SelectionMode QSGTextInput::mouseSelectionMode() const
1579 Q_D(const QSGTextInput);
1580 return d->mouseSelectionMode;
1583 void QSGTextInput::setMouseSelectionMode(SelectionMode mode)
1586 if (d->mouseSelectionMode != mode) {
1587 d->mouseSelectionMode = mode;
1588 emit mouseSelectionModeChanged(mode);
1593 \qmlproperty bool QtQuick2::TextInput::canPaste
1595 Returns true if the TextInput is writable and the content of the clipboard is
1596 suitable for pasting into the TextEdit.
1598 bool QSGTextInput::canPaste() const
1600 Q_D(const QSGTextInput);
1604 void QSGTextInput::moveCursorSelection(int position)
1607 d->control->moveCursor(position, true);
1611 \qmlmethod void QtQuick2::TextInput::moveCursorSelection(int position, SelectionMode mode = TextInput.SelectCharacters)
1613 Moves the cursor to \a position and updates the selection according to the optional \a mode
1614 parameter. (To only move the cursor, set the \l cursorPosition property.)
1616 When this method is called it additionally sets either the
1617 selectionStart or the selectionEnd (whichever was at the previous cursor position)
1618 to the specified position. This allows you to easily extend and contract the selected
1621 The selection mode specifies whether the selection is updated on a per character or a per word
1622 basis. If not specified the selection mode will default to TextInput.SelectCharacters.
1625 \o TextEdit.SelectCharacters - Sets either the selectionStart or selectionEnd (whichever was at
1626 the previous cursor position) to the specified position.
1627 \o TextEdit.SelectWords - Sets the selectionStart and selectionEnd to include all
1628 words between the specified postion and the previous cursor position. Words partially in the
1632 For example, take this sequence of calls:
1636 moveCursorSelection(9, TextInput.SelectCharacters)
1637 moveCursorSelection(7, TextInput.SelectCharacters)
1640 This moves the cursor to position 5, extend the selection end from 5 to 9
1641 and then retract the selection end from 9 to 7, leaving the text from position 5 to 7
1642 selected (the 6th and 7th characters).
1644 The same sequence with TextInput.SelectWords will extend the selection start to a word boundary
1645 before or on position 5 and extend the selection end to a word boundary on or past position 9.
1647 void QSGTextInput::moveCursorSelection(int pos, SelectionMode mode)
1651 if (mode == SelectCharacters) {
1652 d->control->moveCursor(pos, true);
1653 } else if (pos != d->control->cursor()){
1654 const int cursor = d->control->cursor();
1656 if (!d->control->hasSelectedText())
1657 anchor = d->control->cursor();
1658 else if (d->control->selectionStart() == d->control->cursor())
1659 anchor = d->control->selectionEnd();
1661 anchor = d->control->selectionStart();
1663 if (anchor < pos || (anchor == pos && cursor < pos)) {
1664 const QString text = d->control->text();
1665 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1666 finder.setPosition(anchor);
1668 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1669 if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord)
1670 || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) {
1671 finder.toPreviousBoundary();
1673 anchor = finder.position() != -1 ? finder.position() : 0;
1675 finder.setPosition(pos);
1676 if (pos > 0 && !finder.boundaryReasons())
1677 finder.toNextBoundary();
1678 const int cursor = finder.position() != -1 ? finder.position() : text.length();
1680 d->control->setSelection(anchor, cursor - anchor);
1681 } else if (anchor > pos || (anchor == pos && cursor > pos)) {
1682 const QString text = d->control->text();
1683 QTextBoundaryFinder finder(QTextBoundaryFinder::Word, text);
1684 finder.setPosition(anchor);
1686 const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons();
1687 if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord)
1688 || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) {
1689 finder.toNextBoundary();
1692 anchor = finder.position() != -1 ? finder.position() : text.length();
1694 finder.setPosition(pos);
1695 if (pos < text.length() && !finder.boundaryReasons())
1696 finder.toPreviousBoundary();
1697 const int cursor = finder.position() != -1 ? finder.position() : 0;
1699 d->control->setSelection(anchor, cursor - anchor);
1705 \qmlmethod void QtQuick2::TextInput::openSoftwareInputPanel()
1707 Opens software input panels like virtual keyboards for typing, useful for
1708 customizing when you want the input keyboard to be shown and hidden in
1711 By default the opening of input panels follows the platform style. On Symbian^1 and
1712 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1713 the panels are automatically opened when TextInput element gains active focus. Input panels are
1714 always closed if no editor has active focus.
1716 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1717 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1718 the behavior you want.
1720 Only relevant on platforms, which provide virtual keyboards.
1726 text: "Hello world!"
1727 activeFocusOnPress: false
1729 anchors.fill: parent
1731 if (!textInput.activeFocus) {
1732 textInput.forceActiveFocus()
1733 textInput.openSoftwareInputPanel();
1735 textInput.focus = false;
1738 onPressAndHold: textInput.closeSoftwareInputPanel();
1743 void QSGTextInput::openSoftwareInputPanel()
1747 QEvent event(QEvent::RequestSoftwareInputPanel);
1748 QApplication::sendEvent(canvas(), &event);
1754 \qmlmethod void QtQuick2::TextInput::closeSoftwareInputPanel()
1756 Closes a software input panel like a virtual keyboard shown on the screen, useful
1757 for customizing when you want the input keyboard to be shown and hidden in
1760 By default the opening of input panels follows the platform style. On Symbian^1 and
1761 Symbian^3 -based devices the panels are opened by clicking TextInput. On other platforms
1762 the panels are automatically opened when TextInput element gains active focus. Input panels are
1763 always closed if no editor has active focus.
1765 . You can disable the automatic behavior by setting the property \c activeFocusOnPress to false
1766 and use functions openSoftwareInputPanel() and closeSoftwareInputPanel() to implement
1767 the behavior you want.
1769 Only relevant on platforms, which provide virtual keyboards.
1775 text: "Hello world!"
1776 activeFocusOnPress: false
1778 anchors.fill: parent
1780 if (!textInput.activeFocus) {
1781 textInput.forceActiveFocus();
1782 textInput.openSoftwareInputPanel();
1784 textInput.focus = false;
1787 onPressAndHold: textInput.closeSoftwareInputPanel();
1792 void QSGTextInput::closeSoftwareInputPanel()
1796 QEvent event(QEvent::CloseSoftwareInputPanel);
1797 QApplication::sendEvent(canvas(), &event);
1802 void QSGTextInput::focusInEvent(QFocusEvent *event)
1804 Q_D(const QSGTextInput);
1805 if (d->showInputPanelOnFocus) {
1806 if (d->focusOnPress && !isReadOnly()) {
1807 openSoftwareInputPanel();
1810 QSGImplicitSizeItem::focusInEvent(event);
1813 void QSGTextInput::itemChange(ItemChange change, const ItemChangeData &value)
1816 if (change == ItemActiveFocusHasChanged) {
1817 bool hasFocus = value.boolValue;
1818 d->focused = hasFocus;
1819 setCursorVisible(hasFocus); // ### refactor: && d->canvas && d->canvas->hasFocus()
1820 if(echoMode() == QSGTextInput::PasswordEchoOnEdit && !hasFocus)
1821 d->control->updatePasswordEchoEditing(false);//QLineControl sets it on key events, but doesn't deal with focus events
1823 d->control->deselect();
1825 QSGItem::itemChange(change, value);
1829 \qmlproperty bool QtQuick2::TextInput::inputMethodComposing
1832 This property holds whether the TextInput has partial text input from an
1835 While it is composing an input method may rely on mouse or key events from
1836 the TextInput to edit or commit the partial text. This property can be
1837 used to determine when to disable events handlers that may interfere with
1838 the correct operation of an input method.
1840 bool QSGTextInput::isInputMethodComposing() const
1842 Q_D(const QSGTextInput);
1843 return d->control->preeditAreaText().length() > 0;
1846 void QSGTextInputPrivate::init()
1849 #if defined(Q_WS_MAC)
1850 control->setThreadChecks(true);
1852 control->setParent(q);//Now mandatory due to accessibility changes
1853 control->setCursorWidth(1);
1854 control->setPasswordCharacter(QLatin1Char('*'));
1855 q->setSmooth(smooth);
1856 q->setAcceptedMouseButtons(Qt::LeftButton);
1857 q->setFlag(QSGItem::ItemAcceptsInputMethod);
1858 q->setFlag(QSGItem::ItemHasContents);
1859 q->connect(control, SIGNAL(cursorPositionChanged(int,int)),
1860 q, SLOT(cursorPosChanged()));
1861 q->connect(control, SIGNAL(selectionChanged()),
1862 q, SLOT(selectionChanged()));
1863 q->connect(control, SIGNAL(textChanged(QString)),
1864 q, SLOT(q_textChanged()));
1865 q->connect(control, SIGNAL(accepted()),
1866 q, SIGNAL(accepted()));
1867 q->connect(control, SIGNAL(updateNeeded(QRect)),
1868 q, SLOT(updateRect(QRect)));
1869 #ifndef QT_NO_CLIPBOARD
1870 q->connect(q, SIGNAL(readOnlyChanged(bool)),
1871 q, SLOT(q_canPasteChanged()));
1872 q->connect(QApplication::clipboard(), SIGNAL(dataChanged()),
1873 q, SLOT(q_canPasteChanged()));
1874 canPaste = !control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
1875 #endif // QT_NO_CLIPBOARD
1876 q->connect(control, SIGNAL(updateMicroFocus()),
1877 q, SLOT(updateCursorRectangle()));
1878 q->connect(control, SIGNAL(displayTextChanged(QString)),
1879 q, SLOT(updateRect()));
1881 oldValidity = control->hasAcceptableInput();
1882 lastSelectionStart = 0;
1883 lastSelectionEnd = 0;
1884 QPalette p = control->palette();
1885 selectedTextColor = p.color(QPalette::HighlightedText);
1886 selectionColor = p.color(QPalette::Highlight);
1887 determineHorizontalAlignment();
1889 if (!qmlDisableDistanceField()) {
1890 QTextOption option = control->textLayout()->textOption();
1891 option.setUseDesignMetrics(true);
1892 control->textLayout()->setTextOption(option);
1896 void QSGTextInput::cursorPosChanged()
1899 updateCursorRectangle();
1900 emit cursorPositionChanged();
1901 // XXX todo - not in 4.8?
1903 d->control->resetCursorBlinkTimer();
1906 if(!d->control->hasSelectedText()){
1907 if(d->lastSelectionStart != d->control->cursor()){
1908 d->lastSelectionStart = d->control->cursor();
1909 emit selectionStartChanged();
1911 if(d->lastSelectionEnd != d->control->cursor()){
1912 d->lastSelectionEnd = d->control->cursor();
1913 emit selectionEndChanged();
1918 void QSGTextInput::updateCursorRectangle()
1921 d->updateHorizontalScroll();
1922 updateRect();//TODO: Only update rect between pos's
1924 emit cursorRectangleChanged();
1926 d->cursorItem->setX(d->control->cursorToX() - d->hscroll);
1929 void QSGTextInput::selectionChanged()
1932 updateRect();//TODO: Only update rect in selection
1933 emit selectedTextChanged();
1935 if(d->lastSelectionStart != d->control->selectionStart()){
1936 d->lastSelectionStart = d->control->selectionStart();
1937 if(d->lastSelectionStart == -1)
1938 d->lastSelectionStart = d->control->cursor();
1939 emit selectionStartChanged();
1941 if(d->lastSelectionEnd != d->control->selectionEnd()){
1942 d->lastSelectionEnd = d->control->selectionEnd();
1943 if(d->lastSelectionEnd == -1)
1944 d->lastSelectionEnd = d->control->cursor();
1945 emit selectionEndChanged();
1949 void QSGTextInput::q_textChanged()
1953 emit displayTextChanged();
1955 d->determineHorizontalAlignment();
1956 d->updateHorizontalScroll();
1958 if(hasAcceptableInput() != d->oldValidity){
1959 d->oldValidity = hasAcceptableInput();
1960 emit acceptableInputChanged();
1964 void QSGTextInputPrivate::showCursor()
1966 if (textNode != 0 && textNode->cursorNode() != 0)
1967 textNode->cursorNode()->setColor(color);
1970 void QSGTextInputPrivate::hideCursor()
1972 if (textNode != 0 && textNode->cursorNode() != 0)
1973 textNode->cursorNode()->setColor(QColor(0, 0, 0, 0));
1976 void QSGTextInput::updateRect(const QRect &r)
1979 if (!isComponentComplete())
1983 d->textLayoutDirty = true;
1989 QRectF QSGTextInput::boundingRect() const
1991 Q_D(const QSGTextInput);
1992 QRectF r = QSGImplicitSizeItem::boundingRect();
1994 int cursorWidth = d->cursorItem ? d->cursorItem->width() : d->control->cursorWidth();
1996 // Could include font max left/right bearings to either side of rectangle.
1998 r.setRight(r.right() + cursorWidth);
2002 void QSGTextInput::updateSize(bool needsRedraw)
2007 setImplicitHeight(d->control->height()-1); // -1 to counter QLineControl's +1 which is not consistent with Text.
2008 setImplicitWidth(d->calculateTextWidth());
2009 if(w==width() && h==height() && needsRedraw)
2013 void QSGTextInput::q_canPasteChanged()
2016 bool old = d->canPaste;
2017 #ifndef QT_NO_CLIPBOARD
2018 d->canPaste = !d->control->isReadOnly() && QApplication::clipboard()->text().length() != 0;
2020 if(d->canPaste != old)
2021 emit canPasteChanged();